/* Copyrigh(c) 1993
   The below program is used to display chinese character in screen
   without X window in LINUX.The program is protected under GNU copyleft
   .The detailed is as GNU's COPYING which i include it in the package.
   You can distribute this program freely.But YOU MUST DISTRIBUTE THE
   COMPLETE CODE IN THE PACKAGE.If you have modified the package,you
   must note it in README file and told others how to get the origin 
   version.
*/

/*
   $Id: chinese.c,v 0.23 1993/11/13 21:58:35 root Exp $
*/

/********************************************************************/
/*     main modual                                                  */ 
/*        Builded date : 1993/08/09                                 */
/*     Modified                                                     */
/*        1993/08/10                                                */
/*             (1) add function ch_cursoron,ch_cursoroff            */
/*             (2) add function ch_cursor_blink                     */        
/*        1993/08/14                                                */
/*	       (1) modified ch_cursoron and ch_cursoroff. Now they  */
/*                 are used to turn on/off cursor.                  */
/*        1993/08/28                                                */
/*             (1) Change to accomodate the application of daemon   */
/*        1993/09/03                                                */
/*             (1) support virtual console.This is version 0.2      */    
/********************************************************************/  
#include "portable.h"
#include "color.h"
#include "vga.h"
#include "chinese.h"
#include "chmsg.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/kd.h>
static void newline();
static void advance();
void ch_goto_systemarea(int);
void ch_cursor();
static void showch_attr(char,char);
#define max(x,y) (((x)>(y))? x:y)
#define UNDERLINE 1
#define INVERT    2
#define COUPLE_LEFT    0x80
#define COUPLE_RIGHT   0x40
/* default color scheme */
int COLOR_DEFAULT_FG = 15;
int COLOR_DEFAULT_BG = 0;
int COLOR_SYSTEM_FG = 0;
int COLOR_SYSTEM_BG = 10;
/* the below is no effect now */
int CURSOR_SL = 13;
int CURSOR_EL = 15;


static VSC vscreen[CONS_NUM];
static VSC *nscr;
static int write_to_screen = 0;
static int activeconsole;

FILE *statuslog;
#define curx           (nscr->curx)
#define cury           (nscr->cury)
#define dimx           (nscr->dimx)
#define dimy           (nscr->dimy)
#define cursor_x       (nscr->cursor_x)
#define cursor_y       (nscr->cursor_y)
#define cursor_blinked (nscr->cursor_blinked)
#define no_cursor       (nscr->no_cursor)
#define cursor_rate    (nscr->cursor_rate)
#define scr_text        (nscr->scrtext)
#define scr_attr        (nscr->scrattr)
#define cursor_on      (nscr->cursor_on)
#define c_stack        (nscr->c_stack)
#define codesys        (nscr->codesys)
#define und            (nscr->und)
#define inv            (nscr->inv)
#define pos            (nscr->pos)
#define sys_attr       (nscr->sys_attr)
#define mode           (nscr->screenmode)
#define autoscroll     (nscr->isscrolled)
#define topl           (nscr->top)
#define bottoml        (nscr->bottom)

static int chconsole;
static void showcc(CHAR);
void ch_drawctext(int,int,WORD);
void ch_drawtext(int,int,CHAR);
/* switch to other screen,but no redraw in this place */
void _ch_swap_console(int newconsole)
{
  int i,j;
  static void cursor();
  static VSC *swapscr = NULL;

  if (newconsole < 0 || newconsole >= CONS_NUM)
    return;
  nscr = &(vscreen[newconsole]);
  if (scr_text == NULL)
    {
      scr_text = (char *) malloc(80*30);
      scr_attr = (char *) malloc(80*30);
      if (scr_attr == NULL)
	sys_fatel("out of memory");
      for(i=0;i<80*30;i++)
	{
	  scr_text[i] = ' ';
	  scr_attr[i] = sys_attr;
	}
    }
  if (swapscr == NULL)
    swapscr = nscr;
  else
    {
      nscr = swapscr;
      swapscr = NULL;
    }
}
int ch_codesystem()
{
  return codesys;
}
void ch_change_console(int newconsole)
{
  int i,j,lastmode;
  static void cursor();

  if (newconsole < 0 || newconsole >= CONS_NUM)
    return;
  lastmode = mode;
  nscr = &(vscreen[newconsole]);
  if (mode == TEXT)
    mon_textmode();
  else
    mon_grmode();
    
  if (scr_text == NULL)
    {
      scr_text = (char *) malloc(80*30);
      scr_attr = (char *) malloc(80*30);
      if (scr_attr == NULL)
	sys_fatel("out of memory");
      for(i=0;i<80*30;i++)
	{
	  scr_text[i] = ' ';
	  scr_attr[i] = sys_attr;
	}
    }
  if (mode != TEXT)
    {
      if (cursor_rate != 0)
	{
	  signal(SIGALRM,cursor);
	  alarm(cursor_rate);
	}
    }
  else
    {
      alarm(0);
    }
  chconsole = newconsole;
  ch_change_input(newconsole);
  if (mode != TEXT)
    {
      ch_drawsystem();
      ch_redraw();
    }
}
/*
   The function of 
        ch_cursor_blinked : control the cursor is blinked or not
	ch_have_cursor    : control the cursor should display in screen
	ch_cursor_rate    : control the blink rate of cursor
*/


static void cursor(int signo)
{ 
  if (!cursor_blinked )
    {
      return;
    }
  ch_cursor();
  signal(SIGALRM,( void (*)()) cursor);
  alarm(cursor_rate);
} 

static void init_virtual_console()
{
  int i;

  i = 0;
  init_console();
  for(nscr = &(vscreen[0]);i < CONS_NUM;i++,nscr = &(vscreen[i]))
    {
      curx = cury = 0;
      scr_text = scr_attr = NULL;
      dimx = 80;
      dimy = 29;
      cursor_x = cursor_y = 0;
      cursor_blinked = 1;
      no_cursor = 0;
      cursor_on = 0;
      cursor_rate = 1;
      codesys = CODE_BIG5;
      sys_attr = 0;
      mode = TEXT;
      autoscroll = 1;
      topl = 0;
      bottoml = dimy-1;
    }
  ch_change_console(0);
}

void adm_init()
{
  statuslog = fopen("/dev/tty8","w");
    
  load_sys_font_table();
  init_virtual_console();
  mon_setcolor(COLOR_DEFAULT_FG+COLOR_DEFAULT_BG*256);
  con_init();
  input_init();
}


demo_output()
{
  int i;

  ch_change_console(0);
  ch_graphicmode(0);
  ch_write_to_screen(1);
  for(i=0;i<10;i++)
    ch_showstr("TEST\n");
  ch_write_to_screen(0);
  sleep(10);
  ch_textmode(0);
}

	
ch_drawsystem()
{
  int oldx = ch_wherex(),
      oldy = ch_wherey();
  int i,oldw,color;
  i = 0;
  oldw = write_to_screen;
  color = mon_curcolor();
  mon_setcolor(COLOR_SYSTEM_BG*256+COLOR_SYSTEM_FG);
  write_to_screen = 1;
  
  ch_goto_systemarea(0);
  for(i=0;i<79;i++)
    ch_showch(' ');
  ch_goto_systemarea(0);
  ch_showstr("[¤¤¤å-");
  showcc('0'+chconsole);
  showcc(']');
  ch_gotoxy(oldx,oldy);
  ch_input_redraw();
  if (dimy != MAX_DIMY)
    {
      mon_setcolor(COLOR_SYSTEM_FG);
      for(i=0;i<5;i++)
	mon_drawline(0,dimy*16+i,dimx*8-1,dimy*16+i);
    }
  write_to_screen = oldw;
  mon_setcolor(color);
}

void ch_clear()
{
  ch_cursor_blink(0);
  if (write_to_screen)
    mon_clearblock(0,dimx,0,dimy*16-1);
  ch_gotoxy(0,0);
  ch_cursor_blink(1);
}

void ch_clreol()
{
  int i;

  if (write_to_screen)
    {
      ch_cursor_blink(0);
      mon_clearblock(curx,cury*16,dimx-1,(cury+1)*16);
      ch_cursor_blink(1);
    }
  for(i=curx;i<dimx-1;i++)
    {
      scr_text[cury*dimx+i] = ' ';
      scr_attr[cury*dimx+i] = sys_attr;
    }
}
void ch_system_clreol()
{
  int color,i;
  int oldw = autoscroll;
  if (write_to_screen)
    {
      autoscroll = 0;
      color = mon_curcolor();
      mon_setcolor(COLOR_SYSTEM_FG+COLOR_SYSTEM_BG*256);
      ch_cursor_blink(0);
      for(i=curx;i<dimx;i++)
	showcc(' ');
      autoscroll = oldw;  
      ch_cursor_blink(1);
      mon_setcolor(color);
    }
  for(i=curx;i<dimx-1;i++)
    {
      scr_text[cury*dimx+i] = ' ';
      scr_attr[cury*dimx+i] = sys_attr;
    }

}
  
void ch_cursor()
{
  if (cursor_on)
    {
      /* erase the last cursor if it be change place */
      if (curx != cursor_x || cury != cursor_y)
	{
	  mon_cursor(cursor_x,cursor_y*16);
	  cursor_on = 0;
	  cursor_x = curx;
	  cursor_y = cury;
	}
    }
  else
    {
      cursor_x = curx;
      cursor_y = cury;
    }
  mon_cursor(curx,cury*16);
  cursor_on = 1 - cursor_on;
}

void ch_gotoxy(int x,int y)
{
  ch_cursor_blink(0);
  if ((x >= 0) && (x < dimx) && (y >= 0) && (y < dimy))
    {
      if (cury == MAX_DIMY)
	ch_have_cursor(1);
      curx = x;
      cury = y;
      c_stack = 0;
      pos = cury*dimx+curx;
    }
  ch_cursor_blink(1);
}

static void showcc(CHAR c)
{
  int i;

#ifdef USE_BY_CHDAM
  extern int *infd;
#endif  
  ch_cursor_blink(0);  
  switch(c)
    {
    case 7:
      ioctl(infd[chconsole],KDMKTONE,0x06370100);
      break;
    case '\n':
      newline();
      break;
    case '\r':  
      ch_gotoxy(0,cury);
      pos = cury*dimx+curx;
      break;
    case '\b':
      ch_gotoxy(max(0,curx-1),cury);
      /*
      mon_drawtext(curx,cury*16,efont[(int)' ']);
      pos = cury*dimx+curx;

      if (scr_attr[pos] &COUPLE_LEFT)
	scr_attr[pos+1] &= ~(COUPLE_RIGHT);
	  
      for(i=pos;i<pos+dimx-curx-1;i++)
	{
	  scr_text[i] = scr_text[i+1];
	  scr_attr[i] = scr_attr[i+1];
	}
      scr_text[i] = ' ';
      scr_text[i] = sys_attr;
      */
      break;
    case '\t':
      ch_gotoxy((curx / 8 +1)*8-1,cury);
      pos = cury*dimx+curx;
      advance();
      break;
    default:
      if (c < 128 && c >= 32)
	if (write_to_screen)
	  ch_drawtext(curx,cury,c);
      scr_text[pos] = c;
      scr_attr[pos] = sys_attr;
      advance();
    }
  ch_cursor_blink(1);
}




void ch_showch(CHAR c)
{
  WORD code,code1;
  
  if (scr_attr[pos]&COUPLE_LEFT)
    scr_attr[pos+1] &= ~(COUPLE_RIGHT);
  else if (scr_attr[pos]&COUPLE_RIGHT)
    scr_attr[pos-1] &= ~(COUPLE_LEFT);

  if (!(scr_attr[pos-1]&COUPLE_RIGHT))
    if ((curx != 0) && (scr_text[pos-1]>=128))
      {
	/* 
	   the left char is uncoupled,so we test if we can couple
	   with the left                 
	*/

	code = tran_code(codesys,scr_text[pos-1],c);
	if (code != 0xffff)
	  {
	    scr_text[pos] = c;
	    scr_attr[pos] = (sys_attr | COUPLE_RIGHT);
	    scr_attr[pos-1] |= COUPLE_LEFT;
	    ch_cursor_blink(0);
	    ch_drawctext(curx-1,cury,code);
	    ch_cursor_blink(1);
	    advance();
	    return;
	  }
      }

  /* the char can't couple with its left char */
  /* In this time test if can couple with the right */
  if (scr_attr[pos+1]&COUPLE_LEFT)
    showcc(c);
  else
    {
      if (curx == dimx - 1)
	{
	  showcc(c);
	  return;
	}
      if (c < 128)
	{
	  showcc(c);
	  return;
	}
      code = tran_code(codesys,c,scr_text[pos+1]);
      if (code == 0xffff)
	showcc(c);
      else
	{
	  scr_text[pos] = c;
	  scr_attr[pos] = sys_attr | COUPLE_LEFT;
	  scr_attr[pos+1] |= COUPLE_RIGHT;
	  ch_cursor_blink(0);
	  ch_drawctext(curx,cury,code);
	  ch_cursor_blink(1);
	  advance();
	}
    }
}
	  
void ch_showstr(CHAR *s)
{
  while(*s)
    {
      ch_showch(*s++);
    }
}
	  
int ch_wherex()
{
  return curx;
}
int ch_wherey()
{
  return cury;
}

void ch_setdim(int x,int y)
{
  dimx = x;
  dimy = y;
}
int ch_DimX()
{
  return dimx;
}
int ch_DimY()
{
  return dimy;
}

static void advance()
{
  ch_cursor_blink(0);
  curx++;pos++;
  if (curx >= dimx)
    {
      cury++;
      curx = 0;
      if (cury >=dimy)
	{
	  if (autoscroll)
	    ch_scroll(topl,bottoml,1);
	  cury = dimy -1;
	  pos = cury*dimx+curx;
	}
    }
  ch_cursor_blink(1);
}
static void newline()
{
  ch_cursor_blink(0);
  cury++;
  if (cury >= dimy)
    {
      if (autoscroll)
	ch_scroll(topl,bottoml,1);
      cury = dimy-1;
    }
  pos = cury*dimx+curx;
  ch_cursor_blink(1);
}
void ch_scroll(int ul,int dl,int l)
{
  int i,j;

  ch_cursor_blink(0);
  mon_scroll(ul*16,(dl+1)*16,l*16);
  ch_cursor_blink(1);
  for(j=ul;j<=dl-1;j++)
    {
      memcpy(scr_text+j*dimx,scr_text+(j+1)*dimx,dimx);
      memcpy(scr_attr+j*dimx,scr_attr+(j+1)*dimx,dimx);
    }
  memset(scr_text+j*dimx,' ',dimx);
  memset(scr_attr+j*dimx,sys_attr,dimx);

}
void ch_rscroll(int ul,int dl,int l)
{
  int i,j;
 
  ch_cursor_blink(0);
  mon_rscroll(ul*16,(dl+1)*16,l*16);
  ch_cursor_blink(1);
  for(j=dl-1;j>ul;j--)
    {
      memcpy(scr_text+j*dimx,scr_text+(j-1)*dimx,dimx);
      memcpy(scr_attr+j*dimx,scr_attr+(j-1)*dimx,dimx);
    }
  memset(scr_text+dl*dimx,' ',dimx);
  memset(scr_attr+dl*dimx,sys_attr,dimx);
}

/*
int ch_getch()
{
  return vga_getch();
}
*/
void adm_end()
{
  mon_textmode(TEXT);
}
  
void ch_cursoron()
{
  if (!cursor_on)
    ch_cursor();
  ch_cursor_blink(1);
}

void ch_cursoroff()
{
  if (cursor_on)
    ch_cursor();
  ch_cursor_blink(0);
}

void ch_cursor_blink(int i)
{
  cursor_blinked += ((i == 0)? -1 : 1);
  if (no_cursor)
    {
      return;
    }
  
  if (cursor_blinked == 0 && (i == 0))
    {
      if (cursor_on)
	ch_cursor();
      signal(SIGALRM,SIG_IGN);
    }
  else if (cursor_blinked == 1 && (i == 1))
    {
      if (!cursor_on)
	ch_cursor();
      signal(SIGALRM,cursor);
      alarm(cursor_rate);
    }
}


void ch_cursor_rate(int rr)
{
  cursor_rate = rr;
  if (rr == 0)
    ch_cursor_blink(0);
      
}

void ch_underline(int i)
{
  if (i==1 && !und)
    {
      sys_attr |= UNDERLINE;
      und = 1;
      mon_underline(0);
    }
  else if (und)
    {
      sys_attr &= ~UNDERLINE;
      und = 0;
      mon_underline(1);
    }
}
void ch_invert(int i)
{
  if (i==1)
    {
      sys_attr |= INVERT;
      inv = 1;
      mon_invert(1);
    }
  else 
    {
      sys_attr &= ~INVERT;
      inv = 0;
      mon_invert(0);
    }
}

void ch_deletechar()
{
  int i;

  mon_moveleft(curx,dimx-1,cury*16,1);
  for(i=pos;i<pos+dimx-curx-1;i++)
    {
      scr_text[i] = scr_text[i+1];
      scr_attr[i] = scr_attr[i+1];
    }
  scr_text[i] = ' ';
  scr_attr[i] = sys_attr;
}

void ch_insertchar()
{
  int i;
  for(i=pos+dimx-curx-1;i>pos;i--)
    {
      scr_text[i] = scr_text[i-1];
      scr_attr[i] = scr_attr[i-1];
    }
  scr_text[pos] = ' ';
  scr_attr[pos] = sys_attr;
  for(i=curx;i<dimx;i++)
    showch_attr(scr_text[pos+i-curx],scr_attr[pos+i-curx]);
}
void ch_clearblock(int lx,int ty,int rx,int by)
{
  int i,j,pp;
  ch_cursor_blink(0);
  mon_clearblock(lx,ty*16,rx,by*16+15);
  ch_cursor_blink(1);
  for(j=ty;j<=by;j++)
    {
      pp = j*dimx+lx;
      for(i=lx;i<=rx;i++)
	{
	  scr_text[pp] = ' ';
	  scr_attr[pp++] = sys_attr;
	}
    }
}
void ch_insertline()
{
  ch_rscroll(cury,bottoml-1,1);
}
void ch_deleteline()
{
  fprintf(statuslog,"DELETELINE(%d,%d)\n",cury,bottoml-1);
  ch_scroll(cury,bottoml-1,1);
}

void ch_goto_systemarea(int loc)
{
  ch_have_cursor(0);
  cury = MAX_DIMY;
  curx = loc;
  pos = cury*dimx+curx;
}
void ch_showBIG5(WORD c)
{
  int color = mon_curcolor();
  mon_setcolor(COLOR_SYSTEM_FG+COLOR_SYSTEM_BG*256);
  c = tran_code(CODE_BIG5,c/256,c%256);
  if (c != 0xffff)
    if (write_to_screen)
      {
	ch_cursor_blink(0);
	ch_drawctext(curx,cury,c);
	ch_cursor_blink(1);
      }
  mon_setcolor(color);
}

static char *ttys = {"/dev/tty0"};

void ch_textmode(int con)
{
  int fd;
  if (con <0 || con >= CONS_NUM)
    return;

  if (con == chconsole && (vscreen[con].screenmode != TEXT) )
    mon_textmode();
  vscreen[con].screenmode = TEXT;
}

void ch_graphicmode(int con)
{

  if ((con < 0) || (con >= CONS_NUM))
    return;

  if (con == chconsole && (vscreen[con].screenmode == TEXT))
    {
      mon_grmode();
      ch_drawsystem();
      ch_redraw();
    }
  vscreen[con].screenmode = G640x480x16;
}
static void showch_attr(char c,char attr)
{
  if (attr&UNDERLINE)
    ch_underline(1);
  else
    ch_underline(0);
  if (attr&INVERT)
    ch_invert(1);
  else
    ch_invert(0);
  ch_showch(c);
}
void ch_redraw()
{
  int i;
  int oldx = ch_wherex();
  int oldy = ch_wherey();
  int scrollmode,curcorrate;
  int oldinv = inv;
  int oldund = und;
  
  scrollmode = autoscroll;
  autoscroll = 0;
  
  ch_have_cursor(0);
  ch_gotoxy(0,0);
  c_stack = 0;
  
  for(i=0;i<dimx*dimy;i++)
    {
       showch_attr(scr_text[i],scr_attr[i]);
    }
  ch_invert(inv);
  ch_underline(und);
  ch_gotoxy(oldx,oldy);
  ch_have_cursor(1);
  autoscroll = scrollmode;
}
void ch_write_to_screen(int m)
{
  write_to_screen = m;
}
void ch_restoretext()
{
  mon_textmode();
}
void ch_have_cursor(int st)
{
  if (st == 0)
    {
      no_cursor = 1;
      alarm(0);
      if (cursor_on)
	ch_cursor();
    }
  else
    {
      no_cursor = 0;
    }
}

void ch_system_showstr(char *s)
{
  int color = mon_curcolor();
  int oldw = autoscroll;
  mon_setcolor(COLOR_SYSTEM_FG+COLOR_SYSTEM_BG*256);
  autoscroll = 0;
  ch_showstr(s);
  autoscroll = oldw;
  mon_setcolor(color);
}

void ch_system_showch(char c)
{
  int color = mon_curcolor();
  int oldw = autoscroll;
  mon_setcolor(COLOR_SYSTEM_FG+COLOR_SYSTEM_BG*256);
  autoscroll = 0;
  ch_showch(c);
  autoscroll = oldw;
  mon_setcolor(color);
}

void ch_setscroll(int t,int b)
{
  if (t < 0)
    t = 0;
  else if (t > dimy-3)
    t = dimy-3;
  if (b < 0)
    b = t + 2;
  if (b > dimy-2)
    b = dimy-1;
  bottoml = b;
  topl = t;
}

void ch_setwsize(int tty,int wx,int wy)
{
  VSC *nscr ;
  if (tty > CONS_NUM)
    return;
  
  nscr = &vscreen[tty];
  if (wx > MAX_DIMX)
    wx = MAX_DIMX;
  else if (wx < 0)
    wx = MIN_DIMX;

  if (wy > MAX_DIMY)
    wy = MAX_DIMY;
  else if (wy < 0)
    wy = 0;

  dimx = wx;
  dimy = wy;
  
}

  

