/*->c.rxfax */


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

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


#include "h.DrawLevel0"


#include "h.wos"
#include "h.mym"
#include "h.ram"
#include "h.strdef"
#include "h.file"
#include "h.tiff"
#include "h.fsx"
#include "h.xext"
#include "h.def"
#include "h.fax"
#include "h.view"
#include "h.dir"
#include "h.batch"
#include "h.buffer"
#include "h.config"
#include "h.serial"
#include "h.code"
#include "h.vx"
#include "h.dbug"
#include "h.main"
#include "h.state"

#include "h.con"

#include "h.rxfax"



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

#define RXBUFFSIZE 0x10000


typedef struct
{
 int pn;
 int xpx;
 int ypx;
 int xres;
 int yres;
 int len;
 int comp;
 int fp;
} pagestr;


#define RXIDLEN 32

static char    rxname[256];
static int     rxfh;
static buffer  rxbuff;
static int     rxpages;
static pagestr page[32];
static char    rxid[RXIDLEN];
static int     rxpagewidth;
static int     rxpagelength;
static int     rxresln;
static int     rxxres;
static int     rxyres;
static int     rxmaxwidth;
static int     rxmaxlength;

static int     rxbitrate;
static int     rxscantime;

static int     rxdatacompression;
static int     rxerrorcorrection;
static int     rxbinaryftp;
static int     rxpagelengthcode;

static int     rxerror;


void faxrxscan(int fp)
{
 rxbitrate =stack[fp+0];
 rxscantime=stack[fp+1];
}


/* faxrxparams(rxpagelength,rxdatacompression,rxerrorcorrection,rxbinaryftp);*/

void faxrxparams(int fp)
{
 rxpagelengthcode=stack[fp+0];
 rxdatacompression=stack[fp+1];
 rxerrorcorrection=stack[fp+2];
 rxbinaryftp=stack[fp+3];
}




/* called to open a new document */
/* return 0 if OK                */

int faxrxopendocument(int fp)
{
 os_error * ep;

 genbatchname(RXBFILE,rxname,TIFF);

 rxpages=0;
 rxmaxwidth=0;
 rxmaxlength=0;

         ep=fs_open(rxname,'w',&rxfh);
 if(!ep) ep=tiff_hdr(rxfh);

 conaction("{CON04}");
 confax(leaf(rxname));

 return(0);
 fp=fp;
}



/* called to close a document        */
/* return 0 if OK                    */
/* int faxrxclosedocument(int docok) */

int faxrxclosedocument(int fp)
{
 os_error * ep;
 int        i;
 int        docok;
 int        bn;

 docok=stack[fp];

 ep=NULL;

 conaction("{CON05}");
 conclrfax();

 for(i=0;i<rxpages;i++)
 {
  ep=fs_seek(rxfh,page[i].fp);
  if(ep) break;
  ep=faxifd(rxfh,page[i].xpx,page[i].ypx,page[i].xres,page[i].yres,
                 page[i].len,page[i].comp,page[i].pn,rxpages);


/*  dprintf(5,"pn=%d rxp=%d",page[i].pn,rxpages); */

 }

 ep=fs_close(rxfh,ep);

 setftype(rxname,TIFF);

 if(!docok || !batdiscard)
 {
  bn=addtorxbatch(TIFF,rxname,0,0)-1;
  strcpy(vtable[RXBFILE][bn].ident,rxid);

  vtable[RXBFILE][bn].tsum.xres=rxxres;
  vtable[RXBFILE][bn].tsum.yres=rxyres;
  vtable[RXBFILE][bn].tsum.maxwidth=rxmaxwidth;
  vtable[RXBFILE][bn].tsum.maxlines=rxmaxlength;
  vtable[RXBFILE][bn].tsum.npages=rxpages;

  vtable[RXBFILE][bn].autoprint=vxautoprint;
  vtable[RXBFILE][bn].autoforward=batforward;

  writetolog("{LOG11} %s {LOG14}\n",leaf(rxname));

  addzeroevent(RXFAXZERO);
 }
 else
 {
  fs_delete(rxname);
  writetolog("{LOG15}\n");
 }

 consent(!docok);

 return(0);
}



static int escape;
static int serialeof;
static int rxbitrev=0;
static int nodle=0;
static int putback;
static int putbackcode;
static int doubledle=0;

static int dlesub;
       int noeopdle;


void setrxbor(int fp)
{
 rxbitrev=stack[fp];
}

void setdlemode(int fp)
{
 nodle=stack[fp] & 0x1;
 dlesub=stack[fp] & 0x2;
 noeopdle=stack[fp] & 0x4;
}

void faxrxclear(void)
{
 nodle=0;
 noeopdle=0;
 dlesub=0;
 rxbitrev=0;
}


static os_error * sr_get(buffer * b,int * c)
{
 int code;

 if(serialeof)
 {
  *c=EOF;
  return(NULL);
 }

 while(1)
 {
  if(putback) 
  {
   code=putbackcode;
   putback=0;
  }
  else code=getbytet(1000);

  if(escape)
  {
   escape=0;

   if(nodle)
   {
    if(code==ETX)
    {
     if(!doubledle)
     {
      serialeof=1;
      *c=EOF;
      return(NULL);
     }
     else
     {
      if(rxbitrev) *c=bitrev[ETX];
      else         *c=ETX;
      doubledle=0;
     }
    }
    else
    if(doubledle)
    {
     if(rxbitrev) *c=bitrev[DLE];
     else         *c=DLE;
     doubledle=0;
     putback=1;
     putbackcode=code;
     return(NULL);
    }
    else
    if(code==DLE)
    {
     if(rxbitrev) *c=bitrev[DLE];
     else         *c=DLE;
     escape=doubledle=1;
     return(NULL);
    }
    else
    {
     if(rxbitrev) *c=bitrev[DLE];
     else         *c=DLE;
     doubledle=0;
     putback=1;
     putbackcode=code;
     return(NULL);
    }
   }
   else
   {
    if(code==ETX) /* normal end */
    {
     serialeof=1;
     *c=EOF;
     return(NULL);
    }
    else
    if(code==DLE) /* write a DLE */
    {
     if(rxbitrev) *c=bitrev[DLE];
     else         *c=DLE;
     return(NULL);
    }
    else
    {
     if(dlesub)
     {
      if(code==SUB)
      {
       if(rxbitrev) *c=bitrev[DLE];
       else         *c=DLE;

       putback=1;
       putbackcode=DLE;
      }
     }
     else
     {
      /* chuck it */
     }
    }
   }
  }
  else
  if(code==DLE) escape=1;
  else
  if(code<0)
  {
   serialeof=1;
   *c=EOF;
   return(NULL);
  }
  else
  {
   if(rxbitrev) *c=bitrev[code];
   else         *c=code;
   return(NULL);
  }
 }
 b=b;
}





static codestr cxin;
static codestr cxout;



static os_error * decodepage(int * goodlines,int * badlines)
{
 os_error * ep;
 int        good;
 int        bad;
 int        eof;

 ep=NULL;
 escape=0;
 putback=0;
 doubledle=0;
 serialeof=0;
 good=0;
 bad=0;

 cxin.width=rxpagewidth;
 cxin.height=rxpagelength;
 cxin.bitrev=0;
 cxin.getbyte=sr_get;
 cxin.bf=NULL;

 if(rxdatacompression) cxin.type=FAXCCITT4;
 else                  cxin.type=FAXCCITT3;

 cxin.newbuffer=1;

 cxout.width=cxin.width;
 cxout.height=cxin.height;
 cxout.bitrev=0;
 cxout.putbyte=bf_put;
 cxout.bf=&rxbuff;

 if(datacompression) cxout.type=TIFFCCITT4;
 else                cxout.type=FAXCCITT3;

 cxout.newbuffer=0;

         ep=codeinit(&cxout);
 if(!ep) ep=decodeinit(&cxin);

 if(!ep)
 {
  setdbdataphase(1,1);

  while(1)
  {
   ep=cxin.getline(&cxin,&eof);
   if(eof) break;

   if(cxin.good) good++;
   else          bad++;

   cxout.run=cxin.run;
   cxout.runs=cxin.runs;

   cxout.putline(&cxout,0,1);
  }

  setdbdataphase(0,1);

  ep=cxout.puteop(&cxout);

  decodefinit(&cxin);
  codefinit(&cxout);
 }

 *goodlines=good;
 *badlines=bad;
 rxpagelength=good+bad;

 return(ep);
}





/* function called if someone hits Cancel button */

static void rxcancel(void)
{
 rxerror=1;
}




/* called to rx page data */
/* int faxrxpage(page,rxpagewidth,rxresln); */
/* return 0 if OK             */
/*        1 if local error    */
/*        2 if data error     */

int faxrxpage(int fp)
{
 os_error * ep;
 int        ifdfp;
 int        datafp;
 int        edatafp;
 int        goodlines;
 int        badlines;
 int        pgn;


 pgn=stack[fp];
 rxpagewidth=stack[fp+1];
 rxpagewidth=faxt3widthtable[rxpagewidth];
 rxresln=stack[fp+2];
 rxpagelength=22219;
 rxerror=0;

 conaction("{CON07}");
 conpage(pgn+1,-1);
 conparam(rxbitrate,rxresln,rxdatacompression);

 setfaxcancelhandler(rxcancel);

 if(pgn<rxpages)
 {                 /* repeating a page */
  ep=fs_seek(rxfh,page[pgn].fp);
 }
 else
 {
  rxpages++;
 }

 page[pgn].xpx=rxpagewidth;
 page[pgn].ypx=rxpagelength;

 page[pgn].comp=datacompression?TIFFCCITT4:FAXCCITT3;

 ep=fs_tell(rxfh,&ifdfp);

 page[pgn].fp=ifdfp;
 page[pgn].pn=rxpages;
 page[pgn].len=0;

 if(rxresln)
 {
  rxxres=page[pgn].xres=XRES;
  rxyres=page[pgn].yres=YRESHI;
 }
 else
 {
  rxxres=page[pgn].xres=XRES;
  rxyres=page[pgn].yres=YRESLO;
 }

 if(!ep) ep=faxifd(rxfh,page[pgn].xpx,page[pgn].ypx,page[pgn].xres,
          page[pgn].yres,page[pgn].len,page[pgn].comp,page[pgn].pn,rxpages);

 if(!ep) ep=fs_tell(rxfh,&datafp);

 if(!ep) ep=bf_alloc(&rxbuff,RXBUFFSIZE,rxfh,0);
 if(!ep)
 {

 /* dprintf(0,"faxrxpage w=%d l=%d res=%d",rxpagewidth,rxpagelength,rxresln);*/

  ep=decodepage(&goodlines,&badlines);
  page[pgn].ypx=rxpagelength;
  if(rxpagewidth>rxmaxwidth)   rxmaxwidth=rxpagewidth;
  if(rxpagelength>rxmaxlength) rxmaxlength=rxpagelength;

 /* dprintf(2,"good=%d bad=%d",goodlines,badlines); */

  if(!ep) ep=bf_dump(&rxbuff);
  if(!ep) ep=bf_dealloc(&rxbuff);
  else       bf_dealloc(&rxbuff);
 }

 if(!ep) ep=fs_tell(rxfh,&edatafp);
 if(!ep) ep=fs_seek(rxfh,ifdfp);
 page[pgn].len=edatafp-datafp;
 if(!ep) ep=faxifd(rxfh,page[pgn].xpx,page[pgn].ypx,page[pgn].xres,
          page[pgn].yres,page[pgn].len,page[pgn].comp,page[pgn].pn,rxpages);

 clearfaxcancelhandler();

 if(!ep && !rxerror)
 {
  ep=fs_seek(rxfh,edatafp);

  if(!(goodlines+badlines))                           return(1);
  else
  if(((badlines*100)/(goodlines+badlines))>faxerrors) return(1);
  else                                                return(0);
 }
 else return(2);
}


void xfaxrxid(char * string)
{
 strcpy(rxid,string);
 writetolog("{LOG16}%s\n",rxid);
 conid(rxid);
}


void faxrxid(int fp)
{
 char string[RXIDLEN];
 strncpy(string,stringptr(stack[fp]),RXIDLEN-1);
 string[RXIDLEN-1]=0;
 xfaxrxid(string);
}

