/*->c.state */


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


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

#include "h.DrawLevel0"

#include "h.etc"

#include "h.wos"
#include "h.mym"
#include "h.ram"
#include "h.strdef"
#include "h.timex"
#include "h.file"
#include "h.tiff"
#include "h.fsx"
#include "h.pic"
#include "h.buffer"
#include "h.main"
#include "h.xext"
#include "h.dir"
#include "h.txfax"
#include "h.sched"
#include "h.config"
#include "h.con"
#include "h.serialdev"
#include "h.ser"
#include "h.view"
#include "h.batch"
#include "h.vx"
#include "h.newfax"
#include "h.log"

#include "h.state"





static int faxstate;


/* states are */

/* does nothing, just sits on the icon bar */

#define SQUIESCENT 0

/* sits on icon bar, and monitors serial line */

#define SANSWER    1

/* issued dial command, waiting for response */

#define SDIAL      2

/* transmitting data */

#define STXDATA    3

/* receiving data */

#define SRXDATA    4



#define WAKEUPDELAY 500
#define INTERDELAY  500


static int newdatatime;
static int newdatastate;
static int quiescenttime;


void rxdatazero(void)
{
 if(zerotime>newdatatime)
 {
  sethearsayicon(newdatastate?1:0);
  newdatastate^=1;
  newdatatime=zerotime+100;
 }
}


static void setrxdata(int on)
{
 if(on)
 {
  addzeroevent(RXDATAZERO);
 }
 else
 {
  remzeroevent(RXDATAZERO);
 }
}



void txdatazero(void)
{
 if(zerotime>newdatatime)
 {
  sethearsayicon(newdatastate?2:0);
  newdatastate^=1;
  newdatatime=zerotime+100;
 }
}


static void settxdata(int on)
{
 if(on)
 {
  addzeroevent(TXDATAZERO);
 }
 else
 {
  remzeroevent(TXDATAZERO);
 }
}



static void setanswerstate(int on)
{
 if(on)
 {
  sethearsayicon(0);
  addzeroevent(FAXPOLL);
 }
 else
 {
  sethearsayicon(3);
  remzeroevent(FAXPOLL);
 }
}


static void setdialstate(int enter)
{
 sethearsayicon(0);
 USE(enter);
}



static void setstate(int newstate)
{
 char string[128];


 switch(faxstate)
 {
     case SANSWER:
                  setanswerstate(0);
                  break;

     case SRXDATA:
                  setrxdata(0);
                  break;


     case STXDATA:
                  settxdata(0);
                  break;

  case SQUIESCENT:
                  setanswerstate(1);
                  quiescenttime=monotonic()+WAKEUPDELAY;
                  break;

       case SDIAL:
                  setdialstate(0);
                  break;
 }


 switch(newstate)
 {
     case SANSWER:
                  if(answermode)
                  {
                   strcpy(string,"{CON00} (");
                   if(answermode & AVOICE) strcat(string,"{CON17}+");
                   if(answermode & AFAX)   strcat(string,"{CON18}+");
                   if(answermode & ADATA)  strcat(string,"{CON19}+");
                   string[strlen(string)-1]=')';
                   conaction(string);
                  }
                  else
                  {
                   conaction("{CON16}");
                  }

                  setanswerstate(1);
                  break;

     case SRXDATA:
                  setrxdata(1);
                  break;


     case STXDATA:
                  settxdata(1);
                  break;

  case SQUIESCENT:
                  conaction("{CON01}");
                  setanswerstate(0);
                  break;

       case SDIAL:
                  setdialstate(1);
                  break;
 }

 faxstate=newstate;
}



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

static faxcanfn faxcan;

void setfaxcancelhandler(faxcanfn faxcanf)
{
 faxcan=faxcanf;
}

void clearfaxcancelhandler(void)
{
 faxcan=NULL;
}

void faxcancel(void)
{
 if(!faxcan)
 {
  holdtarget();
  xexec("modem_interrupt",NULL,NULL,NULL);
  zruns=0;
 }
 else
 {
  faxcan();
 }
}




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

static int  modemactive;





void directreceive(void)
{
 int result;
 int duration;
 int mode;

 if(faxstate==SANSWER)
 {
  if(activemodem())
  {
   if(server)
   {
    runanswerserver(0);  /* was result */
   }
   else
   {
    writetolog("{LOG00}\n");
    duration=clock();
    contime(1);

    setstate(SRXDATA);
    xexec("modem_connect",NULL,NULL,&result);
    if(result)
    {
     mode=result;
     xexec("modem_receive",NULL,&mode,&result);
    }

    contime(0);
    saveconfig();
    setstate(SANSWER);
    writelogdcost("{LOG01}",duration,-1);
   }

   clearmodem();
  }
 }
}



void directsend(void)
{
 int enter;
 int result;
 int documents;
 int duration;
 int mode;
 int answer;

 if(faxstate==SANSWER)
 {
  if(activemodem())
  {
   if(directtarget(serversn))
   {
    writetolog("{LOG02}\n");
    setstate(STXDATA);
    duration=clock();
    contime(1);

    enter=0;
    mode=txmode;
    answer=0;

    if(xexec2("modem_autoanswer",&enter,&answermode,NULL) &&
        xexec("modem_setmode",NULL,&mode,NULL) &&
        xexec("modem_setanswer",NULL,&answer,NULL))
    {
     setstate(SDIAL);
     faxtxprelims();
     conaction("{CON02}");

     if(xexec("modem_connect",NULL,NULL,&result))
     {
      if(result)
      {
       mode=result;
       setstate(STXDATA);
       documents=1;
       if(!xexec2("modem_send",&mode,&documents,&result))
       {
        writetolog("{LOG03}\n");
       }
      }
      else
      {
       writetolog("{LOG04}\n");
      }
     }
     else
     {
      writetolog("{LOG04}\n");
     }
     setstate(SANSWER);
    }

    contime(0);
    saveconfig();

    enter=rings;
    answer=modemanswerorginate;
    xexec("modem_setmode",NULL,&answermode,NULL);
    xexec("modem_setanswer",NULL,&answer,NULL);
    xexec2("modem_autoanswer",&enter,&answermode,NULL);

    writelogdcost("{LOG05}",duration,-1);

    setuptarget();
   }
   clearmodem();
  }
 }
}



void directdial(char * text,int recv)
{
 static int norecurse;
 int        result;
 int        enter;
 int        documents;
 char       number[128];
 int        duration;
 newbitstr  bits;
 int        n;
 int        rxmode;
 int        answer;
 int        mode;
 int        code;

 if(norecurse) return;
 norecurse=1;

 /* need to set up phone number bits */
 /* repeating schedule work, because here there is no schedule */

 n=findname(text);
 if(n>=0) 
 {
  getdirbitsall(n,&bits); /* get voice,fax,data bits */
  rxmode=0;
  if(bits.voice) rxmode|=AVOICE;
  if(bits.fax)   rxmode|=AFAX;
  if(bits.data)  rxmode|=ADATA;
 }
 else
 {
  bits=defnewbits;
  rxmode=answermode;
 }


 if(faxstate==SANSWER)
 {
  if(activemodem())
  {
   if(!getnumber(text,number,1,bits.prefix))
   {
    if(recv || directtarget(serversn))
    {
     txdirn=getdirid(n);  /* zeroed by directtarget ^^^^  or not set! */

     enter=0;
     answer=(recv!=0);
     if(recv) mode=rxmode;
     else     mode=txmode;

     if(xexec2("modem_autoanswer",&enter,&answermode,NULL) &&
        xexec("modem_setmode",NULL,&mode,NULL) &&
        xexec("modem_setanswer",NULL,&answer,NULL))
     {
      writetolog("{LOG08} %s\n",text);

      if(!recv) faxtxprelims();

      setstate(SDIAL);
      conaction("{CON03} %s",text);
      confax(leaf(txdocname));

      if(xexec("modem_dial",number,NULL,&result))
      {
       duration=clock();
       contime(1);

       if(result)
       {
        mode=result;

        if(txserver(result,txdirn,&code))
        {

        }
        else
        if(recv)
        {
         setstate(SRXDATA);
         xexec("modem_receive",NULL,&mode,&result);
        }
        else
        {
         setstate(STXDATA);
         documents=1;
         if(!xexec2("modem_send",&mode,&documents,&result))
         {
          writetolog("{LOG03}\n");
         }
        }
       }
       else
       {
        writetolog("{LOG04}\n");
       }

       writelogdcost("{LOG17}",duration,bits.band);
       contime(0);
      }
      else
      {
       writetolog("{LOG10} %s\n",text);
      }

      setstate(SANSWER);
      enter=rings;
      answer=modemanswerorginate;

      xexec("modem_setmode",NULL,&answermode,NULL);
      xexec("modem_setanswer",NULL,&answer,NULL);
      xexec2("modem_autoanswer",&enter,&answermode,NULL);

      saveconfig();
     }

     if(!recv) setuptarget();
    }
   }

   clearmodem();
  }
 }

 norecurse=0;
}



void faxpoll(void)
{
 static int norecurse;
 int        result;
 int        enter;
 int        mode;
 int        answer;
 int        duration;
 int        code;


 if(norecurse) return;
 norecurse=1;

 if(faxstate==SANSWER)
 {
  if(answermode && xexec("modem_poll",NULL,NULL,&result))
  {
   if(result) /* looks like we're going to receive a fax */
   {
    if(server)
    {
     directtarget(serversn);
     runanswerserver(result);
    }
    else
    {
     writetolog("{LOG06}\n");
     duration=clock();
     contime(1);

     setstate(SRXDATA);
     xexec("modem_connect",NULL,NULL,&result);
     if(result)
     {
      mode=result;
      xexec("modem_receive",NULL,&mode,&result);
     }
     setstate(SANSWER);
     writelogdcost("{LOG07}",duration,-1);

     contime(0);
     saveconfig();
    }
   }
  }
   /* Do call placing logic */
  if(monotonic()>quiescenttime && txfindtarget())
  {
   quiescenttime=monotonic()+INTERDELAY;

   if(activemodem())
   {
    enter=0;

    if(xexec2("modem_autoanswer",&enter,&answermode,NULL))
    {
     mode=txmode;
     answer=txanswer;
     if(xexec("modem_setmode",NULL,&mode,NULL))
     {
      if(xexec("modem_setanswer",NULL,&answer,NULL))
      {
       setstate(SDIAL);

       faxtxprelims();
       writetolog("{LOG08} %s\n",txname);
       conaction("{CON03} %s",txname);
       confax(leaf(txdocname));
       if(xexec("modem_dial",txnumber,NULL,&result))
       {
        duration=clock();
        contime(1);


        if(result)
        {
         if(txdocuments)
         {
          if(txserver(result,txdirn,&code))
          {
           if(code) schedaddattempt();
           else     schedsentdoc();
          }
          else
          {
           setstate(STXDATA);
           if(!xexec2("modem_send",&mode,&txdocuments,&result))
           {
            writetolog("{LOG03}\n");
            schedaddattempt();
           }
           else
           if(result)
           {
            writetolog("{LOG03}\n");
            schedaddattempt();
           }
          }
         }
         else  /* nothing to send, try to rx? */
         {
          if(txserver(result,txdirn,&code))
          {
           if(code) schedaddattempt();
           else     schedsentdoc();
          }
          else
          {
           setstate(SRXDATA);
           if(!xexec("modem_receive",NULL,&mode,&result))
           {
            writetolog("{LOG03}\n");
            schedaddattempt();
           }
           else
           {
            if(result)
            {
             writetolog("{LOG03}\n");
             schedaddattempt();
            }
            else
            {
             schedsentdoc();
            }
           }
          }
         }
        }
        else
        {
         writetolog("{LOG09} %s\n",txname);
         schedaddattempt();
        }

        writelogdcost("{LOG17}",duration,txband);
        contime(0);
       }
       else
       {
        writetolog("{LOG10} %s\n",txname);
        schedaddattempt();
       }
      }
     }
    }

    xexec("modem_disconnect",NULL,NULL,NULL);

    setstate(SANSWER);

    answer=modemanswerorginate;
    xexec("modem_setmode",NULL,&answermode,NULL);
    xexec("modem_setanswer",NULL,&answer,NULL);

    enter=rings;
    xexec2("modem_autoanswer",&enter,&answermode,NULL);
    saveconfig();
    clearmodem();
   }
   else  /* if not active modem */
   {
    schedaddattempt();
   }
  }
 }
 norecurse=0;
}



void voicedial(char * text,int map,int prefix)
{
 static int norecurse;
 int        result;
 int        enter;
 char       number[128];

 if(norecurse) return;
 norecurse=1;

 if(faxstate==SANSWER)
 {
  if(activemodem())
  {
   if(!getnumber(text,number,map,prefix))
   {
    enter=0;
    xexec2("modem_autoanswer",&enter,&answermode,NULL); 

    setstate(SDIAL);
    xexec("modem_voicedial",number,NULL,&result);
    setstate(SANSWER);

    enter=rings;
    xexec2("modem_autoanswer",&enter,&answermode,NULL);
   }
   clearmodem();
  }
 }
 norecurse=0;
}



void stategoquiet(void)
{
 int enter;
 int result;
 static int norecurse;

 if(norecurse) return;
 norecurse=1;

 if(faxstate!=SQUIESCENT)
 {
  enter=0;
  if(modemactive)
  {
   xexec2("modem_autoanswer",&enter,&answermode,&result);
   xexec("modem_terminate",NULL,NULL,NULL);
   remzeroevent(BLOCKZERO);
   modemactive=0;
  }
  setstate(SQUIESCENT);
 }

 norecurse=0;
}



int stategoanswer(void)
{
 int        enter;
 int        answer;
 int        result;
 int        code;
 static int norecurse;

 if(norecurse) return(1);
 norecurse=1;

 code=1;
 modemactive=0;

 if(xexec("modem_initiate",NULL,&deviceport,&result))
 {
  if(!result)
  {
   answer=modemanswerorginate;
   xexec("modem_setmode",NULL,&answermode,NULL);
   xexec("modem_setanswer",NULL,&answer,NULL);

   enter=rings;
   xexec2("modem_autoanswer",&enter,&answermode,&result);
   if(!result)
   {
    setstate(SANSWER);
    setuptarget();
    code=0;
    modemactive=1;
    clearmodem();
   }
   else 
   {
    xexec("modem_terminate",NULL,NULL,NULL);
    remzeroevent(BLOCKZERO);
   }
  }
  else code=result;
 }

 norecurse=0;

 return(code);
}



int activemodem(void)
{
 int result;

 if(!modemactive)
 {
  if(!xexec("modem_initiate",NULL,&deviceport,&result) || result)
  {
   errorbox("{MODEM}");
   return(0);
  }
 }

 modemactive=1;
 return(1);
}



void clearmodem(void)
{
 if(!answermode && modemactive)
 {
  xexec("modem_terminate",NULL,NULL,NULL);
  remzeroevent(BLOCKZERO);
  modemactive=0;
 }
}



void stateclick(void)
{
 if(buttons==1)
 {
  if(faxstate==SANSWER)    stategoquiet();
  else
  if(faxstate==SQUIESCENT)
  {
   if(stategoanswer()==1)
              errorbox("{MODEM}");
  }
 }
}


void xsetstate(int fp)
{
 if(stack[fp])
 {
  if(faxstate==SQUIESCENT) stategoanswer();
 }
 else
 {         
  if(faxstate==SANSWER)    stategoquiet();
 }
}




int activestate(void)
{
 return(faxstate!=SQUIESCENT);
}


/* return 0 on OK */

int checkactive(void)
{
 if(faxstate==SQUIESCENT)
 {
  if(stategoanswer()==1)
  {
   errorbox("{MODEM}");
   return(1);
  }
 }
 return(0);
}



int onlinestate(void)
{
 return(faxstate==SDIAL || faxstate==STXDATA || faxstate==SRXDATA);
}


void stateinit(void)
{
 addabendhandler(faxcancel);

 setstate(SQUIESCENT);
}



void statefinit(void)
{


}



static int savestate;

void statesavequiet(void)
{
 savestate=faxstate;
 stategoquiet();
}


void stateload(void)
{
 switch(savestate)
 {
  case    SANSWER:
                  stategoanswer();
                  break;

  case SQUIESCENT:
                  stategoquiet();
                  break;
 }
}


/*****************************************************************************/
/* an event that is triggered by the rx of a fax              */
/* we do it this way to prevent, printing whilst on line etc. */

void rxfaxzero(void)
{
 int bn;
 static int norecurse;

 if(!norecurse && !onlinestate())
 {
  norecurse=1;
  statesavequiet();

  for(bn=0;bn<vnofiles[RXBFILE];bn++)
  {
   if(vtable[RXBFILE][bn].autoprint)   autoprint(RXBFILE,bn);
   if(vtable[RXBFILE][bn].autoforward) autoforward(bn);
   vtable[RXBFILE][bn].autoprint=vtable[RXBFILE][bn].autoforward=0;
  }

  batchpop();

  stateload();
  remzeroevent(RXFAXZERO);
  norecurse=0;
 }
}

