/*->c.replay */

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


#include "h.kernel"

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


#include "h.wos"
#include "h.trans"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.pr"

#include "h.term"
#include "h.file"

#include "h.vxdef"
#include "h.vxterm"
#include "h.mxterm"


#include "h.vtdef"
#include "h.vtfile"
#include "h.vtprint"
#include "h.vtact"
#include "h.vtscr"


#include "h.tek"

#include "h.replay"



FILE * repfp=NULL;


int    replayfix;          /* signal to terminals we are replaying stuff */
                           /* and that they should stop on cls           */
int    replayclscode;      /* code to indicate pending operation         */
int    replayclsflag;

int    repskiptonext;

int    reptime;            /* time of next replay zero */


static int    repspeed;           /* real variables */
static int    reppause;
static int    repframe;
static int    repframeno;
static int    repbytes;
static int    rephome;

static int    crepspeed;          /* what the display is showing */
static int    creppause;
static int    crepframeno;
static int    crepframe;
static int    crepbytes;


static char * repname;            /* name of what we are replaying */
static int    wasvolatile;



typedef struct repstr
{
 int offset;
 int clscode;
} repstr;


#define REPCHUNK 32*sizeof(repstr)


static repstr * repstack;


/* addresses of sprites */


#define FDIGITHI 0
#define FDIGITLO 1
#define BDIGIT4  2
#define BDIGIT3  3
#define BDIGIT2  4
#define BDIGIT1  5
#define BDIGIT0  6
#define PAUSE    7
#define RFRAME   8



static char rsnames[9][12];


static void replaysetup(void)
{
 int i;

 for(i=FDIGITHI;i<=FDIGITLO;i++)
 {
  strcpy(rsnames[i],"lcd0");
  setspa(whandle[REPLAY],13+i-FDIGITHI,12,rsnames[i]);
 }

 for(i=BDIGIT4;i<=BDIGIT0;i++)
 {
  strcpy(rsnames[i],"lcd0");
  setspa(whandle[REPLAY],7+i-BDIGIT4,12,rsnames[i]);
 }

 for(i=15;i<=24;i++) seti(whandle[REPLAY],i,0x70000000,0xF0000000);

 strcpy(rsnames[PAUSE],"p1");
 setspa(whandle[REPLAY],12,12,rsnames[PAUSE]);

 strcpy(rsnames[RFRAME],"f");
 setspa(whandle[REPLAY],25,12,rsnames[RFRAME]);

 writeicon(whandle[REPLAY],5,transtoken("REP00"));

 repspeed=10;
 crepspeed=0; 
 reppause=creppause=0;
 crepframeno=0;
 repframe=crepframe=1;
 repbytes=crepbytes=rephome=0;
}


static char * replaystr[4]={"p1","p2","p4","p3"};

static void replayupdate(void)
{
 int nr;
 int nc;
 int r;
 int c;
 int ir;
 int ic;
 int i;

 if(reppause!=creppause)
 {
  strcpy(rsnames[PAUSE],replaystr[reppause]);
  seti(whandle[REPLAY],12,0,0);
  writeicon(whandle[REPLAY],5,transtoken(reppause?"REP01":"REP00"));
 }

 if(repframe!=crepframe)
 {
  strcpy(rsnames[RFRAME],repframe?"f":"");
  seti(whandle[REPLAY],25,0,0);
 }

 if(repbytes!=crepbytes) /* things get complicated */
 {
  r=repbytes;
  c=crepbytes;

  for(i=0;i<5;i++)
  {
   nr=r/10;
   nc=c/10;

   ir=r-nr*10;
   ic=c-nc*10;

   if(ir!=ic)
   {
    rsnames[BDIGIT0-i][3]='0'+ir;
    seti(whandle[REPLAY],11-i,0,0);
   }

   r=nr;
   c=nc;

   if(r==c) break;
  }
 }


 if(repframeno!=crepframeno) /* things get complicated */
 {
  r=repframeno;
  c=crepframeno;

  for(i=0;i<2;i++)
  {
   nr=r/10;
   nc=c/10;

   ir=r-nr*10;
   ic=c-nc*10;

   if(ir!=ic)
   {
    rsnames[FDIGITLO-i][3]='0'+ir;
    seti(whandle[REPLAY],14-i,0,0);
   }

   r=nr;
   c=nc;

   if(r==c) break;
  }
 }


 if(crepspeed!=repspeed)
 {
  r=repspeed;
  c=crepspeed;

  for(i=0;i<10;i++)
  {
   r-=10;
   c-=10;

   if((r<0 && c>=0) || (c<0 && r>=0))
   {
    seti(whandle[REPLAY],i+15,r>=0?0xB0000000:0x70000000,0xF0000000);
   }
   else
   if(c<=0 && r<=0) break;
  }
 }

 crepspeed=repspeed; 
 creppause=reppause;
 crepframeno=repframeno;
 crepframe=repframe;
 crepbytes=repbytes;
}









/* seeks back a frame */

static void repbackframe(void)
{
 if(reppause==3 && repframeno>1)
 {
  repframeno--;
  replayclscode=repstack[repframeno-1].clscode;
  fseek(repfp,repbytes=repstack[repframeno-1].offset,SEEK_SET);
  flex_chunk((flex_ptr)&repstack,repframeno*sizeof(repstr),REPCHUNK);
 }
 else
 if(repframeno>0)
 {
  replayclscode=repstack[repframeno-1].clscode;
  fseek(repfp,repbytes=repstack[repframeno-1].offset,SEEK_SET);
 }
}




/* saves the current frame state */

static void repsaveframe(void)
{
 repstack[repframeno].clscode=replayclscode;
 repstack[repframeno].offset=repbytes;

 if(flex_chunk((flex_ptr)&repstack,(repframeno+1)*sizeof(repstr),REPCHUNK))
                                                                 repframeno++;
}



/* clears the paused on a frame state */

static void repclearframe(void)
{
 if(replayclscode==VXCLS && vxexists)     viewcls();
 else
 if(replayclscode==VTCLS && vtexists)     clearscr(replayclsflag);
 else
 if(replayclscode==VTCLSHOME && vtexists) clearscrhome(replayclsflag);
 else
 if(replayclscode==TEKCLS && tekexists)    tekcls();
 else
 if(replayclscode==MXCLS && vxexists && minitel)     mxcls();
}





/* boot frame code */

static int repbootframes(void)
{
 repframeno=0;
 return(flex_alloc((flex_ptr)&repstack,REPCHUNK));
}



/* trash frame code */

static void reptrashframes(void)
{
 flex_free((flex_ptr)&repstack);
}






void closereplay(void)
{

 if(repfp)
 {
  fclose(repfp);
  repfp=NULL;
  closedownt(REPLAY);
  remzeroevent(REPLAYZERO);
  reptrashframes();
 }

 if(repname && wasvolatile)
 {
  remove(repname);
  flex_free((flex_ptr)&repname);
  wasvolatile=0;
 }
}







/* clicks on window */

void replayclick(void)
{
 switch(icon)
 {
  case  1:                 /* go back one frame */
          repframe=1;
          repbackframe();
          repclearframe();
          reppause=3;
          break;

  case  5:                 /* pause/play */
          if(!reppause) reppause=1;
          else
          {
           if(reppause==3) repclearframe();
           reppause=0;
          }
          break;

  case  2:                 /* skip forward one frame */
          if(reppause==3)  repclearframe();
          reppause=0;
          repskiptonext=1;
          repframe=1;
          break;


  case  6:                 /* faster */
          if(repspeed>9) repspeed+=10;
          else           repspeed+=1;
          break;


  case 26:                 /* start over */
          repframeno=reppause=0;
          fseek(repfp,repbytes=rephome,SEEK_SET);
          break;

  case  4:                 /* go into frame mode */
          repframe^=1;
          break;

  case  3:                 /* slower */
          if(repspeed>10) repspeed-=10;
          else
          if(repspeed>2)  repspeed-=1;
          break;

 }

 replayupdate();
}



void replayzero(void)
{
 int i,byte;

 if(reppause) return;
 if(zerotime<reptime) return;

 replayfix=repframe;
 replayclscode=0;

 for(i=0;(i<repspeed) || repskiptonext;i++)
 {
  if(feof(repfp)) 
  {
   reppause=2;
   break;
  }

  if(tty(byte=fgetc(repfp))!=EOF) repbytes++;

  if(replayclscode)
  {
   repsaveframe();
   reppause=3;
   break;
  }
 }

 replayfix=0;
 repskiptonext=0;

 replayupdate();

 reptime=zerotime+5;
}



/* passed a filename, to replay through the terminal */

void startreplay(int type,char * filename,int xvolatile)
{
 int   handle;
 char  header[32];

 closereplay();

 handle=createwindowsub(REPLAY,leaf(filename));
 if(!handle) return;

 replaysetup();
 if(!repbootframes()) return;

 wasvolatile=xvolatile;

 if((repfp=fopen(filename,"rb"))==NULL)
 {
  reptrashframes();
  closedownt(REPLAY);
  return;
 }

 if(xvolatile)
 {
  if(flex_alloc((flex_ptr)&repname,256)) strcpy(repname,filename);
  else return;
 }

 if(type==CEPT2 || type==CEPT3)  /* these gotta have a header */
 {
  fread(header,7,1,repfp);
  if(strcmp(header,"ACDemo\n"))
  {
   closereplay();
   return;
  }

  rephome=7;
 }

 repbytes=rephome;

 popup(handle,0);
 addzeroevent(REPLAYZERO);
}

