#define CHINESE_SYSTEM
#include <stdio.h>
#include <stdarg.h>
#include <stdarg.h>
#include "chinese.h"
struct {
  int inverted:1;
  int underline:1;
  int bold:1;
  int color;
  int scroll_upper,scroll_lower;
  int ox,oy;
} termstate = {0,0,0,0,0,0,0};
#define max(a,b) (((a) > (b))? (a):(b))
#define min(a,b) (((a) > (b))? (b):(a))

#define NORMAL 0
#define ESC    1
#define BRA    2
#define SEND   3
#define RSEND  4
#define LINE   5
#define CHINESE 6
  
#define PARN   1
#define INIT   2

int state = NORMAL;
int esc_state = NORMAL;


static void state_esc(char c);
static void state_bra(char c);
static void save_cursor(),restore_cursor();
static void set_attribute();
void con_init();
FILE *log;
#ifdef DEBUG_LOG_INPUT
static FILE *log_file;
#endif
void con_init()
{
  termstate.inverted = termstate.underline = 0;
  termstate.color = 15;
  termstate.scroll_upper = 0;
  termstate.scroll_lower = ch_DimY()-1;
  termstate.ox = termstate.oy = 0;
  log = fopen("/dev/tty8","w");
#ifdef DEBUG_LOG_INPUT
  log_file = fopen("/tmp/logfile","w");
  if (log_file == NULL)
    {
      fprintf(log,"Can' open output log file\n");
    }
#endif
}

int _cwrite(int con,const char *buf,int len)
{
  int i;
  
  _ch_swap_console(con);
#ifdef DEBUG_LOG_INPUT
  fprintf(log_file,"@");
  fwrite(buf,1,len,log_file);
  fflush(log_file);
#endif
  for(i=0;i<len;i++,buf++)
    {
      switch(state) 
	{
	case ESC:
	  state_esc(*buf);
	  continue;
	case BRA:
	  state_bra(*buf);
	  continue;
	case SEND:
	  printf("\033(%c",*buf);
	  break;
	case RSEND:
	  printf("\033)%c",*buf);
	  break;
	case LINE:
	  /* NO FUNCTION */
	  break;
	case CHINESE:
	  if (*buf <= '9' && *buf >= '0')
	    ch_inputmethod(*buf-'0');
	  break;
	default:
	  if (*buf == 27)
	    {
	      state = ESC;
	      continue;
	    }
	  else
	    ch_showch(*buf);
	}
      state = NORMAL;
    }
  _ch_swap_console(0);
  return len;
}
	
  
static void state_esc(char c)
{
  /* Control char can be use in escape sequence */
  if (c < 32)
    {
      ch_showch(c);
      return;
    }
  switch(c)
    {
    case '[':
      state = BRA;
      return;
    case '(':
      state = SEND;
      return;
    case ')':
      state = RSEND;
      return;
    case '<':
      /* ANSI mode */
      break;
    case '#':
      /* NO FUNCTION*/
      state = LINE;
      return;
    case '*':
      state = CHINESE;
      return;
    case 'c':
      con_init();
      break;
    case 'D':
	  ch_scroll(termstate.scroll_upper,termstate.scroll_lower,1);
      break;
    case 'E':
      ch_gotoxy(0,min(ch_wherey()+1,ch_DimY()-1));
      break;
    case 'M':
      ch_rscroll(termstate.scroll_upper,termstate.scroll_lower,1);
      break;
    case '7':
      save_cursor();
      break;
    case '8':
      restore_cursor();
      break;
    case 'Z': /* Respond to terminal identify (VT102) */
      /* NO FUNCTION */
    }
  state = NORMAL;
  esc_state = NORMAL;
}

static void save_cursor()
{
  termstate.ox = ch_wherex();
  termstate.oy = ch_wherey();
}

static void restore_cursor()
{
  ch_gotoxy(termstate.ox,termstate.oy);
}


static void state_bra(char c)
{
  static int par[2]={0,0},parn=0,cm,i;


  if (esc_state == NORMAL)
    if ((c>='0') && (c <='9'))
      {
	parn = 1;
	esc_state = PARN;
      }

  if ((c >='0') && (c <= '9'))
    {
      par[parn-1] = par[parn-1]*10 + c - '0';
      return;
    }
  else 
    {
      if (esc_state == INIT)
	{
	  switch(c)
	    {
	    case 'l':
	      ch_have_cursor(0);
	      break;
	    case 'h':
	      ch_have_cursor(1);
	      break;
	    }
	}
      else
	{
	  switch(c)
	    {
	    case ';':
	      parn++;
	      return;
	    case 'c': /* Request terminal to identify itself */
	      /* NO FUNCTION */
	      break;
	      
	    case 'i':
	      /* NO FUNCTION */
	      break;
	    case 'q':
	      /* NO FUNCTION */
	      break;
	    case  'r':
	      if (parn == 2)
		{
		  if (!par[0])
		    par[0]++;
		  if (par[1] - par[0] < 2)
		    par[1] = par[0]+2;
		  ch_setscroll(par[0]-1,par[1]-1);
		  termstate.scroll_upper = par[0]-1;
		  termstate.scroll_lower = par[1]-1;
		  ch_gotoxy(0,0);
		}
	      break;
	    case 'm':

	      if (parn == 2)
		set_attribute(par[0],par[1]);
	      else if (parn == 1)
		set_attribute(par[0],par[0]);
	      else
		set_attribute(0,0);

	      break;
	      
	    case 'g':
	      /* NO FUNCTION */
	      break;
	    case 'A':
	      if (parn == 0)
		cm = 1;
	      else
		cm = par[0];
	      ch_gotoxy(ch_wherex(),max(ch_wherey()-cm,0));
	      break;
	    case 'B':
	      if (parn == 0)
		cm = 1;
	      else
		cm = par[0];
	      ch_gotoxy(ch_wherex(),min(ch_wherey()+cm,ch_DimY()-1));
	      break;
	    case 'C':
	      if (parn == 0)
		cm = 1;
	      else
		cm = par[0];
	      ch_gotoxy(min(ch_wherex()+cm,ch_DimX()-1),ch_wherey());
	      break;
	    case 'D':
	      if (parn == 0)
		cm = 1;
	      else
		cm = par[0];
	      ch_gotoxy(max(ch_wherex()-cm,0),ch_wherey());
	      break;
	
	    case 'J':
	      if (parn == 0|| (parn == 1&& par[0]==0))
		ch_clearblock(0,ch_wherey()+1,ch_DimX()-1,ch_DimY()-1);
	      else if (parn == 1)
		{
		  if (par[0] == 1)
		    ch_clearblock(0,0,ch_DimX()-1,ch_wherey()-1);
		  else if (par[0] == 2)
		    {
		      ch_clearblock(0,0,ch_DimX()-1,ch_DimY()-1);
		      ch_gotoxy(0,0);
		    }
		}
	      break;
	      /* through pass */
	    case 'K':
	      if (parn == 0|| (parn == 1&& par[0]==0))
		ch_clearblock(ch_wherex(),ch_wherey(),ch_DimX()-1,ch_wherey());
	      else if (parn == 1)
		{
		  if (par[0] == 1)
		    ch_clearblock(0,ch_wherey(),ch_wherex(),ch_wherey());
		  else if (par[0] == 2)
		    ch_clearblock(0,ch_wherey(),ch_DimX()-1,ch_DimY()-1);
		}
	      break;
	    case 'L':
	      if (parn == 0||(parn == 1 && par[0]==0))
		ch_insertline();
	      else if (parn == 1)
		{
		  for(i=0;i<par[0];i++)
		    ch_insertline();
		}
	      break;
	    case 'H':
	      if (parn == 0)
		ch_gotoxy(0,0);
	      else 
		{
		  if (parn == 1)
		    par[1] = 1;
		  ch_gotoxy(par[1]-1,par[0]-1);
		}
	      break;
	    case 'M':
	      if (parn == 0 || (parn==1 && par[0] == 0))
		par[0] = 1;
	      for(i=0;i<par[0];i++)
		ch_deleteline();
	      break;
	    case 'P':
	      if (parn==0 || (parn==1 && par[0]==0))
		ch_deletechar();
	      else
		{
		  for(i=0;i<par[0];i++)
		    ch_deletechar();
		}
	      break;
	    case 'Y': /* SELF TEST */
	      /* NO FUNCTION */
	      break;
	    case '@':
	      if (parn==0)
		ch_insertchar();
	      else
		{
		  if (par[0]==0)
		    par[0] = 1;
		  for(i=0;i<par[0];i++)
		    ch_insertchar();
		}
	      break;
	      
	    case '=':
	      printf("\033=");
	      break;
	    case '>':
	      printf("\033>");
	      break;
	    case '?':
	      esc_state = INIT;
	      return;
	    }
	}
      state = NORMAL;
      esc_state = NORMAL;
      parn = 0;
      par[0] = par[1] = 0;
    }
}
	  
static void set_attribute(int p1,int p2)
{

  switch(p1)
    {
    case 0:
      termstate.inverted = 0;
      termstate.underline = 0;
      ch_invert(0);
      ch_underline(0);
      break;
    case 4:
      ch_underline(0);
      termstate.underline = 0;
      break;
    case 7:
      ch_invert(1);
      termstate.inverted = 1;
      break;
    case 24:
      ch_underline(0);
      termstate.underline = 0;
      break;
    case 27:
      ch_invert(0);
      termstate.inverted = 0;
      break;
    }
}
