/*->c.vtprint */

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

#include "h.os"
#include "h.bbc"
#include "h.wimp"
#include "h.flex"


#include "h.swinos"
#include "h.def"
#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.xext"
#include "h.file"
#include "h.fsx"

#include "h.xmodem"

#include "h.vtdef"

#include "h.vtlo"
#include "h.vtscr"
#include "h.vtcol"
#include "h.vtkey"
#include "h.vtselect"
#include "h.vtwimp"


#include "h.vtprint"



/*****************************************************************************/
/* printer buffer */


/*
    Acorn codes

    <27><%11000000>  Start literal escape sequence
    <27><%10fedcba>  If 'a' is 1 then toggle bold style (on=>off, off=>on)
                     If 'b' is 1 then toggle light style (on=>off, off=>on)
                     If 'c' is 1 then toggle italic style (on=>off, off=>on)
                     If 'd' is 1 then toggle underline (on=>off, off=>on)
                  If 'e' is 1 then toggle superscript (on=>off,off=>on)
                    If 'f' is 1 then toggle subscript (on=>off, off=>on)
  <27><other>     Ignored

*/


#define PDZERO  0x80;
#define PDBOLD  0x1;
#define PDITAL  0x4;
#define PDUNDER 0x8;


#define PTEXT   0
#define PEPSON  1
#define PIBM    2
#define PDRIVER 3



int  prtype=PIBM;  /* printer type RX,MX,FX */
int  preol;

/*
 #define ASCIICR   0
 #define ASCIILF   1
 #define ASCIICRLF 2
 #define ASCIILFCR 3
 #define ASCIIRAW  4
*/


int  prerrorf;


#define PRCHUNK 0x400


char * prbuff;
int    prlo;        /* lowest byte in buffer      */
int    prhi;        /* first free space in buffer */
int    prlines;     /* lines in buffer            */
int    prlinespp;   /* lines per page             */
int    prwidth;     /* width of printer           */
int    prposn;
int    prescseq;

int    prendition;

int    pdrend;      /* acorn style bits */

int    prlastpage;  /* points to end of last page in buffer */
int    prtime;



void   setprinter(int fp)
{
 int temp;

 if(stack[fp]>0)   prlinespp=stack[fp];
 if(stack[fp+1]>0) prwidth=stack[fp+1];

 temp=stack[fp+2];

 if(temp==10) preol=ASCIILF;
 else
 if(temp==13) preol=ASCIICR;
 else
 if(temp==14) preol=ASCIICRLF;
 else
 if(temp==15) preol=ASCIILFCR;
 else
 if(temp==16) preol=ASCIIRAW;
}



void sendprintmessage(void)
{
 wimp_msgstr msg;

 msg.hdr.size=((48+12) & 0xFFFFFFFC);
 msg.hdr.task=taskhandle;
 msg.hdr.your_ref=0;
 msg.hdr.action=Message_PrintSave;

 msg.data.datasave.w=0;
 msg.data.datasave.i=0;
 msg.data.datasave.x=0;
 msg.data.datasave.y=0;
 msg.data.datasave.estsize=prhi-prlo;
 msg.data.datasave.type=TEXT;
 strcpy(msg.data.datasave.leaf,"HearsayPr");

 wimp_sendmessage(17,&msg,0);

 saveref=msg.hdr.my_ref;

 setupsavetypes(SAVEPRINTER,TEXT);
}



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

static int printerfh;

static os_error * openprinter(void)
{
 os_error * err;

 err=NULL;

 if(!printerfh)
 {
  err=fs_open("PRINTER:",'w',&printerfh);
 }

 return(err);
}


static os_error * closeprinter(void)
{
 os_error * err;

 err=NULL;

 if(printerfh)
 {
  fx(21,3,0);
  err=fs_close(printerfh,NULL);
  printerfh=0;
 }

 return(err);
}


/* space==1 bytes in buffer 2=space */

extern buffercount(int space,int buffer);


static int prbytes(void)
{
 return(buffercount(1,3));
}

static int prspace(void)
{
 return(buffercount(2,3));
}

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


/* idea send the contents of the buffer to the printer */
/* then trash the buffer */

void dmpflush(void)
{
 if((prposn || prlines) && prhi>prlo)
 {
  sendprintmessage();
 }
}



void prsquash(void)
{
 if(prlo>PRCHUNK)
 {
  memmove(prbuff,prbuff+prlo,prhi-prlo);
  prhi-=prlo;
  prlastpage-=prlo;
  prlo=0;
  flex_chunk((flex_ptr)&prbuff,prhi,PRCHUNK);
 }
}



void printerdemon(void)
{
 int space;

 if(prtype==PDRIVER)
 {
  if((zerotime-prtime)>6000)
  {
   dmpflush();
   prtime=zerotime;
  }
 }
 else
 {
  if(printerfh || !openprinter()) 
  {
   space=prspace()-1;
   if(space>(prhi-prlo)) space=prhi-prlo;

/* dprintf(0,"space=%d bytes=%d lo=%d hi=%d",space,prbytes(),prlo,prhi); */

   if(space && prhi>prlo)
   {
    fs_write(printerfh,&prbuff[prlo],space);
    prlo+=space;
    prsquash();
   }
   else
   if(prlo==prhi && !prbytes())
   {
    closeprinter();
    remzeroevent(PRINTERZERO);
    prlo=prhi=prlastpage=0;
    flex_chunk((flex_ptr)&prbuff,0,PRCHUNK);
   }
  }
 }
 /* dprintf(0,"prlo=%d prhi=%d",prlo,prhi); */
}



/* reset printer buffer */

void printclear(void)
{
 prlo=prhi=prlastpage=0;
 flex_extend((flex_ptr)&prbuff,0);
 prposn=0;
 prescseq=0;
 prlines=0;
 pdrend=PDZERO;
 remzeroevent(PRINTERZERO);
 closeprinter();
}



 
static void zresc(char code)
{
 prescseq=1;
 zrsub(ESC);
 zrsub(code);
 prescseq=0;
}


static void zresc2(int code1,int code2)
{
 prescseq=1;
 zrsub(ESC);
 zrsub(code1);
 if(code2>=0) zrsub(code2);
 prescseq=0;
}






/* called from messages to send contents of buffer to printer */
/* return 1 on OK 0 not */

int prdumpbuffer(char * name)
{
 int code;
 FILE * fp;

/* dprintf(0,"prdump buffer in"); */

 fp=fopen(name,"wb");
 if(fp)
 {
  fwrite(prbuff+prlo,prlastpage-prlo,1,fp);
  fclose(fp);
  code=1;
 }
 else
  code=0;

 prlo=prlastpage;
 remzeroevent(PRINTERZERO);

/* dprintf(0,"prdump buffer ex");  */

 return(code);
}



/* called to add byte to printer buffer */

void zrsubsub(int code)
{
 if(flex_chunk((flex_ptr)&prbuff,prhi+4,PRCHUNK))
 {
  prbuff[prhi++]=code;

  if(!prescseq)
  {
   if(code==NL)
   {
    prlines++;
    if(preol!=ASCIIRAW)
    {
     if(preol==ASCIICR) prbuff[prhi-1]=CR;
     else
     if(preol==ASCIICRLF) 
     {
      prbuff[prhi-1]=CR;
      prbuff[prhi++]=NL;
     }
     else
     if(preol==ASCIILFCR)
     {
      prbuff[prhi++]=CR;
     }
    }
   }
   else
   if(code==FF) 
   {
    prlines+=(prlinespp-(prlines % prlinespp)) % prlinespp;
    prposn=0;
   }
   else
   if(code==CR)
   {
    prposn=0;
    if(preol!=ASCIIRAW) prhi--;
   }
   else
   if(code>31)  
   {
    prposn++;
    if(prposn>=prwidth)
    {
     prposn=0;
     prlines++;
    }
   }
  }
 }
}



void zrsub(int code)
{
 int empty=prhi==prlo;
 int temp;
 int oldlines=prlines;

 zrsubsub(code);

 if(prtype==PDRIVER)
 {
  if(oldlines!=prlines && ((prlines % prlinespp)==0)) 
  {
   zrsubsub(FF);
   prlastpage=prhi;
   temp=prescseq;
   prescseq=1;
   zrsubsub(ESC);
   zrsubsub(pdrend);
   prescseq=temp;
   addzeroevent(PRINTERZERO);
   prtime=clock();
   dmpflush();
  }
 }
 else 
 if(empty) addzeroevent(PRINTERZERO);

/* dprintf(1,"prlo=%d prhi=%d",prlo,prhi); */
}


void printerflush(void)
{
 if(prtype==PDRIVER && prlines) zrsub(FF);
}



void printsettype(int type)
{
 prtype=type;
 printclear();
}




void printboot(void)
{
 flex_alloc((flex_ptr)&prbuff,0);
 prlo=prhi=0;
 prposn=0;
 prlines=0;
 prescseq=0;
 prlinespp=60;
 prwidth=80;
 printerfh=0;
}




/***************************************************************************/
/*
   Code to handle VT terminals printers 
*/
/***************************************************************************/

/* printer specific code, printer output channel */



void printinit(void)
{
 prerrorf=0;
}



int prerror(void)
{
 return(prerrorf);
}





void godoubleheight(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc2('w',1);
}



void godoublewidth(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc2('W',1);
}



void goitalics(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc('4');
 else
 if(prtype==PDRIVER)
 {
  pdrend|=PDITAL;
  zresc(pdrend);
 }
}



void gounderline(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc2('-','1');
 else
 if(prtype==PDRIVER)
 {
  pdrend|=PDUNDER;
  zresc(pdrend);
 }
}



void gonoitalics(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc('5');
 else
 if(prtype==PDRIVER)
 {
  pdrend&=~PDITAL;
  zresc(pdrend);
 }
}



void gonormalheightwidth(void)
{
 if(prtype==PEPSON || prtype==PIBM) 
 {
  zresc2('W',0);
  zresc2('w',0);
 }
}


void gonounderline(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc2('-','0');
 else
 if(prtype==PDRIVER)
 {
  pdrend&=~PDUNDER;
  zresc(pdrend);
 }
}



void gobold(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc('E');
 else
 if(prtype==PDRIVER)
 {
  pdrend|=PDBOLD;
  zresc(pdrend);
 }
}



void gonobold(void)
{
 if(prtype==PEPSON || prtype==PIBM) zresc('F');
 else
 if(prtype==PDRIVER)
 {
  pdrend&=~PDBOLD;
  zresc(pdrend);
 }
}



/*****************************************************************************/
/* interface printer to VT code */


void resetprint(void)
{
 gonoitalics();
 gonounderline();
 gonormalheightwidth();
 gonobold();
 if(prtype==PIBM) zresc2('t','1');
 else
 if(prtype==PDRIVER) 
 {
  pdrend=PDZERO;
  zresc(pdrend);
 }
 prendition=0;
}



/*  This homes printer to current rendition  */

void gorendition(int rendition)
{
 int temp; 
 int i;

 temp=prendition ^ rendition;

 for(i=0;i<8;i++)
 {
  if(temp & (1 << i))
  {
   if(prendition & (1 << i))
    switch(i)
    {                                    /* clear things */
     case 0:
            gonobold();
            break;

     case 2:
            gonoitalics();
            break;

     case 3:
            gonounderline();
            break;
    }
    else
     switch(i)
     {                                   /* set things  */

      case 0:
             gobold();
             break;

      case 2:
             goitalics();
             break;

      case 3:
             gounderline();
             break;
     }
  }
 }
 prendition=rendition;
}




void goabsrend(int rendition)
{
 resetprint();
 gorendition(rendition);
}


void setprintlo(int * variable,int value)
{
 *variable=value;
 printinit();
 if(autoprint) goabsrend(rendition);
 vtwriteprint();
}

void setprint(int * variable,int value)
{
 if(printer) setprintlo(variable,value);
}


void vtautoprinton(void)
{
 autoprint=1;
 printinit();
 goabsrend(rendition);
 vtwriteprint();
}

void vtautoprintoff(void)
{
 autoprint=0;
 printinit();
 vtwriteprint();
}


void vtautoprint(int fp)
{
 if(stack[fp]) vtautoprinton();
 else          vtautoprintoff();
}



int  conpoint;
char constring[5];


/* initialise the printer controller */

void printconboot(void) 
{
 int i;
 conpoint=0;
 for(i=0;i<5;i++) constring[i]=0;
}



int cmatch(char * string1,char * string2)
{
 int i;
 i=0;

 do
 {
  if(string1[i]!=string2[i]) return(0);
  i++;
 }
 while(string2[i]);

 return(1);
}



void printcontroller(int byte) 
{ 
 int i;
 char * cons;

 /* vt52 ESC X */
 /* vt100 ESC [ 4 i */

 if(ansimode) cons="\33[4i"; 
 else         cons="\33X";  /* should be 27 */

 constring[conpoint]=byte;

 if(cmatch(cons,constring))
 {
  conpoint++;
  if(cons[conpoint]==0) conoprint=0;
 }
 else 
 {
  for(i=0;i<=conpoint;i++) printprint(constring[i]);
  printconboot();
 }
}



/*****************************************************************************/
/* VT printer commands */


/* prints a given chunk of a given line in the capture buffer */

void printline(int xlo,int xhi,int y)
{ 
 int x;
 int byte;
 int code;
 int mxrend;

 tline * lp;
 int     loc;
 int   * data;
 int     attr;
 int     atrf;
 int     lastnospc;


 lp=vtindex(y);

 attr=lp->attr;

 if(attr==VTADHB) return;

 atrf=attr>0;

 resetprint();

 if(attr==VTADHT)
 {
  godoubleheight();
  godoublewidth();
 }
 else
 if(attr==VTADW)
 {
  godoublewidth();
 }

 xlo=xlo>>atrf;
 xhi=xhi>>atrf;


 lastnospc=xhi;
 for(x=xlo;x<=xhi;x++)
 {
  lp=vtindex(y);
  loc=lp->loc;
  data=(int *)(linedata+loc)+x;

  code=(*data) & 0xFF00;
  byte=(*data) & 0xFF;

  if(byte!=SPC) lastnospc=x;
 }


 for(x=xlo;x<=lastnospc;x++) /* was xhi, strip trailing spaces */
 {
  lp=vtindex(y);
  loc=lp->loc;
  data=(int *)(linedata+loc)+x;

  code=(*data) & 0xFF00;
  byte=(*data) & 0xFF;

  mxrend=0;
  if(code & VTITAL)  mxrend|=4; /* italics */
  if(code & VTUNDER) mxrend|=8; /* underline */
  if(code & VTBOLD)  mxrend|=1; /* bold */

  gorendition(mxrend);
  printprintable(byte);
 }

 prnlf();
 if(autoprint) goabsrend(rendition);
}



void  printcursor(void)
{ 
 printinit();
 printline(0,width-1,ttyy+tops); 
}



void printscreen(void)
{ 
 int y;

 printinit();

 if(printarea) 
   for(y=0;y<24;y++) 
     printline(0,width-1,y+tops);
 else
   for(y=scltop;y<=sclbot;y++)
     printline(0,width-1,y+tops);

 if(printff) printprint(12);
}


void vtdumpscreen(int fp)
{
 fp=0;
 printscreen();
}



void printbuffer(void)
{
 int y;

 printinit();

 for(y=0;y<buffsize;y++) 
   printline(0,width-1,y);
}



void printchunk(int xlo,int ylo,int xhi,int yhi)
{
 int y;
 int lo;
 int hi;

 printinit();

 for(y=ylo;y<=yhi;y++) 
 {
  if(y==ylo) lo=xlo;
  else       lo=0;

  if(y==yhi) hi=xhi;
  else       hi=width-1;

  printline(0,width-1,y);
 }
}



/* This just sends code to printer takes out LF's */

void printprint(int code)
{      
 zrsub(code);
}



static char ansimap[33]="\40\333\40\40\40\40\370\361\40\40\331\277\332\300\305\304\304\304\304\304\303\264\301\302\263\363\362\343\367\234\372\40";

static char vtmap[96]={32,105,155,156,32,157,32,159,32,32,166,174,32,32,32,32,
                       248,241,253,32,32,230,32,250,32,32,167,175,172,171,32,
                       168,133,32,134,132,132,132,146,128,138,130,136,137,141,
                       161,140,139,32,165,149,162,148,148,148,56,237,151,163,
                       150,129,152,32,32,133,160,131,131,132,134,145,135,138,
                       130,136,137,141,161,140,140,32,32,149,162,147,147,148,
                       246,237,151,163,150,129,152,32,129};





/* This sends code to the printer, but
if less than 32, sorts out either ANSI or spec graf.
if greater than 127, decides what to do,
finds pounds sign */



void printprintable(int code)
{
 code=code & 0xFF;

 if(!ansisys && !ttymode && code<32)   /* this is VT spec grafics */
 {
  if(prtype!=PIBM) code=32;
  else             code=ansimap[code];
 }
 else
 if(ansisys && code <32)               /* this is ANSI lo codes */
 {
  code=32;
 }
 else
 if(ansisys && code >127)              /* this is ANSI hi codes */
 {
  if(prtype!=PIBM)
  {
   if(code==156) code=35; 
   else          code=32;
  }
 }
 else
 if(vt220 && code >159)                 /* this is VT220 hi codes */
 { 
  if(prtype!=PIBM)
  {
   if(code==163) code=35; 
   else          code=32;
  }
  else 
   code=vtmap[code-160];
 }
 else
 if(ttymode && code==163)               /* pound sign in non ANSI terminal */
 {
  if(prtype!=PIBM) code=35;
  else             code=156;
 }

 zrsub(code);
}


void prnlf(void)
{
 printprint(13);
 printprint(10);
}


