/*->c.text */

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

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

#include "h.Drawlevel0"


#include "h.def"
#include "h.wos"
#include "h.main"
#include "h.strdef"
#include "h.mym"
#include "h.serial"
#include "h.ram"
#include "h.file"
#include "h.pr"
#include "h.key"
#include "h.script"
#include "h.dir"
#include "h.batch"
#include "h.fsx"
#include "h.timex"
#include "h.fax"
#include "h.view"
#include "h.tiff"
#include "h.buffer"
#include "h.code"
#include "h.config"
#include "h.fo"
#include "h.swis"
#include "h.pic"
#include "h.link"

#include "h.text"


#define PAGEWIDTH   ((256*180*210*10)/254)
#define PAGEHEIGHT  ((256*180*297*10)/254)

#define LEFTMARGIN  ((256*180*6*10)/254)
#define BOTMARGIN   ((256*180*6*10)/254)

#define XLEFTMARGIN  ((256*180*4*10)/254)
#define XBOTMARGIN   ((256*180*4*10)/254)


#define DCHUNK      0x1000




static void doopen(Draw_diag * diag,int xsize,int ysize)
{
 int * buffp=(int*)diag->data;
 int * buff=buffp;

 strcpy((char*)buffp,"Draw");
 buffp++;
 *buffp++=201;
 *buffp++=0;

 strcpy((char*)buffp,"ArcFax      ");
 buffp+=3;

 *buffp++=0;
 *buffp++=0;
 *buffp++=xsize;
 *buffp++=ysize;

 diag->length=(buffp-buff)*sizeof(int);
}



/* trash diag contents */

void cleardiag(Draw_diag * diag)
{
 if(diag->data) flex_free((flex_ptr)&(diag->data));
 diag->length=0;
}



/* create a diag */

static os_error * opendiag(Draw_diag * diag,int xsize,int ysize)
{
 os_error * ep;

 if(diag->data) ep=flex_chunke((flex_ptr)&(diag->data),0,DCHUNK);
 else           ep=flex_alloce((flex_ptr)&(diag->data),DCHUNK);

 if(!ep)
 {
  diag->length=0;
  doopen(diag,xsize,ysize);
 }

 return(ep);
}



static int drawsavediag(Draw_diag * diag,char * filename)
{ 
 FILE * fp;
 int    realfile;

 fp=ropen(filename,"wb");
 if(!fp) return(0);

 if(diag->data && diag->length>0)
                   rwrite(diag->data,1,diag->length,fp);

 realfile=!ramfp(fp);

 rclose(fp);
 if(realfile) setftype(filename,DRAW);

 return(1);
}






static int textoff;
static int textlen;



os_error * writetotextcolumnc(Draw_diag * diag,int c)
{
 char     * buff;
 os_error * ep;

 ep=NULL;

 if((diag->length & 3)==0)
 {
  ep=flex_chunke((flex_ptr)&(diag->data),diag->length+4,DCHUNK);
 }

 buff=diag->data+diag->length;
 *buff=c;
 diag->length++;
 textlen++;

 return(ep);
}







os_error * writetotextcolumn(Draw_diag * diag,char * string)
{
 char     * buff;
 os_error * ep;
 int        len;
 int        xlen;

 len=strlen(string);
 xlen=(len+3) & (~3);

 ep=flex_chunke((flex_ptr)&(diag->data),diag->length+xlen,DCHUNK);

 buff=diag->data+diag->length;
 memcpy(buff,string,len);
 diag->length+=len;
 textlen+=len;

 return(ep);
}



os_error * writetotextcolumnf(Draw_diag * diag,char * format, ...)
{
 os_error * ep;
 va_list args;
 char v[128];
 va_start(args, format);
 vsprintf(v, format, args);
 ep=writetotextcolumn(diag,v);
 va_end(args);
 return(ep);
}



os_error * starttextcolumn(Draw_diag * diag,int x0,int y0,int x1,int y1)
{
 os_error * ep;
 int      * buffp;
 int      * buff;

 ep=flex_chunke((flex_ptr)&(diag->data),diag->length+68,DCHUNK);

 buff=buffp=(int*)(diag->data+diag->length);


 textoff=diag->length;
 *buffp++=9;
 *buffp++=0;
 *buffp++=x0;
 *buffp++=y0;
 *buffp++=x1;
 *buffp++=y1;


 *buffp++=10;         /* a single column */
 *buffp++=24;
 *buffp++=x0;
 *buffp++=y0;
 *buffp++=x1;
 *buffp++=y1;


 *buffp++=0;          /* end of columns */
 *buffp++=0;
 *buffp++=0;
 *buffp++=0;          /* black */
 *buffp++=0xFFFFFF00; /* white */


 textlen=(buffp-buff)*sizeof(int);
 diag->length+=textlen;

 writetotextcolumn(diag,"\\!1\n");

 return(ep);
}



os_error * endtextcolumn(Draw_diag * diag)
{
 os_error * ep;
 int      * buffp;
 char     * p;
 int        extra;

 ep=NULL;

 buffp=(int*)(diag->data+textoff);
 p=(char*)(diag->data+diag->length);
 *p++=0;
 textlen++;
 diag->length++;

 extra=(4-(textlen & 3)) & 3;
 memset(p,0,extra);

 textlen+=extra;
 diag->length+=extra;

 *(buffp+1)=textlen;

 return(ep);
}




os_error * starttextpage(Draw_diag * diag,int portrait,int linespp)
{
 os_error * ep;
 int        height;

 fontinit();

 if(portrait)
 {
  ep=opendiag(diag,PAGEWIDTH,PAGEHEIGHT);
  starttextcolumn(diag,LEFTMARGIN,BOTMARGIN,PAGEWIDTH-LEFTMARGIN,
                                            PAGEHEIGHT-BOTMARGIN);

  height=PAGEHEIGHT;  /* in Draw */
 }
 else
 {
  ep=opendiag(diag,PAGEHEIGHT,PAGEWIDTH);
  starttextcolumn(diag,XLEFTMARGIN,XBOTMARGIN,PAGEHEIGHT/2-XLEFTMARGIN,
                                              PAGEWIDTH-XLEFTMARGIN);

  height=PAGEWIDTH;  /* in Draw */
 }

 height=(height*72)/(256*180);   /* in pts  */
 height/=linespp;

 writefontvariations(textfontname,diag,height);
 writetotextcolumn(diag,"\\0/");
 writetotextcolumnf(diag,"\\L%d\n",height);
 writetotextcolumnf(diag,"\\P%d\n",height);

 return(ep);
}


os_error * startcolumn2(Draw_diag * diag,int linespp)
{
 os_error * ep;
 int        height;

 ep=starttextcolumn(diag,PAGEHEIGHT/2+XLEFTMARGIN,XBOTMARGIN,
                         PAGEHEIGHT-XLEFTMARGIN,PAGEWIDTH-XLEFTMARGIN);

 height=PAGEWIDTH;  /* in Draw */

 height=(height*72)/(256*180);   /* in pts  */
 height/=linespp;

 writefontvariations(textfontname,diag,height);
 writetotextcolumn(diag,"\\0/");
 writetotextcolumnf(diag,"\\L%d\n",height);
 writetotextcolumnf(diag,"\\P%d\n",height);

 return(ep);
}




static void flushcache(void)
{
 os_regset rx;

 os_swix(ColourTrans_InvalidateCache,&rx);

}




#define DRAWWORDS 16





os_error * rasterize(int xres,int yres,int maxwidth,int portrait,
                     buffer * dest,Draw_diag * diag,codestr * cx)
{
 os_error      * ep;
 int             xpix;
 int             ypix;
 Draw_diag       spdiag;
 os_regset       rx;
 char          * buff;
 sprite_header * spa;
 char          * spimage;
 int             spbitwidth;
 int             spbytewidth;
 int             spdx;
 int             spdy;
 int             spmode;
 wimp_box        tbox;
 wimp_redrawstr  redrawstr;
 int             x;
 int             y;
 char          * p;
 int           * ip;
 int             black;
 int             run;
 int             mask;
 int             width;
 unsigned int    code;
 int             blanklines;
 int             pendnewline;


 /* int t1,t2,t3; */

 blanklines=0;


 xres=(256*180)/xres;
 yres=(256*180)/yres;


 if(portrait)
 {
  xpix=PAGEWIDTH/xres;
  ypix=PAGEHEIGHT/yres;
 }
 else
 {
  ypix=PAGEWIDTH/xres;
  xpix=PAGEHEIGHT/yres;
 }

 spdiag.length=0;
 spdiag.data=NULL;

 spmode=(yres==YRESHI?YRESLO:0);

 ep=createsprite(&spdiag,spmode,xpix,ypix);
 if(!ep)
 {
  buff=spdiag.data;

  getdeltas(spmode,&spdx,&spdy);

  spa=(sprite_header *)(buff+DRAWWORDS*4);
  spimage=(buff+DRAWWORDS*4)+spa->image;
  spbitwidth=spa->width*32+spa->rbit;
  spbytewidth=(spa->width+1)*4;


  rx.r[0]=60|512;
  rx.r[1]=(int)spa;
  rx.r[2]=(int)spa;
  rx.r[3]=0;

  ep=os_swix(OS_SpriteOp,&rx);  /* output to sprite */
  if(!ep)
  {
   flushcache();
   vdumodevars();

   tbox.x0=0;
   tbox.y1=0;
   tbox.x1=spdx*spbitwidth;
   tbox.y0=ypix*spdy;

   redrawstr.box.x0=0;                   /* size of box to put pic in */
   redrawstr.box.x1=spdx*spbitwidth;
   redrawstr.box.y0=0;
   redrawstr.box.y1=ypix*spdy;

   redrawstr.scx=0;
   redrawstr.scy=0;

   redrawstr.g.x0=0;                     /* size of clip window */
   redrawstr.g.x1=spdx*spbitwidth;
   redrawstr.g.y0=0;
   redrawstr.g.y1=ypix*spdy;

/*   t1=clock(); */

   picrend(&tbox,*diag,&redrawstr);

/*   t2=clock(); */


   if(portrait)
   {
    for(y=0;y<ypix;y++)
    {
     pendnewline=1;
     mask=0;
     code=0;    /* compiler */
     width=0;
     run=0;
     black=0;

     ip=(int*)(spimage+y*spbytewidth);

     for(x=0;x<spbitwidth;x++)
     {
      if(mask==0)
      {
       code=*ip++;
       if(!code && !black)
       {
        run+=32;
        x+=32;
        continue;
       }
       mask=1;
      }

      if(code & mask)
      {
       if(black) run++;
       else
       {
        if(pendnewline) 
        {
         writeblanks(&blanklines,maxwidth,dest,cx);
         newline(dest,maxwidth);
         pendnewline=0;
        }

        cx->runs[cx->run++]=run;
        width+=run;
        run=1;
        black=1;
       }
      }
      else
      {
       if(!black) run++;
       else
       {
        if(pendnewline) 
        {
         writeblanks(&blanklines,maxwidth,dest,cx);
         newline(dest,maxwidth);
         pendnewline=0;
        }

        cx->runs[cx->run++]=run;
        width+=run;
        run=1;
        black=0;
       }
      }

      mask=mask<<1;
     }

     if(x>spbitwidth)
     {
      run-=(x-spbitwidth);
     }

     if(width==0) blanklines++;
     else
     {
      if(pendnewline) 
      {
       writeblanks(&blanklines,maxwidth,dest,cx);
       newline(dest,maxwidth);
       pendnewline=0;
      }

      if(black)
      {
       cx->runs[cx->run++]=run;
       width+=run;
       run=0;
      }

      cx->runs[cx->run++]=maxwidth-width;
      endline(dest);
     }
    }
   }
   else
   {
    for(x=spbitwidth-1;x>=0;x--)
    {
     pendnewline=1;
     width=0;
     run=0;
     black=0;

     p=spimage+(x>>3);
     mask=1<<(x & 7);

     for(y=0;y<ypix;y++)
     {
      if(*p & mask)
      {
       if(black) run++;
       else
       {
        if(pendnewline) 
        {
         writeblanks(&blanklines,maxwidth,dest,cx);
         newline(dest,maxwidth);
         pendnewline=0;
        }

        cx->runs[cx->run++]=run;
        width+=run;
        run=1;
        black=1;
       }
      }
      else
      {
       if(!black) run++;
       else
       {
        if(pendnewline) 
        {
         writeblanks(&blanklines,maxwidth,dest,cx);
         newline(dest,maxwidth);
         pendnewline=0;
        }

        cx->runs[cx->run++]=run;
        width+=run;
        run=1;
        black=0;
       }
      }
      p+=spbytewidth;
     }

     if(width==0) blanklines++;
     else
     {
      if(pendnewline) 
      {
       writeblanks(&blanklines,maxwidth,dest,cx);
       newline(dest,maxwidth);
       pendnewline=0;
      }

      if(black)
      {
       cx->runs[cx->run++]=run;
       width+=run;
       run=0;
      }
     }

     cx->runs[cx->run++]=maxwidth-width;
     endline(dest);
    }
   }

   if(blanklines) 
   {
    if(blanklines>8) blanklines=8;
    writeblanks(&blanklines,maxwidth,dest,cx);
   }

   if(!ep) ep=os_swix(OS_SpriteOp,&rx);  /* switch back to previous values */
   else       os_swix(OS_SpriteOp,&rx);

   flushcache();
   vdumodevars();
  }

 /* t3=clock(); */

 /* dprintf(0,"t1=%d t2=%d",t2-t1,t3-t2);  */

  flex_free((flex_ptr)&spdiag.data);
 }
 return(ep);
}


