/*->c.term */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.akbd"


#include "h.wos"
#include "h.pr"

#include "h.timex"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.xext"

#include "h.serial"
#include "h.key"
#include "h.ftp"
#include "h.batch"
#include "h.record"
#include "h.script"

#include "h.xmodem"

#include "h.vtdef"
#include "h.vtfile"
#include "h.vtprint"
#include "h.vtact"
#include "h.vtwimp"
#include "h.vtlo"

#include "h.vxdef"
#include "h.vxterm"
#include "h.vxwimp"
#include "h.vxbuff"


#include "h.tek"
#include "h.replay"


#include "h.term"



/***************************************************************************/
/*
 Code to handle terminal byte input/output
*/
/***************************************************************************/


int txtrans;  /* flag do we translate on output ? */
int rxtrans;  /* flag do we translate on input  ? */


char txtable[256];
char rxtable[256];


void clearxlat(char * table)
{
 int i;
 if(table==txtable) txtrans=0;
 else
 if(table==rxtable) rxtrans=0;

 for(i=0;i<256;i++) *table++=i;
}


void bootxlat(void)
{
 clearxlat(txtable);
 clearxlat(rxtable);
}



/*****************************************************************************/



/*

  void translatetable(int txrx,int oldcode,int newcode);
  void cleartranslatetable(int txrx);

 */



void translatetable(int fp)
{
 int txrx=stack[fp];
 int oldcode=stack[fp+1];
 int newcode=stack[fp+2];

 if(oldcode>=0 && oldcode<=255 && newcode>=0 && newcode<=255)
 {
  if(txrx==0)
  {
   txtable[oldcode]=newcode;
   txtrans=1;
  }
  else
  if(txrx==1)
  {
   rxtable[oldcode]=newcode;
   rxtrans=1;
  }
 }
}


void cleartranslatetable(int fp)
{
 int txrx=stack[fp];

 if(txrx==0) clearxlat(txtable);
 else
 if(txrx==1) clearxlat(rxtable);
}


#define KBMASK 127

static char kbuff[128];
static int  kblo;
static int  kbhi;
static int  kbclaimed;


int kbget(void)
{
 if(kblo<kbhi) return(kbuff[kblo++ & KBMASK]);
 else          return(-1);
}

int kbput(int byte)
{
 if((kbhi-kblo)<KBMASK) kbuff[kbhi++ & KBMASK]=byte;
 return(0);
}



/* int kgetc(int time) */

int kgetc(int fp)
{
 int time=stack[fp]+clock();
 int c;

 do
 {
  if((c=kbget())!=-1) return(c);
  if(scriptstop()) break;
  if(scriptpoll) pollzt();
 } while(clock()<time);

 return(-1);
}



void claimkeyboard(int fp)
{
 kbclaimed=(stack[fp]!=0);
}


void termline(int fp)
{
 int temp;

 temp=stack[fp];
 if(temp<0 || temp>7) terminalmode=TMODENUL;
 else
 if(temp==0 || temp==1)
 {
  if(vxexists) terminalmode=TMODEVX;
 }
 else
 {
  if(vtexists) terminalmode=TMODEVT;
 }
}



/* void termtab(int term,int x,int y) */


void termtab(int fp)
{
 int terminal=stack[fp];
 int x=stack[fp+1];
 int y=stack[fp+2];

 if(terminal==TERMVX || terminal==TERMMX)
 {
  vxsetcursor();
  ttvx=x;
  ttvy=y;
 }
 else
 if(terminal==TERMTEK) teksetcurs(x,y);
 else
                       vtsetcursorp(x-1,y-1);
}



/*

int termchar(int terminal,int x,int y);

Return character at posn (x,y) in terminal window.

terminal can be VIEWDATA or VT320

 */

int termchar(int fp)
{
 int terminal=stack[fp];
 int x=stack[fp+1];
 int y=stack[fp+2];

 if(terminal==TERMVX || terminal==TERMMX) return(vscr->tcbuf[y][x] & 0x1FF);
 else                                     
 {
  tline * lp;
  int     loc;
  int   * data;

  lp=vtindex(tops+y);
  loc=lp->loc;
  data=(int *)(linedata+loc);                                                     return(data[x] & 0x3FF);
 }
}


/*


int  termcurs(int terminal,int coord);

terminal can be VIEWDATA,VT320,TEK

coord 0 returns X coord.
      1 returns Y coord.

*/



int  termcurs(int fp)
{
 int terminal=stack[fp];
 int coord=stack[fp+1];
 int x;
 int y;

 if(terminal==TERMVX || terminal==TERMMX)
 {
  x=ttvx;
  y=ttvy;
 }
 else
 if(terminal==TERMTEK)
 {
  tekgetcurs(&x,&y);
 }
 else
 {
  x=ttyx+1;
  y=ttyy+1;
 }

 if(coord) return(y);
 else      return(x);
}



/*****************************************************************************/



int termoutbyte(int byte)
{
 if(txtrans) byte=txtable[byte];

 if(kbclaimed) return(kbput(byte));
 else          return(outbyte(byte));
}



int concode;          /* 0==normal 2==expand 1==No ctrls */
int terminalmode;     /* 1==viewdata 2==VT */
int terminalmodeset=1;/* flag have we deliberately put the terminal on line */


int currentterminal=TERMNONE;
int defaultterminal=TERMANSI;
int currentterminalopen;
int newdata;


int ttns;

char * termname[TERMMAX]=
{
 "TERM00",
 "TERM01",
 "TERM02",
 "TERM03",
 "TERM04",
 "TERM05",
 "TERM06",
 "TERM07",
 "TERM08"
};



static int saveterminalmode;

void savetmode(int newmode)
{
 saveterminalmode=terminalmode;
 terminalmode=newmode;
}


void loadtmode(void)
{
 terminalmode=saveterminalmode;
}



void tty2(int byte)
{
 if(spconcode && spoolflag) myspool(byte);

 if(terminalmode==TMODEVX) viewx(byte);
 else
 if(terminalmode==TMODEVT)
 {
  if(tekexists)
  {
   if(!vttekmode && tektextplane) vt220byte(byte);
   else                           tekt(byte);
  }
  else vt220byte(byte);
 }
}



void termcodes(int byte)
{
 char string[8];
 int  i;
 uncode(string,byte);
 for(i=0;string[i];i++) tty2(string[i]);
}


/* produces the character terminal actually sees */
/* used by getprompt, and record files           */


int termmask(int byte)
{
 if(terminalmode==TMODEVX)  byte=vxmaskbyte(byte);
 else
 if(terminalmode==TMODEVT)
 {
  if(tekexists)
  {
   if(!vttekmode && tektextplane) byte=vtmaskbyte(byte);
   else                           byte=tekmaskbyte(byte);
  }
  else byte=vtmaskbyte(byte);
 }
 return(byte);
}





int tty(int byte)
{
 if(byte!=-1)
 {
  if(filter) byte&=0x7F;

  if(rxtrans) byte=rxtable[byte];

  if(recordflag) recordvdu(termmask(byte));

  if(concode==TERMEXECCTRLS) tty2(byte);
  else
  if(concode==TERMDISPCTRLS) termcodes(byte);
  else
  if(byte>31 || byte==10 || byte==13) tty2(byte);
 }

 return(byte);
}



static int  zmhi;
static char zmbuff[16];
static int  zmtime;
static int  zmtrap;
static int  zmtype;




void zmzero(void)
{
 remzeroevent(ZMZERO);

 if(zmtype==1 && txbatchfiles()) ftpsendp(PZMODEM);   /* we should send    */
 else
 if(zmtype==0) ftpreceivep(PZMODEM);   /* we should receive */
}




void zmflush(void)
{
 int i;

 tty('X'-'@');
 for(i=0;i<zmhi;i++) tty(zmbuff[i]);

 zmtrap=0;
}


int xhex(int c)
{
 if(isdigit(c)) c=c-'0';
 else           c=toupper(c)-'A'+10;
 return(c);
}




int ztty(int byte)
{
 int i;
 int crc;
 int c;

 if(zmautodload)
 {
  if(zmtrap)
  {
   if(byte!=-1)
   {
    zmbuff[zmhi++]=byte;

    if(zmhi==1 && byte!='B')
    {
     zmflush();
    }
    else
    if(zmhi>14)
    {
     crc=0;

     for(i=1;i<15;i+=2)
     {
      if(isxdigit(zmbuff[i]) && isxdigit(zmbuff[i+1]))
      {
       c=(xhex(zmbuff[i])<<4)+xhex(zmbuff[i+1]);
       crc=updcrc(c,crc);
       if(i==1) zmtype=c;
      }
      else break;
     }

     if(i<15 || (crc & 0xFFFF))
     {
      zmflush();
     }
     else
     {
      zmtrap=0;
      byte=-1;
      addzeroevent(ZMZERO);
     }
    }
   }
   else
   {
   if(zmtime<zerotime) zmflush();
   }
   return(byte);
  }
  else
  if(byte==('X'-'@'))
  {
   zmtrap=1;
   zmhi=0;
   zmtime=zerotime+100;
   return(byte);
  }
 }
 return(tty(byte));
}



void termzero(void)
{
 if(active && !ftpactive && terminalmode && ztty(getbyte())!=-1)
 {
  while(ztty(getbyte())!=-1);
  if(newdata && !currentterminalopen) setnewdata(1);
 }
}



/* attempt to get prompt, return 1, else 0 (fail) */

int getprompt(char * string,int time)
{
 char result[128];
 int  len;
 int  match;
 int  code;
 int  byte;

 if(convert(string,result,&len,128)) return(0);

 time=clock()+time;
 code=0;
 match=0;

 while(clock()<time)
 {
  byte=getbyte();

  if(byte!=-1)
  {
   if(terminalmode) tty(byte);

   if(filter)  byte&=0x7F;

   if(rxtrans) byte=rxtable[byte];

   byte=termmask(byte);

   if(result[match]==byte)
   {
    match++;
    if(match==len)
    {
     code=1;
     break;
    }
   }
   else match=0;
  }
  else
  {
   if(scriptpoll) pollzt();
   if(scriptstop()) break;
  }
 }

 return(code);
}



int ttywrite(int byte)
{
 tty(byte);
 return(0);
}

void termstring(char * s)
{
 while(*s) ttywrite(*s++);
}



int convertstringterm(char * string)
{
 return(expandmacro(ttywrite,string));
}


/*****************************************************************************/


int asciifile;


void asciizero(void)
{
 remzeroevent(ASCIIZERO);
 asciisetone(asciifile);
 ftpsendp(PASCII); 
}


int termloadfile(int type,char * name,int xvolatile)
{
 if(isshift) startreplay(type,name,xvolatile);
 else
 if(isctrl && !ftpactive)
 {
  asciifile=addtotxbatch(type,name,xvolatile,0);
  if(asciifile--) addzeroevent(ASCIIZERO);
 }
 else        addtotxbatch(type,name,xvolatile,1);
 return(1);
}


/*****************************************************************************/


void destroyterminals(void)
{
 if(currentterminal!=TERMNONE)
 {
  xexec("sys_term_destroy",NULL,&currentterminal,NULL);

  vtclosewindows();
  vtdestroy(); 
  vxclosewindows();
  vxdestroy();
  tekclosewindows();
  tekdestroy();
  ttns=0;
  currentterminal=TERMNONE;
  terminalmode=TMODENUL;
  remzeroevent(TERMZERO);
 }
}



/* called from Terminal menu */

void setterm(int term)
{ 
 int new;

 if(term<0 || term>TERMMAX) return;

 if(term!=currentterminal)
 {
  destroyterminals();
  new=1;

  if(term==TERMVX || term==TERMMX)
  {
   if(!vxcreate(term)) return;
  }
  else
  {
   if(term==TERMTTNS)
   {
    if(!vtcreate(TERMVT100)) return;
    if(!vxcreate(TERMVX))
    {
     destroyterminals();
     return;
    }

    if(campusdefault==TERMVX) terminalmode=TMODEVX;
    else                      terminalmode=TMODEVT;
    terminalmodeset=1;

    ttns=1;
   }
   else
   if(term==TERMTEK) 
   {
    if(!vtcreate(TERMVT100)) return;
    tekcreate();
   }
   else
   {
    if(!vtcreate(term)) return;
   }
  }

  xexec("sys_term_create",NULL,&term,NULL);
 }
 else new=0;

 if(term==TERMVX || term==TERMMX)  vxopenwindows(new);
 else
 {
  if(term==TERMTTNS)
  {
   if(terminalmode==TMODEVT)
   {
    vxopenwindows(new);
    vtopenwindows(new);
   }
   else
   {
    vtopenwindows(new);
    vxopenwindows(new);
   }
  }
  else
  if(term==TERMTEK)
  {
   if(tektextplane)
   {
    vtopenwindows(teknew);
    teknew=0;
   }
   tekopenwindows(new);
  }
  else vtopenwindows(new);
 }

 currentterminal=term;
 currentterminalopen=1;

 setnewdata(0);
 addzeroevent(TERMZERO);

 xexec("sys_term_open",NULL,&term,NULL);

 commsfnopenwindow();
}


void closeterm(void)
{
#ifndef VICK

 keyboardoncaret(0); 

 if(currentterminal==TERMVX || currentterminal==TERMMX) vxclosewindows();
 else
 {
  if(currentterminal==TERMTEK)  tekclosewindows();
  if(currentterminal==TERMTTNS) vxclosewindows();
  vtclosewindows();
 }

 xexec("sys_term_close",NULL,&currentterminal,NULL);

 currentterminalopen=0;

 closereplay();
 commsfnclosewindow();

#endif
}


/* called from click on icon bar, boots appropriate terminal */

void iconterm(void)
{
 if(!currentterminalopen)
 {
  if(currentterminal==TERMNONE) setterm(defaultterminal);
  else                          setterm(currentterminal);
 }
 else
 {
  if(currentterminal==TERMVX || currentterminal==TERMMX) vxsetfocusfront();
  else
  if(currentterminal==TERMTEK);
  else
  if(currentterminal==TERMTTNS);
  else                            vtsetfocusfront();
 }
}



void setpopterm(void)
{
 int i;
 for(i=0;i<=TERMMAX;i++)  tickst(term_menu,i,i==currentterminal);
}



void decodeterm(int m2)
{
 setterm(m2);
 setpopterm();
}



void minimisememory(void)
{
 printerflush();
 if(!currentterminalopen) destroyterminals();
 if(!vxclearbok()) vxbclearunsaved();
}

