/*->c.log */

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

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

#include "h.Drawlevel0"


#include "h.def"
#include "h.wos"
#include "h.main"
#include "h.mym"
#include "h.serial"
#include "h.ram"
#include "h.file"
#include "h.pr"
#include "h.strdef"
#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.etc"
#include "h.xext"
#include "h.trans"
#include "h.con"
#include "h.band"

#include "h.code"

#include "h.text"
#include "h.config"


#include "h.log"



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


static os_error * getstring(buffer * bf,char * string,int maxlen,int * eof)
{
 os_error * err;
 char     * p;
 int        c;

 err=NULL;
 p=string;
 *eof=0;

 while(maxlen)
 {
  err=bf_get(bf,&c);
  if(err) break;
  if(!c || c=='\r' || c=='\n') break;
  if(c==EOF)
  {
   *eof=1;
   break;
  }

  *p++=c;
  maxlen--;
 }

 *p=0;

 return(err);
}



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

#define TLEN 32


#define STBLANK 0
#define STPART  1


#define TFAIL   0
#define TSENT   1
#define TRECV   2



static char * typestring[]=
{
 "Fail",
 "Sent",
 "Recv",
};



typedef struct tokstate
{
 char time[TLEN];
 char filename[12];
 char duration[8];
 char id[20];
 char number[NUMLEN];
 char cost[8];
 char fail[16];

 int  state:1;
 int  type:2;
 int  dir:1;
} tokstate;



typedef struct tokstr
{
 char otok[6];
 int  bits;
 char ntok[32];
 int  len;
} tokstr;



#define START     1
#define END       2
#define DURATION  4
#define FAIL      8
#define NAME      16
#define ID        32
#define SUCCESS   64
#define INTER     128
#define TAIL      256
#define XTX       512
#define XRX       1024
#define COST      2048
#define XFSR      4096


#define MAXTOK 19


static tokstr tokens[MAXTOK]=
{
 "LOG00",START|NAME|XRX,"",0,     /* Receive fax             */
 "LOG01",END|DURATION|COST,"",0,  /* Finished receiving fax  */

 "LOG02",START|NAME|XTX,"",0,     /* Send fax                */
 "LOG03",FAIL,"",0,           /* Failed to send document */
 "LOG04",FAIL,"",0,           /* Failed to connect       */
 "LOG05",END|DURATION|COST,"",0,   /* Finished sending fax    */

 "LOG06",START|NAME|XRX,"",0,     /* Answering incoming call */
 "LOG07",END|DURATION|COST,"",0,   /* Incoming call over      */

 "LOG08",START|NAME|XTX,"",0,     /* Dialled              */
 "LOG09",FAIL,"",0,           /* Failed to connect to */
 "LOG10",FAIL,"",0,           /* Failed to dial       */
 "LOG17",END|DURATION|COST,"",0,   /* Outgoing call over   */

 "LOG11",INTER,"",0,          /* Fax */
 "LOG12",TAIL|SUCCESS|XTX,"",0,   /* sent */
 "LOG13",ID,"",0,             /* Receiving fax id: */
 "LOG14",TAIL|SUCCESS|XRX,"",0,   /* received */
 "LOG15",FAIL,"",0,           /* Incomplete fax discarded */
 "LOG16",ID,"",0,             /* Sending fax id: */

 "LOG18",XFSR,"",0,           /* Reason: */
};



static void zerotoken(tokstate * state)
{
 memset(state,0,sizeof(tokstate));
 state->state=STBLANK;
 state->type=TFAIL;
}


typedef os_error * (*procfn)(tokstate * state);


static char * nexttoken(char * p,int * len)
{
 int ch;
 int n;

 while((ch=*p)!=0)
 {
  if(!ch || ch!=' ') break;
  else               p++;
 }

 if(!ch) return(NULL);

 n=0;
 while((ch=*p)!=0)
 {
  if(ch==' ') break;
  else        p++;
  n++;
 }

 *len=n;

 return(p);
}


static char * nospc(char * p)
{
 int ch;

 while((ch=*p)!=0)
 {
  if(!ch || ch!=' ') break;
  else               p++;
 }

 if(!ch) return(NULL);
 return(p);
}



static tokstr * tokenptr(char * p)
{
 int i;

 for(i=0;i<MAXTOK;i++)
 {
  if(!strncmp(tokens[i].ntok,p,tokens[i].len)) break;
 }

 if(i<MAXTOK) return(tokens+i);
 else         return(NULL);
}



static void processtoken(char * tok,tokstate * state,procfn pf)
{
 int        bits;
 tokstr   * tokenp;
 char     * start;
 char     * p;
 char     * temp;
 int        len;
 int        ch;

 /* strip off time */

 start=tok;

 tok=strstr(start," : ");
 if(tok)
 {
  *tok=0;
  tok+=3;


  tokenp=tokenptr(tok);

  if(tokenp)
  {
   bits=tokenp->bits;

   if(bits & START)
   {
    if(state->state==STPART)
    {
     if(pf) pf(state);
     zerotoken(state);
    }
    tok+=tokenp->len;
    if(bits & NAME)
    {  /* try to read name/number */
     p=nospc(tok);
     if(p)
     {
      strcpy(state->number,p);
     }
    }
    if(bits & XTX) state->dir=1;

    state->state=STPART;
    strcpy(state->time,start);
   }
   else
   if(bits & END)
   {
    if(state->state==STPART)
    {
     tok+=tokenp->len;
     if(bits & DURATION)
     {
      tok=nospc(tok);
      if(tok)
      {
       p=nexttoken(tok,&len);
       if(p && len)
       {
        ch=*p;
        *p=0;
        strcpy(state->duration,tok);
        tok=p;
        *p=ch;
       }
      }
     }

     if(bits & COST)
     {
      tok=nospc(tok);
      if(tok)
      {
       p=nexttoken(tok,&len);
       if(p && len)
       {
        *p++=0;
        strcpy(state->cost,tok);
       }
      }
     }

     if(pf) pf(state);
     zerotoken(state);
    }
   }
   else
   if(bits & FAIL)
   {
    if(state->state==STPART)
    {
     state->type=TFAIL;
    }
   }
   else
   if(bits & ID)
   {
    if(state->state==STPART)
    {
     tok+=tokenp->len;
     stripid(tok,state->id);

     if(!state->number[0])
     {
      temp=idtoname(state->id);
      if(temp) strcpy(state->number,temp);
     }
    }
   }
   else
   if(bits & XFSR)
   {
    if(state->state==STPART)
    {
     tok+=tokenp->len;
     strncpy(state->fail,tok,16);
     state->fail[15]=0;
    }
   }
   else
   if(bits & INTER)
   {
    if(state->state==STPART)
    {
     tok+=tokenp->len;
     tok=nospc(tok);
     if(tok)
     {
      p=nexttoken(tok,&len);
      if(p && len)
      {
       *p++=0;
       strcpy(state->filename,tok);

       tok=p;

       tokenp=tokenptr(tok);
       bits=tokenp->bits;

       if(bits & XRX) state->type=TRECV;
       if(bits & XTX) state->type=TSENT;
      }
     }
    }
   }
  }
 }
}


static void tokinit(void)
{
 int i;

 for(i=0;i<MAXTOK;i++)
 {
  strcpy(tokens[i].ntok,transtoken(tokens[i].otok));
  tokens[i].len=strlen(tokens[i].ntok);
 }
}




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

                        /* step between each macro entry in window */
#define TDIRDY   40
                        /* step between top of window and first macro */
#define TDIRFY   12
                        /* height of macro definitions */
#define TDIRHY   32
                        /* x step between entries */
#define TDIRDX   8
#define TDIRPX   8


#define TIMEX    8

#define TFNAME   TLEN
#define TTYPE    (12+1)
#define TDUR     5
#define TCOST    6
#define TID      8
#define TNUM     21
#define TFSR     NUMLEN
#define TLAST    16

#define TMAXWIDTH (TFNAME+TTYPE+TDUR+TCOST+TID+TNUM+TFSR+TLAST)


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

#define LOGSCHUNK 0x1000

#define LBUFFSIZE 0x1000


static int         logn;       /* number of log entries */
static tokstate  * logs;



static void logextent(void)
{
 int sety;
 int n;
 if(logn<3) n=3;
 else       n=logn;
 sety=TDIRFY+TDIRDY*n+TDIRFY;
 extent(whandle[LOG],0,-sety,2*TIMEX+TMAXWIDTH*16,0);
}


/* write another entry to the list */

static os_error * logproc(tokstate * state)
{
 os_error * err;

 err=flex_chunke((flex_ptr)&logs,(logn+1)*sizeof(tokstate),LOGSCHUNK);
 if(!err)
 {
  logs[logn]=*state;
  logn++;
 }
 return(err);
}


static os_error * loginit(void)
{
 os_error * err;
 int        fh;
 tokstate   state;
 char       string[128];
 int        eof;
 buffer     bf;
 fstat      fs;

 err=NULL;

 tokinit();

 zerotoken(&state);

 if(!logs)
 {
  if(!err)
  {
   err=stat(logname,&fs);
   if(!err) err=fs_open(logname,'r',&fh);
   if(!err && fh)
   {
    err=bf_alloc(&bf,LBUFFSIZE,fh,fs.length);
    if(!err)
    {
     err=flex_alloce((flex_ptr)&logs,LOGSCHUNK);
     if(!err)
     {
      logn=0;
      while(1)
      {
       getstring(&bf,string,128,&eof);
       if(string[0])
       {
        processtoken(string,&state,logproc);
       }
       if(eof) break;
      }
     }
     bf_dealloc(&bf);
    }
    err=fs_close(fh,err);
   }
  }
 }
 return(err);
}


static void logfinit(void)
{
 if(logs) flex_free((flex_ptr)&logs);
}



void decodelogfile(int m1)
{
 os_error * err;

 if(m1==0) 
 {
  err=fs_delete(logname);
  if(!err)
  {
   logn=0;
   logfinit();
   flex_alloce((flex_ptr)&logs,LOGSCHUNK);
   logextent();
   refreshwindow(whandle[LOG]);
   reopenw(whandle[LOG]);
  }
  else report(err);
 }
}



void logicon(int icon)
{

 if(buttons==0x2)
 {
  popmenu(logfile_menu);
 }

 USE(icon);
}



static void logredrawsub(wimp_redrawstr * redrawstr,int more)
{
 int oy;
 int ox;
 int ylo;
 int yhi;
 int n;
 int y;
 int x;
 tokstate * state;
 int colour;

 wimpfontstart();

 while(more)
 {
  ox=redrawstr->box.x0-redrawstr->scx;
  oy=redrawstr->box.y1-redrawstr->scy;

  ylo=-(redrawstr->g.y1-oy);            /* small number, top of window */
  yhi=-(redrawstr->g.y0-oy);            /* bigger, bottom of window */

  n=(ylo-TDIRFY)/TDIRDY;
  if(n<0) n=0;
  y=n*TDIRDY+TDIRFY;

  while(y<=yhi && n<logn)
  {
   state=logs+n;

   x=ox+TIMEX;

   if(state->dir) colour=(1<<8)|7;
   else           
   {
    colour=(7<<8)|0;
    wimp_setcolour(7);
    bbc_rectanglefill(x,oy-y,TMAXWIDTH*wimpavfontwidth,-TDIRHY);
   }

   stringat(x,oy-y,state->time,colour,TDIRHY);
   x+=TFNAME*wimpavfontwidth;
   stringat(x,oy-y,state->filename,colour,TDIRHY);
   x+=TTYPE*wimpavfontwidth;
   stringat(x,oy-y,typestring[state->type],colour,TDIRHY);
   x+=TDUR*wimpavfontwidth;
   stringat(x,oy-y,state->duration,colour,TDIRHY);
   x+=TCOST*wimpavfontwidth;
   stringat(x,oy-y,state->cost,colour,TDIRHY);
   x+=TID*wimpavfontwidth;
   stringat(x,oy-y,state->id,colour,TDIRHY);
   x+=TNUM*wimpavfontwidth;
   stringat(x,oy-y,state->number,colour,TDIRHY);
   x+=TFSR*wimpavfontwidth;
   stringat(x,oy-y,state->fail,colour,TDIRHY);

   y+=TDIRDY;
   n++;
  } 

  wimp_get_rectangle(redrawstr,&more);
 }
 wimpfontend();
}


void logredraw(void)
{
 wimp_redrawstr redrawstr;
 int            more;
 redrawstr.w=ewindow;
 wimp_redraw_wind(&redrawstr,&more);
 logredrawsub(&redrawstr,more);
}


void closelog(void)
{
 closedownt(LOG);
 logfinit();
}


void showlog(void)
{
 os_error * err;
 int        handle;

 if(whandle[LOG]) forward(whandle[LOG]);
 else
 {
  handle=createwindow(LOG);
  if(!handle) return;

  err=loginit();
  if(!err) 
  {
   logextent();
   popup(handle,0);
  }
  else
  {
   closelog();
   report(err);
  }
 }
}



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

int             logfile;
char            logname[256];

static tokstate logstate;

static os_error * rlogproc(tokstate * state)
{
 os_error * err;
 int        handle;

 handle=whandle[LOG];

 err=logproc(state);

 if(handle)
 {
  logextent();
  getw(handle);
  scy-=TDIRDY;
  open(handle,x0,y0,x1,y1,scx,scy,bhandle);
  refreshwindow(handle);
 }

 return(err);
}


void writetolog(char * format, ...)
{
 va_list args;
 char string[256];
 char * p;
 FILE * fp;

 writesystimedate(string);
 p=string+strlen(string);
 strcpy(p," : ");
 p+=3;

 va_start(args, format);
 vsprintf(p, format, args);
 va_end(args);

 trans(string,sizeof(string));

 if(logfile)
 {
  fp=fopen(logname,"a");
  if(fp)
  {
   fwrite(string,strlen(string),1,fp);
   fclose(fp);
  }

  if(logs)
  {
   processtoken(string,&logstate,rlogproc);
  }
 }
}

void writetologx(int fp)
{
 writetolog("%s",stringptr(stack[fp]));
}

void writelogdcost(char * logs,int start,int band)
{         
 arctime  timenow;
 int      duration;
 int      day;
 int      current;
 int      cost;

 duration=(clock()-start)/100;

 getcurtime(&timenow);
 getdaysec(&timenow,&day,&current);

 cost=getcost(band,current,day,duration);

 writetolog("%s %d %d.%02d\n",logs,duration,cost/100,cost%100);
}


os_error * logboot(void)
{
 zerotoken(&logstate);
 return(NULL);
}


void logreasonx(char * reason)
{
 writetolog("{LOG18} %s\n",reason);
}


void logreason(int fp)
{
 logreasonx(stringptr(stack[fp]));
}


