/*->c.pr  */


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


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

#include "h.Drawlevel0"


#include "h.main"
#include "h.wos"

#include "h.strdef"

#include "h.vx"
#include "h.trans"

#include "h.pr"



/*****************************************************************************/
/* we use units of 1/72000ths of an inch = 1/1000 pt = 2.54/72000 mm */

/* a routine which reads in numbers as in/mm/pt or default */
/* and outputs our units return -1 on error                */


int frommms(int s)
{
 int i;
                                     /* danger of overflow */
 s=s*36;                             /* factors            */
 for(i=0;i<(3+1);i++) s=s*10;
 s=s/127;                            /* give *72/254       */
 return(s);
}


int scang(char * string,int * minus)
{
 int i;
 int s=0;

 *minus=0;

 for(i=0;i<strlen(string);i++)
 {
  switch(string[i])
  {
   case '+':
            break;

   case '0':
   case '1':
   case '2':
   case '3':
   case '4':
   case '5':
   case '6':
   case '7':
   case '8':
   case '9':
            s=s*10+string[i]-'0';
            break;

   case ' ':
            break;

   case '.':
            return(-1);
            break;

   case '-':
            if(*minus) return(-1);
            *minus=1;
            break;

   case 'M':
   case 'm':
            return(frommms(s));

   default :
            return(-1);

  }
 }

 return(frommms(s));
}




/* a routine which can print in/mm/pt's from our units */

void gsprint(char * string,int value,int units)
{
 int    big;
 int    lit;
 char * minus;

 if(value<0)
 {
  minus="-";
  value=-value;
 }
 else
  minus="";

 big=value*127;
 lit=big/360;
 big=big/360000;
 if(lit>=500) big++;

 sprintf(string,"%s%d%s",minus,big,units?"mm":"");
}




/****************************************************************************/
                           /* RISCOS printer code */


#define PDriver_Info          0x80140
#define PDriver_GiveRectangle 0x8014B
#define PDriver_DrawPage      0x8014C
#define PDriver_GetRectangle  0x8014D
#define PDriver_SelectJob     0x80145
#define PDriver_EndJob        0x80148
#define PDriver_AbortJob      0x80149
#define PDriver_PageSize      0x80143




/* variables to do with printing      */

int isprinter=0;
static int printpoll=0;
static int printhg=0;
int inprinter;

/* variables to do with printing stats */

static int pstot;
static int pscur;
static int pspage;
static int pscopy;

static int psflag;




os_error * pdinfo(os_regset * rx)
{
 os_error * ep;
 ep=os_swix(PDriver_Info,rx);
 return(ep);
}


static os_error * selectjob(int handle,char * title,int * oldhandle) 
{
 os_regset rx;
 os_error  * er;

 rx.r[0]=handle;
 rx.r[1]=(int)title;

 er=os_swix(PDriver_SelectJob,&rx);

 if(!er) *oldhandle=rx.r[0];

 return(er);
}


static os_error * giverect(int id,int * coords,int * trans,
                                               int * botleft,int bkcol)
{
 os_regset rx;

 rx.r[0]=id;
 rx.r[1]=(int)coords;
 rx.r[2]=(int)trans;
 rx.r[3]=(int)botleft;
 rx.r[4]=bkcol;
 return(os_swix(PDriver_GiveRectangle,&rx));
}


static os_error * drawpage(int * copies,int * box,int pageseqno,
                                                  char * pagetextno,int * id)
{
 os_regset rx;
 os_error * er;

 rx.r[0]=*copies;
 rx.r[1]=(int)box;
 rx.r[2]=pageseqno;
 rx.r[3]=(int)pagetextno;

 er=os_swix(PDriver_DrawPage,&rx);

 if(!er)
 {
  *id=rx.r[2];
  *copies=rx.r[0];
 }

 return(er);
}


static os_error * getrect(int * copies, int * box, int * id)
{
  os_regset rx;
  os_error  * er;

  rx.r[1]=(int)box;

  er=os_swix(PDriver_GetRectangle,&rx);
  
  if(!er)
  {
   *id=rx.r[2];
   *copies=rx.r[0];
  }
  return(er);
}


static os_error * endjob(int handle)
{
 os_regset rx;
 rx.r[0]=handle;
 return(os_swix(PDriver_EndJob,&rx));
}


static void abortjob(int handle)
{
 os_regset rx;
 rx.r[0]=handle;
 os_swix(PDriver_AbortJob,&rx);
}


/*****************************************************************************/
/* printer dialogue box */


static int printpawss(void)
{
 int pausetime=clock();
 bbc_vdu(7);
 writeicon(whandle[PSTAT],5,transtoken("Continue"));
 if(printhg) hourglassoff();

 do
 {
  psflag=-1;
  while(psflag==-1) poll(0);
 } while(((clock()-pausetime)<100) && !psflag);

 if(printhg) hourglasson();
 writeicon(whandle[PSTAT],5,transtoken("Pause"));
 return(psflag);
 return(1);
}



static int printpaws(pset * ps)
{
 if(ps->pause) return(printpawss());
 return(0);
}


static int updatestatpoll(void)
{
 int i=5;
 printpoll=1;
 psflag=-1;
 while(i--) 
  {
   poll(0);
   if(psflag!=-1) break;
  }

 printpoll=0;
 if(!psflag) return(printpawss());
 else        return(psflag==1);

 return(0);
}


static int updatestat(void)
{
 int temp;
 writeiconf(whandle[PSTAT],1,"%d",pscopy);
 temp=pscur*100;
 temp/=pstot;
 writeiconf(whandle[PSTAT],3,"%d%%",temp);
 return(updatestatpoll());
}



static int setpspage(int page)
{
 pspage=page;
 return(updatestat());
}




static int setpscopy(int copy)
{
 pscopy=copy;
 return(updatestat());
}



static void statkey(int * key)
{
 if(*key==27) psflag=1;
 else
 return;
 *key=-1;
}



void staticon(void)
{
 switch(icon)
 {
  case 4:    /* cancel */
  case 5:    /* pause */
         psflag=(icon==4);
         break;
 }
}



static void closepstat(int ok)
{
 closedownt(PSTAT);
 ok=0;
}



static void openpstat(int totpages,int totcopies)
{
 int  handle;

 pstot=totpages*totcopies;
 pscur=0; 
 pspage=1;
 pscopy=1;

 handle=createwindow(PSTAT);
 if(!handle) return;

 popup(handle,0);

 updatestat(); 
}


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


static int newprinthandle;
static int oldprinthandle;
static int printcancelled;



static void goprinter(przoomfn przf)
{
 isprinter=1;
 przf(PRUNITYZOOM);
 hourglasson();
 printhg=1;
}


static void gonormal(przoomfn przf)
{
 isprinter=0;
 przf(PRLOADZOOM);
 hourglassoff();
 printhg=0;
}


static os_error * printpage(int copies,int invert,pset * ps,
                                           przoomfn przf,predrawfn prdf)   
{
 os_error  * errpoi=NULL;
 int id;
 int bkcol;            /* background colour of page */
 int box[4];           /* rectangle */
 int trans[4];         /* transformation */
 int botleft[2];
 int totcopies=copies;
 int curcopy=copies;
 wimp_redrawstr redrawstr;


 /* set up page  */

 id=0;

 bkcol=0xFFFFFF00;

 botleft[0]=ps->cx;
 botleft[1]=ps->cy;

 if(ps->flags & PORT)
 {
  trans[0]=(0x10000/ps->xdiv)*ps->xmul;
  trans[1]=0;
  trans[2]=0;
  trans[3]=(0x10000/ps->ydiv)*ps->ymul;
 }
 else
 {
  trans[1]=(0x10000/ps->xdiv)*ps->xmul;
  trans[0]=0;
  trans[3]=0;
  trans[2]=-(0x10000/ps->ydiv)*ps->ymul;
  botleft[0]+=((ps->height*400)/ps->ydiv)*ps->ymul;
 }

 box[0]=ps->box0; 
 box[1]=ps->box1; 
 box[2]=ps->box2;   /* nb bosunits don't use vdi scale */
 box[3]=ps->box3; 


 goprinter(przf);
 selectjob(newprinthandle,"",&oldprinthandle);

 if((errpoi=giverect(id,box,trans,botleft,bkcol))!=NULL) return(errpoi);

 if((errpoi=drawpage(&copies,box,0,"",&id))!=NULL) return(errpoi);

 while(copies) 
 {
  redrawstr.g.x0=box[0];
  redrawstr.g.x1=box[2];
  redrawstr.g.y0=box[1];
  redrawstr.g.y1=box[3];

  prdf(invert,&redrawstr);


  if((errpoi=getrect(&copies,box,&id))!=NULL) return(errpoi);

  selectjob(oldprinthandle,"",&oldprinthandle);
  gonormal(przf);

  if(copies!=curcopy)
  {
   pscur+=curcopy-copies;

   if(copies && setpscopy(totcopies-copies+1)) printcancelled=1;
   else
   if(copies && printpaws(ps)) printcancelled=1;
   curcopy=copies;
  }
  else if(updatestatpoll()) printcancelled=1;

  goprinter(przf);
  selectjob(newprinthandle,"",&oldprinthandle);

  if(printcancelled) break;
 }

 selectjob(oldprinthandle,"",&oldprinthandle);
 gonormal(przf);
 return(errpoi);
}



/* on entering this function, the oldprinthandle is active */
/* if we leave with an error, then the newone is active    */

static os_error * printpages(int invert,pset * ps,przoomfn przf,predrawfn prdf)
{
 os_error * errpoi;
 int        pcopies=ps->copies;
 int        nopages=1;

 openpstat(nopages,pcopies);

 while(vx[vxprint].frame>=(ps->from-1))
 {
  if(setpscopy(1)) return(NULL);

  if((errpoi=printpage(pcopies,invert,ps,przf,prdf))!=NULL) return(errpoi);

  vx[vxprint].frame++;

  if(vx[vxprint].frame<ps->to)
  {
   getframe(vxprint);
   ps->box0=0;
   ps->box1=0;
   ps->box2=vx[vxprint].tfwidth;
   ps->box3=vx[vxprint].tfheight;
   ps->height=vx[vxprint].tfheight;
  }
  else  break;
 }

 return(NULL);
}




/* we always have the newprinthandle selected on leaving this function */

static os_error * doprintjob(int invert,pset * ps,przoomfn przf,predrawfn prdf)
{
 os_error * errpoi;

 if((errpoi=selectjob(newprinthandle,"ArcFax",&oldprinthandle))!=NULL)
                                                               return(errpoi);

 selectjob(oldprinthandle,"",&oldprinthandle);
 gonormal(przf);

 if((errpoi=printpages(invert,ps,przf,prdf))!=NULL) return(errpoi);

 goprinter(przf);
 selectjob(newprinthandle,"",&oldprinthandle);
 return(endjob(newprinthandle));
}




/* dump of graphics screen */


void printfile(int invert,pset * ps,przoomfn przf,predrawfn prdf)  
{
 os_error  * errpoi;
 os_regset rx;
 os_error    err;
 int  failed=0;

 if(inprinter) return;

 printcancelled=0;
 przf(PRSAVEZOOM);

 if(pdinfo(&rx))
 {
  errorbox("{PR00}");
  return;
 }

 rx.r[0]=0x80;                         /* open print file */
 rx.r[1]=(int)path(PRIP);
 errpoi=os_find(&rx);
 newprinthandle=rx.r[0];

 if(!newprinthandle)
 {
  errorbox("{PR01}");
  return;
 }

 addzeroevent(PRINTZERO);
 inprinter=1;

 if((errpoi=doprintjob(invert,ps,przf,prdf))!=NULL)
 {
  err=*errpoi;
  failed=1;
  abortjob(newprinthandle);
 }

 rx.r[0]=0;                            /* close print file */
 rx.r[1]=newprinthandle;
 os_find(&rx);

 selectjob(oldprinthandle,"",&oldprinthandle);

 gonormal(przf);

 inprinter=0;
 remzeroevent(PRINTZERO);

 closepstat(0);

 if(failed) report(&err);
}




/****************************************************************************/
                      /* Printer Driver Messages */

/* between them, these three routines can keep track of the printer area */


int rosprintarea=0;  /* is there a print area set up */
static int leftarea;
static int rightarea;
static int toparea;
static int botarea;



int printareawidth(void)
{
 if(rosprintarea) return((rightarea-leftarea)/400);
 else             return(0);
}



void calcprintarea(pset * ps,int * left,int * right,int * top,int * bot)
{
 int xleft=leftarea;      /* do transform on these vars */
 int xright=rightarea;
 int xtop=toparea;
 int xbot=botarea;
 int temp1;
 int temp2;


 xleft-=ps->cx;
 xright-=ps->cx;
 xtop-=ps->cy;
 xbot-=ps->cy;


 if(!(ps->flags & PORT)) 
 {
  temp1=xleft;
  xleft=xbot;
  xtop=temp1;

  temp2=xright;
  xright=xtop;
  xbot=temp2;
 }



 if(ps->xmul!=ps->xdiv)
 {
  xleft=xleft*ps->xdiv;
  xleft=xleft/ps->xmul;
  xright=xright*ps->xdiv;
  xright=xright/ps->xmul;
 }


 if(ps->ymul!=ps->ydiv)
 {
  xtop=xtop*ps->ydiv;
  xtop=xtop/ps->ymul;
  xbot=xbot*ps->ydiv;
  xbot=xbot/ps->ymul;
 }



 if(!(ps->flags & PORT)) 
 {
  xbot=ps->height-xbot;
  xtop=ps->height-xtop;
 }


 if(xleft<0) xleft=0;
 if(xbot<0)  xbot=0;
 if(ps->width<xright) xright=ps->width;
 if(ps->height<xtop)  xtop=ps->height;

 *left=xleft;
 *right=xright;
 *top=xtop;
 *bot=xbot;
}



static void getpagesize(void)
{
 os_regset  rx;
 os_error * ep;
 int changed=0;

 if(pdinfo(&rx))
 {
  if(rosprintarea)
  {
   rosprintarea=0;
   changed=1;
  }
 }
 else
 {
  ep=os_swix(PDriver_PageSize,&rx);
  if(ep)
  {
   if(rosprintarea)
   {
    rosprintarea=0;
    changed=1;
   }
  }
  else
  {
   if(!rosprintarea)
   {
    rosprintarea=1;
    changed=1;
   }

   if(leftarea!=rx.r[3])
   {
    leftarea=rx.r[3];
    changed=1;
   }

   if(rightarea!=rx.r[5])
   {
    rightarea=rx.r[5];
    changed=1;
   }

   if(toparea!=rx.r[6])
   {
    toparea=rx.r[6];
    changed=1;
   }

   if(botarea!=rx.r[4])
   {
    botarea=rx.r[4];
    changed=1;
   } 
  }
 }

/* if(changed)  tekprupdate(); */
}


/* called when printer configuration has changed */

void setprinterdriver(void)
{
 getpagesize();
}



/* called when printer driver starts up */

void printinitdriver(void)
{
 getpagesize();
}



/* called on program start up */

void rosprintinit(void)        
{
 getpagesize();
}


