/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <pspkernel.h>
#include <psppower.h>
#include <pspctrl.h>
#include <pspwlan.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <SDL.h>

#include "psp_global.h"
#include "psp_sdl.h"
#include "psp_menu.h"
#include "psp_danzeff.h"
#include "psp_fmgr.h"
#include "psp_ssh.h"
#include "psp_irkeyb.h"

# define PSPSSH_MAX_INPUT_LENGTH   1024

static int          loc_ssh_thid = -1;

static volatile int  loc_ssh_input_begin = 0;
static volatile int  loc_ssh_input_end   = 0;
static volatile char loc_ssh_input[PSPSSH_MAX_INPUT_LENGTH];

int
psp_ssh_is_data_to_ssh()
{
  return loc_ssh_input_begin != loc_ssh_input_end;
}

int
psp_ssh_get_data_to_ssh(char *buffer, int length)
{
  int src_index = loc_ssh_input_begin;
  int dst_index = 0;
  while (src_index != loc_ssh_input_end) {

    buffer[dst_index++] = loc_ssh_input[src_index];
    src_index = (src_index + 1) % PSPSSH_MAX_INPUT_LENGTH;

    if (dst_index >= length) break;
  }
  loc_ssh_input_begin = src_index;
  return dst_index;
}

int
psp_ssh_put_key_to_ssh(char key)
{
  loc_ssh_input[loc_ssh_input_end] = key;
  loc_ssh_input_end = (loc_ssh_input_end + 1) % PSPSSH_MAX_INPUT_LENGTH;
# if 0 //LUDO: DEBUG
  fprintf(stdout, "KEY PRESS %x '%c'\n", key, (key >= ' ') ? key : 'X');
# endif
}

int
psp_ssh_put_data_to_ssh(char *data, int length)
{
  int index;
  for (index = 0; index < length; index++) {
    loc_ssh_input[loc_ssh_input_end] = data[index];
    loc_ssh_input_end = (loc_ssh_input_end + 1) % PSPSSH_MAX_INPUT_LENGTH;
  }
# if 0 //LUDO: DEBUG
  for (index = 0; index < length; index++) {
    fprintf(stdout, "KEY PRESS [%d] %x '%c'\n", index, 
          data[index], (data[index] >= ' ') ? data[index] : 'X');
  }
# endif
}

void
psp_ssh_send_to_console(char *buffer, int length)
{
  if (! length) return;

  psp_vt100_process(buffer, length);
}

void
psp_ssh_display_screen()
{
  psp_sdl_blit_console();
  psp_vt100_display_screen();
}

void
psp_ssh_thread(SceSize argc, void *argv)
{
  loc_ssh_input_begin = 0;
  loc_ssh_input_end   = 0;

  cli_main_run_session();
  
  loc_ssh_thid = -1;
}

void
psp_ssh_clear_screen()
{
  psp_ssh_display_screen();
}

void
psp_ssh_start_main_thread()
{
  /* Launch ssh client thread */
  loc_ssh_thid = sceKernelCreateThread( "ssh_thread", 
     (SceKernelThreadEntry)psp_ssh_thread, 0x18, 0x10000, 0, 0 );

  if(loc_ssh_thid >= 0) {
    sceKernelStartThread(loc_ssh_thid, 0, 0);
  }
}

void
psp_ssh_stop_main_thread()
{
  if (loc_ssh_thid != -1) {
    sceKernelExitDeleteThread(loc_ssh_thid);
    sceKernelWaitThreadEnd(loc_ssh_thid, NULL);
    loc_ssh_thid = -1;
  }
  cli_main_close_session();
}

void
psp_ssh_main()
{
  SceCtrlData c;

  long new_pad;
  long old_pad;

  int  danzeff_mode = 0;
  int  danzeff_key;
# ifdef USE_PSP_IRKEYB
  int  irkeyb_mode = 0;
  int  irkeyb_key = 0;
# endif
  int last_time  = 0;

# if 0 //LUDO: FOR_TEST
  loc_ssh_input_begin = 0;
  loc_ssh_input_end   = 0;
# endif

  psp_ssh_start_main_thread();
  sceKernelDelayThread(3000000);

  while (! cli_session_is_terminated()) {

    psp_ssh_display_screen();

    if (danzeff_mode) {
      danzeff_moveTo(-50, -50);
      danzeff_render();
    }
    psp_sdl_flip();

    if (PSPSSH.psp_screenshot_mode) {
      PSPSSH.psp_screenshot_mode--;
      if (PSPSSH.psp_screenshot_mode <= 0) {
        psp_sdl_save_screenshot();
        PSPSSH.psp_screenshot_mode = 0;
      }
    }
    if (PSPSSH.psp_save_log_mode) {
      PSPSSH.psp_save_log_mode--;
      if (PSPSSH.psp_save_log_mode <= 0) {
        psp_vt100_save_log();
        PSPSSH.psp_save_log_mode = 0;
      }
    }

# ifdef USE_PSP_IRKEYB
    irkeyb_mode = 0;
# endif
    sceDisplayWaitVblankStart();
 
    while (1) {
      myCtrlPeekBufferPositive(&c, 1);
      c.Buttons &= PSP_ALL_BUTTON_MASK;

      new_pad = c.Buttons;

# ifdef USE_PSP_IRKEYB
# if 0
      irkeyb_key = psp_irkeyb_check_vt100_key();
      if (irkeyb_key != PSP_IRKEYB_EMPTY) {
        psp_ssh_put_key_to_ssh(irkeyb_key);
        last_time = c.TimeStamp;
        irkeyb_mode = 1;
        break;
      }
# else
      char *irkeyb_buffer = 0;
      int irkeyb_length = psp_irkeyb_peek_data(&irkeyb_buffer);
      if (irkeyb_length > 0) {
        psp_ssh_put_data_to_ssh(irkeyb_buffer, irkeyb_length);
        last_time = c.TimeStamp;
        irkeyb_mode = 1;
        break;
      }
# endif
# endif
      if ((old_pad != new_pad) || ((c.TimeStamp - last_time) > PSP_MENU_MIN_TIME)) {
        last_time = c.TimeStamp;
        old_pad = new_pad;
        break;
      }
    }
# if 0
    {
      char *irkeyb_buffer = 0;
      int irkeyb_length = psp_irkeyb_peek_data(&irkeyb_buffer);
      if (irkeyb_length > 0) {
        psp_ssh_put_data_to_ssh(irkeyb_buffer, irkeyb_length);
        continue;
      }
    }
# endif
    if (irkeyb_mode) continue;

    if (danzeff_mode) {

      danzeff_key = danzeff_readInput(c);

      /* Hack for utf8 chars */
      if (((danzeff_key >> 8) == 0xc2) ||
          ((danzeff_key >> 8) == 0xc3)) {
        char buffer_utf8[3];
        buffer_utf8[0] = danzeff_key >> 8;
        buffer_utf8[1] = danzeff_key & 0xff;
        buffer_utf8[2] = 0;
        psp_ssh_put_data_to_ssh(buffer_utf8, 2);

      } else
      if (danzeff_key < 0) {
        if (danzeff_key  < DANZEFF_CTRL_Z) {
          /* Alt keys */
          char buffer_alt[8];
          char alt_key = 'A' - danzeff_key + DANZEFF_ALT_A;
          sprintf(buffer_alt, "\033%c", alt_key);
          psp_ssh_put_data_to_ssh(buffer_alt, strlen(buffer_alt));
        } else {
          /* Control keys */
          psp_ssh_put_key_to_ssh(-danzeff_key);
        }
      } else
      if (danzeff_key > DANZEFF_START) {
        /* Disable utf8 */
        danzeff_key &= 0x7f;

        if (danzeff_key >= ' ') {
          psp_ssh_put_key_to_ssh(danzeff_key);
        } else
        if (danzeff_key == DANZEFF_PAGE_UP) {
          psp_ssh_put_data_to_ssh("\033[5~", 4);
        } else 
        if (danzeff_key == DANZEFF_PAGE_DOWN) {
          psp_ssh_put_data_to_ssh("\033[6~", 4);
        } else 
        if (danzeff_key == DANZEFF_END) {
          psp_ssh_put_data_to_ssh("\033[F", 3);
        } else 
        if (danzeff_key == DANZEFF_HOME) {
          psp_ssh_put_data_to_ssh("\033[H", 3);
        } else 
        if (danzeff_key == DANZEFF_LEFT) {
          psp_ssh_put_data_to_ssh("\b", 1);
        } else 
        if (danzeff_key == DANZEFF_UP) {
          psp_ssh_put_data_to_ssh("/", 1);
        } else 
        if (danzeff_key == DANZEFF_RIGHT) {
          psp_ssh_put_data_to_ssh(" ", 1);
        } else 
        if (danzeff_key == DANZEFF_DOWN) {
          psp_ssh_put_data_to_ssh("\n",1 );
        } else 
        if (danzeff_key == DANZEFF_INSERT) {
          psp_ssh_put_data_to_ssh("\033[2~", 4);
        } else 
        if (danzeff_key == DANZEFF_DEL) {
          psp_ssh_put_data_to_ssh("\b", 1);
        } else 
        if (danzeff_key == DANZEFF_ESCAPE) {
          psp_ssh_put_key_to_ssh('\033');
        } else 
        if (danzeff_key == DANZEFF_TAB) {
          psp_ssh_put_key_to_ssh('\t');
        } else
        if (danzeff_key == DANZEFF_F1) {
          psp_ssh_put_data_to_ssh("\033OP", 3);
        } else
        if (danzeff_key == DANZEFF_F2) {
          psp_ssh_put_data_to_ssh("\033OQ", 3);
        } else
        if (danzeff_key == DANZEFF_F3) {
          psp_ssh_put_data_to_ssh("\033OR", 3);
        } else
        if (danzeff_key == DANZEFF_F4) {
          psp_ssh_put_data_to_ssh("\033OS", 3);
        } else
        if (danzeff_key == DANZEFF_F5) {
          psp_ssh_put_data_to_ssh("\033OT", 3);
        } else
        if (danzeff_key == DANZEFF_F6) {
          psp_ssh_put_data_to_ssh("\033OU", 3);
        } else
        if (danzeff_key == DANZEFF_F7) {
          psp_ssh_put_data_to_ssh("\033OV", 3);
        } else
        if (danzeff_key == DANZEFF_F8) {
          psp_ssh_put_data_to_ssh("\033OW", 3);
        } else
        if (danzeff_key == DANZEFF_F9) {
          psp_ssh_put_data_to_ssh("\033OX", 3);
        }

      } else 
      if ((danzeff_key == DANZEFF_START ) || 
          (danzeff_key == DANZEFF_SELECT)) 
      {
        danzeff_mode = 0;
        old_pad = new_pad = 0;

        psp_kbd_wait_no_button();
      }

      continue;
    }

    if ((c.Buttons & (PSP_CTRL_LTRIGGER|PSP_CTRL_RTRIGGER|PSP_CTRL_START)) ==
        (PSP_CTRL_LTRIGGER|PSP_CTRL_RTRIGGER|PSP_CTRL_START)) {
      /* Exit ! */
      psp_sdl_exit(0);
    } else
    if(new_pad & PSP_CTRL_SELECT) {
      /* Back to Main Menu */
      psp_ssh_menu();

    } else
    if(new_pad & PSP_CTRL_START) {
      danzeff_mode = 1;
    } else
    if(new_pad & PSP_CTRL_CROSS) {
      psp_ssh_put_key_to_ssh('\n');
    } else
    if(new_pad & PSP_CTRL_TRIANGLE) {
      psp_ssh_put_key_to_ssh('\t');
    } else
    if(new_pad & PSP_CTRL_SQUARE) {
      psp_ssh_put_key_to_ssh('\b');
    } else
    if(new_pad & PSP_CTRL_CIRCLE) {
      psp_ssh_put_key_to_ssh(' ');
    } else
    if(new_pad & PSP_CTRL_LTRIGGER) {
      psp_vt100_screen_scroll_down();
    } else
    if(new_pad & PSP_CTRL_RTRIGGER) {
      psp_vt100_screen_scroll_up();
    } else
    if (new_pad & PSP_CTRL_LEFT) {
      psp_ssh_put_data_to_ssh("\033[D", 3);
    } else 
    if (new_pad & PSP_CTRL_UP) {
      psp_ssh_put_data_to_ssh("\033[A", 3);
    } else 
    if (new_pad & PSP_CTRL_RIGHT) {
      psp_ssh_put_data_to_ssh("\033[C", 3);
    } else 
    if (new_pad & PSP_CTRL_DOWN) {
      psp_ssh_put_data_to_ssh("\033[B", 3);
    }
  }

  psp_ssh_stop_main_thread();

# if 0 //LUDO: FOR_TEST !
  psp_sdl_exit(0);
# endif

# if 0
  if (loc_ssh_thid != -1) {
    sceKernelExitDeleteThread(loc_ssh_thid);
    sceKernelWaitThreadEnd(loc_ssh_thid, NULL);
    loc_ssh_thid = -1;
  }
# endif
}
