#include "VNConsole.h"
#include "vga.h"
#include <fcntl.h>
#include <sys/ioctl.h>

static int tty=2;
static int tty_inject_device;

void do_key(rfbBool down,rfbKeySym keySym,rfbClientPtr cl)
{
  static char isControl=0;

  if(down) {
    /* if(keySym==XK_Escape)
      rfbCloseClient(cl);
    else */ if(keySym==XK_Control_L || keySym==XK_Control_R)
      isControl++;
    else if(tty_inject_device>=0) {
      if(keySym==XK_Escape)
	keySym=27;
      if(isControl) {
	if(keySym>='a' && keySym<='z')
	  keySym-='a'-1;
	else if(keySym>='A' && keySym<='Z')
	  keySym-='A'-1;
	else
	  keySym=0xffff;
      }

      if(keySym==XK_Tab)
	keySym='\t';
      else if(keySym==XK_Return)
	keySym='\r';
      else if(keySym==XK_BackSpace)
	keySym=8;
      else if(keySym==XK_Home || keySym==XK_KP_Home)
	keySym=1;
      else if(keySym==XK_End || keySym==XK_KP_End)
	keySym=5;
      else if(keySym==XK_Up || keySym==XK_KP_Up)
	keySym=16;
      else if(keySym==XK_Down || keySym==XK_KP_Down)
	keySym=14;
      else if(keySym==XK_Right || keySym==XK_KP_Right)
	keySym=6;
      else if(keySym==XK_Left || keySym==XK_KP_Left)
	keySym=2;

      if(keySym<0x100) {
	int ret;
	ret=ioctl(tty_inject_device,TIOCSTI,&keySym);
	if(ret<0) {
	  static char device[64];
	  close(tty_inject_device);
	  sprintf(device,"/dev/tty%d",tty);
	  tty_inject_device=open(device,O_WRONLY);
	  ret=ioctl(tty_inject_device,TIOCSTI,&keySym);
	  if(ret<0)
	    rfbErr("Couldn't reopen device %s!\n",device);
	}
      }
    }
  } else if(keySym==XK_Control_L || keySym==XK_Control_R)
    isControl--;
}

/* these colours are from linux kernel drivers/char/console.c */
unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
				       8,12,10,14, 9,13,11,15 };
/* the default colour table, for VGA+ colour systems */
int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};

int main(int argc,char **argv)
{
  int width=80,height=25;
  char *buffer;
  vncConsolePtr console;
  char tty_device[64],title[128];
  int i;
  FILE* tty_file;
  struct winsize dimensions;

  if(argc>1) {
    if((tty=atoi(argv[1]))<1) {
      rfbErr("Usage: %s [tty_number [vnc args]]\n",argv[0]);
      exit(1);
    } else {
      argv++;
      argc--;
    }
  }

  /* getopt goes here! */

  sprintf(tty_device,"/dev/tty%d",tty);
  if((tty_inject_device=open(tty_device,O_WRONLY))<0) {
    rfbErr("Couldn't open tty device %s!\n",tty_device);
    exit(1);
  }
  rfbLog("Using device %s.\n",tty_device);

  if(ioctl(tty_inject_device,TIOCGWINSZ,&dimensions)>=0) {
    width=dimensions.ws_col;
    height=dimensions.ws_row;
  }

  sprintf(title,"LinuxVNC: /dev/tty%d",tty);

  /* console init */
  console=vcGetConsole(&argc,argv,width,height,&vgaFont,TRUE);
  for(i=0;i<16;i++) {
    console->screen->colourMap.data.bytes[i*3+0]=default_red[color_table[i]];
    console->screen->colourMap.data.bytes[i*3+1]=default_grn[color_table[i]];
    console->screen->colourMap.data.bytes[i*3+2]=default_blu[color_table[i]];
  }
  console->screen->desktopName=title;
  console->screen->kbdAddEvent=do_key;
  console->selectTimeOut=100000;
  console->wrapBottomToTop=TRUE;
#ifdef USE_OLD_VCS
  buffer=malloc(width*height);
  console->cursorActive=FALSE;
#else
  buffer=malloc(width*height*2+4);
  console->cursorActive=TRUE;
#endif
  /* memcpy(buffer,console->screenBuffer,width*height); */

#ifdef USE_OLD_VCS
  sprintf(tty_device,"/dev/vcs%d",tty);
#else
  sprintf(tty_device,"/dev/vcsa%d",tty);
#endif

  while(rfbIsActive(console->screen)) {
    if(!console->currentlyMarking) {
      tty_file=fopen(tty_device,"rb");
      if(!tty_file) {
	rfbErr("cannot open device \"%s\"\n",
		tty_device);
	exit(1);
      }
#ifdef USE_OLD_VCS
      fread(buffer,width,height,tty_file);
#else
      fread(buffer,width*height*2+4,1,tty_file);
      vcHideCursor(console);
#endif
      fclose(tty_file);

      for(i=0;i<console->width*console->height;i++) {
	if
#ifdef USE_OLD_VCS
	 (buffer[i]!=console->screenBuffer[i])
#else
	 (buffer[4+2*i]!=console->screenBuffer[i] ||
	  buffer[5+2*i]!=console->attributeBuffer[i])
#endif
	  {
	    console->x=(i%console->width);
	    console->y=(i/console->width);
	    /*
	      rfbLog("changes: %d,%d (%d!=%d || %d!=%d)\n",
	      console->x,console->y,
	      buffer[4+2*i],console->screenBuffer[i],
	      buffer[5+2*i],console->attributeBuffer[i]);
	    */
	    
#ifdef USE_OLD_VCS
	    vcPutChar(console,buffer[i]);
#else
	    vcPutCharColour(console,buffer[4+i*2],buffer[5+i*2]&0x7,buffer[5+i*2]>>4);
#endif
	  }
      }
      console->x=buffer[2];
      console->y=buffer[3];
    }
    vcProcessEvents(console);
  }
  return(0);
}
