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

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/datetime.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>

#include <Memory.h>

#define VERSION "1.1"

UBYTE *ver="$VER: CrashAnnounce "VERSION" ("__COMMODORE_DATE__")";

jbNewList(struct jbList *list);
jbAddNode(struct jbList *list, struct jbNode *node);
jbFreeList(struct jbList *list,struct jbNode *firstnode,ULONG sizenode);

struct jbList AnnounceList;

struct AnnounceNode
{
   struct StatsNode *Next;
   UBYTE Tagname[80];
   struct Node4D Aka;
};

#define STATSFILE    0
#define GROUP        1

ULONG argarray[]={NULL,NULL,NULL};
UBYTE *argstr="STATSFILE/A,GROUP";

BOOL brk,nomem;

struct DateStamp LastAnnounce[27];

int Compare4D(struct Node4D *node1,struct Node4D *node2)
{
   if(node1->Zone!=0 && node2->Zone!=0)
   {
      if(node1->Zone > node2->Zone) return(1);
      if(node1->Zone < node2->Zone) return(-1);
   }

   if(node1->Net  > node2->Net) return(1);
   if(node1->Net  < node2->Net) return(-1);

   if(node1->Node > node2->Node) return(1);
   if(node1->Node < node2->Node) return(-1);

   if(node1->Point > node2->Point) return(1);
   if(node1->Point < node2->Point) return(-1);

   return(0);
}

Copy4D(struct Node4D *node1,struct Node4D *node2)
{
   node1->Zone=node2->Zone;
   node1->Net=node2->Net;
   node1->Node=node2->Node;
   node1->Point=node2->Point;
}

int CompareNodes(struct AnnounceNode **s1, struct AnnounceNode **s2)
{
   return(Compare4D(&(*s1)->Aka,&(*s2)->Aka));
}

int CompareDateStamp(struct DateStamp *ds1,struct DateStamp *ds2)
{
   if(ds1->ds_Days > ds2->ds_Days)  return(1);
   if(ds1->ds_Days < ds2->ds_Days)  return(-1);

   if(ds1->ds_Minute > ds2->ds_Minute)  return(1);
   if(ds1->ds_Minute < ds2->ds_Minute)  return(-1);

   if(ds1->ds_Tick > ds2->ds_Tick)  return(1);
   if(ds1->ds_Tick < ds2->ds_Tick)  return(-1);

   return(0);
}

SortNodes(struct jbList *list)
{
   ULONG nc,alloc;
   struct AnnounceNode *an,*buf,**work;

   nc=0;

   for(an=list->First;an;an=an->Next)
      nc++;

   if(nc==0)
      return;

   alloc=nc*4;

   if(!(buf=(struct StatsNode **)AllocMem(alloc,MEMF_ANY)))
   {
      nomem=TRUE;
      return;
   }

   work=buf;

   for(an=list->First;an;an=an->Next)
      *work++=an;

   qsort(buf,nc,4,CompareNodes);

   jbNewList(list);

   for(work=buf;nc--;)
      jbAddNode(list,(struct jbNode *)*work++);

   FreeMem(buf,alloc);
}

void smallsprintf(UBYTE *buffer,UBYTE *ctl,...)
{
   va_list args;

   va_start(args, ctl);
   RawDoFmt(ctl,args,(void (*))"\x16\xc0\x4e\x75",buffer);
   Printf(""); /* Appears to be a bug in DICE */
   va_end(args);
   return;
}

BOOL CheckFlags(UBYTE group,UBYTE *node)
{
   UBYTE c;

   for(c=0;c<strlen(node);c++)
   {
      if(group==ToUpper(node[c]))
         return(TRUE);
    }

   return(FALSE);
}

#define STATS_IDENTIFIER   "CST2"

_main()
{
   BPTR fh;
   UBYTE buf[200];
   ULONG num,c;
   struct DiskAreaStats dastat;
   struct AnnounceNode *an;
   struct Node4D LastAka;
   struct RDArgs *rdargs;
   ULONG DayStatsWritten;
   int result;
   
   if(!(rdargs=(struct RDArgs *)ReadArgs(argstr,argarray,NULL)))
   {
      PrintFault(IoErr(),NULL);
      _exit(10);
   }

   strcpy(buf,(UBYTE *)argarray[STATSFILE]);
   strcat(buf,".lastannounce");

   if(fh=Open(buf,MODE_OLDFILE))
   {
      Read(fh,&LastAnnounce[0],sizeof(struct DateStamp)*27);
      Close(fh);
   }

   if(!(fh=Open((UBYTE *)argarray[STATSFILE],MODE_OLDFILE)))
   {
      Printf("Error opening %s\n",(long)argarray[STATSFILE]);
      FreeArgs(rdargs);
      _exit(10);
   }

   Read(fh,buf,4);
   buf[4]=0;

   if(strcmp(buf,STATS_IDENTIFIER)!=0)
   {
      Printf("Unknown format of stats file\n");
      FreeArgs(rdargs);
      Close(fh);
      return;
   }

   Read(fh,&DayStatsWritten,4);

   brk=FALSE;
   nomem=FALSE;

   jbNewList(&AnnounceList);

   Read(fh,&num,4);
   c=0;

   result=5;

   while(c<num && Read(fh,&dastat,sizeof(struct DiskAreaStats))==sizeof(struct DiskAreaStats))
   {
      int group;

      if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      {
         brk=TRUE;
         break;
      }

      if(!argarray[GROUP] || CheckFlags(dastat.Group,(UBYTE *)argarray[GROUP]))
      {
         group=dastat.Group;
         if(group) group=group-'A'+1;

         if(dastat.FirstTime.ds_Days != 0 && CompareDateStamp(&dastat.FirstTime,&LastAnnounce[group]) == 1)
         {
            if(!(an=AllocMem(sizeof(struct AnnounceNode),MEMF_ANY)))
            {
               nomem=TRUE;
               break;
            }

            jbAddNode(&AnnounceList,(struct jbNode *)an);
            strcpy(an->Tagname,dastat.Tagname);
            Copy4D(&an->Aka,&dastat.Aka);
            result=0;
         }
      }

      c++;
   }

   Close(fh);

   SortNodes(&AnnounceList);

   LastAka.Zone=0;
   LastAka.Net=0;
   LastAka.Node=0;
   LastAka.Point=0;

   for(an=AnnounceList.First;an && !brk;an=an->Next)
   {
      if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      {
         brk=TRUE;
         break;
      }

      if(Compare4D(&LastAka,&an->Aka)!=0)
      {
         Printf("\nNew areas at %lu:%lu/%lu.%lu\n\n",
            an->Aka.Zone,
            an->Aka.Net,
            an->Aka.Node,
            an->Aka.Point);
      }

      Printf("%s\n",an->Tagname);
      Copy4D(&LastAka,&an->Aka);
   }

   if(brk)
      PutStr("*** Break\n");

   else if(nomem)
      PutStr("Out of memory!\n");

   else
   {
      DateStamp(&LastAnnounce[0]);

      for(c=0;c<26;c++)
         if(!argarray[GROUP] || CheckFlags('A'+c,(UBYTE *)argarray[GROUP]))
            DateStamp(&LastAnnounce[c+1]);

      strcpy(buf,(UBYTE *)argarray[STATSFILE]);
      strcat(buf,".lastannounce");

      if(fh=Open(buf,MODE_NEWFILE))
      {
         Write(fh,&LastAnnounce[0],sizeof(struct DateStamp)*27);
         Close(fh);
      }
      else
      {
         Printf("Unable to open %s for writing",buf);
      }
   }

   FreeArgs(rdargs);

   jbFreeList(&AnnounceList,AnnounceList.First,sizeof(struct AnnounceNode));

   if(nomem)
      _exit(20);

   else
      _exit(result);
}


