/*->c.timex */

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

#include "h.os"
#include "h.bbc"
#include "h.wimp"
#include "h.swis"

#include "h.def"
#include "h.wos"

#include "h.ram"

#include "h.timex"

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


int monotonic(void)
{
 os_regset rx;
 os_swix(OS_ReadMonotonicTime,&rx);
 return(rx.r[0]);
}



/* get current time */

void getcurtime(arctime * time)
{
 os_error * errpoi;
 char       pblk[32];

 pblk[0]=3;
 errpoi=os_word(14,pblk);

 time->lo=*(unsigned int *)pblk;
 time->hi=pblk[4];
}



static int filetime(fstat * f,arctime * t)
{
 if((f->load & 0xFFF00000)==0xFFF00000)   /* has time stamp */
 {
  t->lo=f->exec;
  t->hi=f->load & 0xFF;
  return(1);
 }
 else
  return(0);
}





/* return -1 f1<f2 1 if f1>f2 else 0 */

int cmptimes(fstat * f1,fstat * f2)
{
 arctime t1;
 arctime t2;
 int     t1true;
 int     t2true;

 t1true=filetime(f1,&t1);
 t2true=filetime(f2,&t2);

 if(!t1true && !t2true) return(0);
 else
 if(!t1true)            return(-1);
 else
 if(!t2true)            return(1);

 if(t1.hi==t2.hi)
 {
  if(t1.lo>t2.lo) return(1);
  else            return(-1);
 }
 else
 if(t1.hi>t2.hi) return(1);
 else            return(-1);
}



/* return -1 t1<t2 1 if t1>t2 else 0 */

int cmptimex(arctime * t1,arctime * t2)
{

 if(t1->hi==t2->hi)
 {
  if(t1->lo>t2->lo) return(1);
  else              return(-1);
 }
 else
 if(t1->hi>t2->hi) return(1);
 else              return(-1);
}


void addtimex(arctime * t,unsigned int delta,int inc)
{
 unsigned int oldlo;

 oldlo=t->lo;

 if(inc)
 {
  t->lo+=delta;
  if(t->lo<oldlo) t->hi++;
 }
 else
 {
  t->lo-=delta;
  if(t->lo>oldlo) t->hi--;
 }
}



void writets(char * string,char * format,arctime * timex)
{
 char pblk[32];
 os_regset rx;

 *(unsigned int *)pblk=timex->lo;
 pblk[4]=timex->hi;

 rx.r[0]=(int)pblk;
 rx.r[1]=(int)string;
 rx.r[2]=64;
 rx.r[3]=(int)format;

 os_swix(OS_ConvertDateAndTime,&rx);
}



void writedate(char * string,arctime * timex)
{
 writets(string,"%ZDY %M3 %YR%0",timex);
}


void writetime(char * string,arctime * timex)
{
 writets(string,"%Z12:%MI%AM%0",timex);
}



void writetimedate(char * string,arctime * timex)
{
 writets(string,"%24:%MI:%SE %W3 %DY %M3 %YR%0",timex);
}


void getsysdate(char * format,int d,int t)
{
 char dstring[64];
 char tstring[64];

 strcpy(dstring,"%ZDY %M3 %YR");
 strcpy(tstring,"%Z12:%MI%AM");

 if(getenv("ArcFax$DateFormat"))
                     strcpy(dstring,getenv("ArcFax$DateFormat"));
 if(getenv("ArcFax$TimeFormat"))
                     strcpy(tstring,getenv("ArcFax$TimeFormat"));

 if(d && t) sprintf(format,"%s %s%%0",tstring,dstring);
 else
 if(t)      sprintf(format,"%s%%0",tstring);
 else       sprintf(format,"%s%%0",dstring);
}



void writesysst(char * string,int d,int t)
{
 arctime timex;
 char format[64];

 getcurtime(&timex);
 getsysdate(format,d,t);
 writets(string,format,&timex);
}



void writesystime(char * string)
{
 writesysst(string,0,1);
}



void writesysdate(char * string)
{
 writesysst(string,1,0);
}


void writesystimedate(char * string)
{
 writesysst(string,1,1);
}


void writefiletime(char * string,fstat * stat)
{
 arctime t;

 if(filetime(stat,&t))
   writetimedate(string,&t);
 else
   strcpy(string,"");
}


void writehms(char * str,int time)
{
 time=time/100;
 sprintf(str,"%02d:%02d:%02d",(time/3600) % 24,(time/60) % 60,time % 60);
}


void writehmap(char * str,int time)
{
 sprintf(str,"%02d:%02d%s",(time/3600) % 12,(time/60) % 60,
                                            (time>=12*3600)?"pm":"am");
}



static int mxt[12]={31,28,31,30,31,30,31,31,30,31,30,31};

void getyearandmonth(arctime * atx,int * yrp,int * mop,int * dyp)
{
 unsigned int dy;
 unsigned int mo;
 unsigned int yr;
 unsigned int su;
 unsigned int tl;
 unsigned int th;

 th=(atx->hi<<24)|(atx->lo>>8);
 tl=atx->lo & 0xFF;

 for(yr=0;;yr++)
 {
  if(((yr % 4)==0) && yr) su=366*3*11250;
  else                    su=365*3*11250;
  if(th<su) break; else th-=su;
 }

 tl=tl+(th << 8);
 tl=tl/100;

 for(mo=1;;mo++)
 {
  su=24*3600*mxt[mo-1];
  if(mo==2 && (yr % 4)==0) su+=24*3600;
  if(tl<su) break; else tl-=su;
 }

 dy=tl/(24*3600)+1;

 *yrp=yr;
 *mop=mo;
 *dyp=dy;
}

int monthdays(int mo,int yr)
{
 int dy;

 dy=mxt[mo-1];
 if(mo==2 && (yr % 4)==0 && yr) dy++;

 return(dy);
}



static void arctomsdos(int * date,int * time,
                unsigned int tl,unsigned int th)
{
 unsigned int dy,mo,yr,ss,mm,hh,su;


 for(yr=0;;yr++)
 {
  if(((yr % 4)==0) && yr) su=366*3*11250;
  else                    su=365*3*11250;
  if(th<su) break; else th-=su;
 }

 if(yr<80) yr=0; else yr-=80;

 tl=tl+(th << 8);
 tl=tl/100;

 for(mo=1;;mo++)
 {
  su=24*3600*mxt[mo-1];
  if(mo==2 && (yr % 4)==0) su+=24*3600;
  if(tl<su) break; else tl-=su;
 }

 dy=tl/(24*3600)+1;
 hh=(tl-24*3600*(dy-1))/3600;
 mm=(tl-24*3600*(dy-1)-3600*hh)/60;
 ss=(tl-24*3600*(dy-1)-3600*hh-60*mm);

 *time=(hh << 11)+(mm << 5)+(ss >> 1);
 *date=(yr <<  9)+(mo << 5)+dy;
}



void arcgetstamp(int arcload,int arcexec,int * date,int * time)
{
 os_regset        rx;
 unsigned int     tl;
 unsigned int     th;
 unsigned int     load;
 unsigned int     exec;
 char             pblk[32];


 if((arcload  & 0xFFF00000)==0xFFF00000)
 {
  load=arcload & 0xFF;
  exec=arcexec;
 }
 else
 {
  pblk[0]=3;

  rx.r[0]=14;

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

  os_swix(OS_Word,&rx);

  exec=*(unsigned int *)pblk;
  load=pblk[4];
 }

 tl=exec & 0xFF;
 th=(load << 24)+(exec >> 8);

 arctomsdos(date,time,tl,th);
}



static void dmytoarc(int date,int time,arctime * tx)  
{
 os_error *   err;
 unsigned int yr,mo,dy,hh,mm,ss,th,tl,tt,i;
 int          block[7];
 os_regset    rx;


 yr = (date >> 9) & 0x7f;   
 mo = (date >> 5) & 0x0f;
 dy = date & 0x1f;

 hh = (time >> 11) & 0x1f;  
 mm = (time >> 5)  & 0x3f;
 ss = (time & 0x1f) * 2;



 block[0]=0;
 block[1]=ss;
 block[2]=mm;
 block[3]=hh;
 block[4]=dy;
 block[5]=mo;
 block[6]=yr+80+1900;

 rx.r[0]=-1;
 rx.r[1]=(int)(&tx->lo);
 rx.r[2]=(int)block;

 err=os_swix(Territory_ConvertOrdinalsToTime,&rx);
 if(!err) return;


 tt=ss*100+mm*6000+hh*360000;
 tl=tt & 0xFF;
 tt=tt >> 8;

 tt+=(dy-1)*3*11250;

 for(i=1;i<mo;i++) tt=tt+mxt[i-1]*3*11250;

 yr+=80;
 tt+=yr*365*3*11250;
 if((yr % 4)!=0) tt+=(yr/4)*3*11250;
 else if(yr) tt+=(yr/4-1)*3*11250;

 if(((yr % 4)==0) && mo>2 && yr) tt+=3*11250;

 th=tt >> 24;
 tl=(tt << 8)+tl;

 tx->lo=tl;
 tx->hi=th;
}


#define STACCNOTYPE  0
#define STACCMINTYPE 1
#define STACCSECTYPE 2
#define STACCDYTYPE  3
#define STACCMOTYPE  4
#define STACCYRTYPE  5

/* given a string, hh:mm:ss dd/mm/yy, produce the time */
/* return 1 OK                                         */

int gettimedate(char * string,arctime * tx)
{
 char * p;
 int    c;
 int    state;
 int    sum;
 int    time;
 int    date;
/* unsigned int    dd;
 unsigned int    mo;
 unsigned int    yy;
 unsigned int    ss;
 unsigned int    mm;
 unsigned int    hh; */

 int    dd;
 int    mo;
 int    yy;
 int    ss;
 int    mm;
 int    hh;


 getcurtime(tx);
 arctomsdos(&date,&time,tx->lo & 0xFF,(tx->hi<<24)|(tx->lo>>8));

 yy = (date >> 9) & 0x7f;   
 mo = (date >> 5) & 0x0f;
 dd = date & 0x1f;

 hh = (time >> 11) & 0x1f;  
 mm = (time >> 5)  & 0x3f;
 ss = (time & 0x1f) * 2;

 yy+=80;

 state=STACCNOTYPE;
 sum=-1;
 p=string;

 while(1)
 {
  c=*p++;

  if(isdigit(c))
  {
   if(sum<0) sum=0;
   sum=sum*10+c-'0';
  }
  else
  if((c==' '||!c) && sum<0)
  {
   if(!c) break;
  }
  else
  if( (c==':' && (state==STACCNOTYPE || state==STACCMINTYPE)) ||
     ((c==' ' || !c) && (state==STACCMINTYPE || state==STACCSECTYPE))
    )
  {
   if(state==STACCNOTYPE)
   {
    hh=sum;
    mm=ss=0;

    if(c==':') state=STACCMINTYPE;
    else       state=STACCDYTYPE;
    sum=-1;
   }
   else
   if(state==STACCMINTYPE)
   {
    mm=sum;
    if(c==':') state=STACCSECTYPE;
    else       state=STACCDYTYPE;
    sum=-1;
   }
   else
   if(state==STACCSECTYPE)
   {
    ss=sum;
    sum=-1;
    if(c==':') break;
    else       state=STACCDYTYPE;
   }
  }
  else
  if(c=='/' || c==' ' || !c)
  {
   if(state==STACCDYTYPE || state==STACCNOTYPE)
   {
    if(state==STACCNOTYPE) hh=mm=ss=0;
    dd=sum;
    if(c=='/') state=STACCMOTYPE;
    else       break;
    sum=-1;
   }
   else
   if(state==STACCMOTYPE)
   {
    mo=sum;
    if(c=='/') state=STACCYRTYPE;
    else       break;
    sum=-1;
   }
   else
   if(state==STACCYRTYPE)
   {
    yy=sum;
    break;
   }
  }
  else break;
 }

 if(mo<1 || mo>12) return(0);
 if(yy<80) yy+=100;
 if(hh<0 || hh>23) return(0);
 if(ss<0 || ss>59) return(0);
 if(mm<0 || mm>59) return(0);
 if(dd<1 || dd>31) return(0);
 if(dd>monthdays(mo,yy)) return(0);

 yy-=80;
 if(yy<0) return(0);


 time=(hh<<11)+(mm<<5)+(ss>>1);
 date=(yy<<9)+(mo<<5)+dd;

 dmytoarc(date,time,tx);

 return(1);
}

/*
void txtest(void)
{
 arctime timex;
 char    string[128];

 while(1)
 {
  gets(string);

  gettimedate(string,&timex);
  writetimedate(string,&timex);
  printf("\n%s\n",string);
 }
} */



void getdaysec(arctime * timenow,int * day,int * secs)
{
 os_regset    rx;
 os_error   * err;
 int          block[9];
 unsigned int th;
 unsigned int tx;
 int          current;

 rx.r[0]=-1;
 rx.r[1]=(int)(&timenow->lo);
 rx.r[2]=(int)block;

 err=os_swix(Territory_ConvertTimeToOrdinals,&rx);
 if(err)
 {
  th=tx=(timenow->hi<<24)|(timenow->lo>>8);  /* cs/256 */
  tx/=(3600*24*100)>>8;                    /* tx==days */

  *day=tx % 7;
  current=th-tx*((3600*24*100)>>8);
  *secs=(current*256)/100;
 }
 else
 {
  *day=(block[7]+5) % 7;          /* day 0 is Sat goes to day 0 is Mon */
  *secs=block[1]+block[2]*60+block[3]*3600;
 }
}


