
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2003 by Francois Boucher
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include <string.h>

#include "lcd.h"
#include "button.h"
#include "kernel.h"
#include "version.h"
#include "sprintf.h"
#include "lcd-charset.h"
#include "lang.h"
#include "debug.h"

/* Two functions that are part of the firmware for the Neo-builds only.
   TODO: make them proper "official" firmware functions or replace them
   with apps code */
extern void lcd_cursor(int x, int y);
extern int button_add(unsigned int button);

#define KEYBOARD_MAX_LENGTH 255

static const unsigned char* const kbd_screens[3] = {
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  "abcdefghijklmnopqrstuvwxyz",
  " !\"#$%&'()*+,-./0123456789;<=>?@[]^_`{|}"
};

static const unsigned char* const kbd_screens_names[3] = {
  "Capitals",
  "Small",
  "Others"
};

static void kbd_show_legend( int nb )
{
  char buf[24];
  snprintf(buf, sizeof(buf), "[%s]", kbd_screens_names[nb] );
  lcd_puts( 0, 1, buf );  
  lcd_puts( 0, 2, kbd_screens[nb] );
  lcd_puts( 0, 3, &kbd_screens[nb][20] );
}

/*
  Returns text len Max = KEYBOARD_MAX_LENGTH characters.

  This function MUST NOT fill in more than 'buflen' bytes into the given
  buffer!
*/
static char kbdbuffer[KEYBOARD_MAX_LENGTH+1]; /* no use to alloc this huge one
                                                 on the stack */
int kbd_input(char* text, int buflen)
{
  char* pstart;
  char* pcursor;
  char* pold;
  int bufferlen;
  char cursorpos = 0;
  int ret = 0;
  bool done = false;
  int key;
  int screen = 0;
  int screenidx = -1;
  const unsigned char * pcurscreen = kbd_screens[0];
  bool ctl;

  bufferlen = strlen(text);
  
  if(bufferlen > KEYBOARD_MAX_LENGTH)
    bufferlen = KEYBOARD_MAX_LENGTH;
  
  strncpy(kbdbuffer, text, bufferlen);
  kbdbuffer[bufferlen] = 0;

  lcd_clear_display();

  /* Initial setup */
  lcd_puts(0, 0, kbdbuffer);
  kbd_show_legend(screen);
  lcd_cursor(cursorpos, 0);
  lcd_write_command(LCD_BLINKCUR);
  
  pstart = pcursor = kbdbuffer;

  while(!done) {
      /* We want all the keys except the releases and the repeats */
      key = button_get(true);
    
      if( key & BUTTON_IR)
          ctl = key & (NEO_IR_BUTTON_PLAY|NEO_IR_BUTTON_STOP|NEO_IR_BUTTON_BROWSE);
      else
          ctl = key & (BUTTON_PLAY|BUTTON_STOP|BUTTON_MENU);

      if( ctl ) {
          /* These key do not change the first line */
          switch( key ) {
              case BUTTON_MENU:
              case BUTTON_IR|NEO_IR_BUTTON_BROWSE:
	
                  /* Toggle legend screen */
                  screen++;
                  if( screen == 3 )
                      screen = 0;

                  pcurscreen = kbd_screens[screen];

                  screenidx = -1;
                  kbd_show_legend( screen );
                  
                  /* Restore cursor */
                  lcd_cursor( cursorpos, 0 );
                  break;
                  
              case BUTTON_PLAY:
              case BUTTON_IR|NEO_IR_BUTTON_PLAY:
                  if( bufferlen ) {
                      strncpy(text, kbdbuffer, bufferlen);
                      text[bufferlen] = 0;
                      ret = bufferlen;
                  }
                  /* fallthrough */
                  
              case BUTTON_STOP:
              case BUTTON_IR|NEO_IR_BUTTON_STOP:
                  
                  /* Remove blinking cursor */
                  lcd_write_command(LCD_OFFCUR);
                  done = true;
          }
      }
      else {
      
          switch( key ) {
	
              case BUTTON_PROGRAM:
              case BUTTON_PROGRAM|BUTTON_REPEAT:
              case BUTTON_IR|NEO_IR_BUTTON_PROGRAM:
	
                  /* Delete char at pcursor */
                  /* Check if we are at the last char */

                  if( *(pcursor+1) != 0 ) {
                      /* move rest of the string to the left in buffer */
                      pold = pcursor;
                      while( *pcursor ){
                          *pcursor = *(pcursor+1);
                          pcursor++;
                      }
	  
                      /* Restore position */
                      pcursor = pold;
                  }
                  else {
                      *pcursor = 0;
                      pcursor--;
                      cursorpos--;
                  }
	  
                  bufferlen--;
                  break;
                  
              case BUTTON_IR|NEO_IR_BUTTON_EQ:
              case BUTTON_SELECT|BUTTON_LEFT:
                  
                  /* Insert left */

                  if(bufferlen >= buflen)
                      break;
                  
                  pold = pcursor;
	
                  /* Goto end */
                  while( *pcursor )
                      pcursor++;

                  /* Move string content to the right */
                  while( pcursor >= pold ){
                      *(pcursor+1) = *pcursor;
                      pcursor--;
                  }

                  pcursor = pold;
                  *pcursor = ' ';
                  
                  bufferlen++;
                  break;
	
              case BUTTON_IR|NEO_IR_BUTTON_MUTE:
              case BUTTON_SELECT|BUTTON_RIGHT:
	
                  /* Insert Right */
	
                  if(bufferlen >= buflen)
                      break;
	
                  pold = pcursor;
	
                  /* Goto end */
                  while(*pcursor)
                      pcursor++;
	
                  /* Move string content to the right */
                  while(pcursor > pold){
                      *(pcursor+1) = *pcursor;
                      pcursor--;
                  }
	
                  pcursor = pold;
                  *(pcursor+1) = ' ';
	
                  bufferlen++;
	
                  button_add( BUTTON_RIGHT );
                  break;

              case BUTTON_LEFT:
              case BUTTON_REPEAT|BUTTON_LEFT:
              case BUTTON_IR|NEO_IR_BUTTON_REWIND:
              case BUTTON_IR|NEO_IR_BUTTON_REWIND|BUTTON_REPEAT:

                  /* Move cursor left.  Shift text right if all the way to the
                     left */
                  
                  /* Check for start of string */
                  if(pcursor > kbdbuffer) {
                      
                      screenidx = -1;
                      cursorpos--;
                      pcursor--;
                      
                      /* Check if were going off the screen */
                      if( cursorpos == -1 ) {
                          cursorpos = 0;
                          
                          /* Shift text right if we are */
                          pstart--;
                      }
                  }
                  break;
                  
              case BUTTON_RIGHT:
              case BUTTON_REPEAT|BUTTON_RIGHT:
              case BUTTON_IR|NEO_IR_BUTTON_FFORWARD:
              case BUTTON_IR|NEO_IR_BUTTON_FFORWARD|BUTTON_REPEAT:
                  
                  /* Move cursor right.  Shift text left if all the way to
                     the right */
    
                  /* Check for end of string */
                  if( *(pcursor+1) != 0 ) {
                      screenidx = -1;
                      cursorpos++;
                      pcursor++;
	
                      /* Check if were going of the screen */
                      if( cursorpos == 20 ) {
                          cursorpos = 19;
	    
                          /* Shift text left if we are */
                          pstart++;
                      }
                  }
                  break;
	
              case BUTTON_UP:
              case BUTTON_UP|BUTTON_REPEAT:
              case BUTTON_IR|NEO_IR_BUTTON_VOLUP:
              case BUTTON_IR|NEO_IR_BUTTON_VOLUP|BUTTON_REPEAT:
                  screenidx += 2;
                  /* fallthrough */
              case BUTTON_DOWN:
              case BUTTON_DOWN|BUTTON_REPEAT:
              case BUTTON_IR|NEO_IR_BUTTON_VOLDN:
              case BUTTON_IR|NEO_IR_BUTTON_VOLDN|BUTTON_REPEAT:
                  screenidx--;

                  if( screenidx < 0 )
                      screenidx = strlen(pcurscreen)-1;
                  
                  if( pcurscreen[screenidx] == 0 )
                      screenidx = 0;	   

                  /* Changes the character over the cursor */
                  *pcursor = pcurscreen[screenidx];
          }
      
          lcd_puts( 0, 0, pstart);
          lcd_cursor( cursorpos, 0 );
      }
  }
  return ret;
}
