/*
 *    MSClock-Handler.c        (c) 12.02.91 by Martin Steppler
 */

// includes

#include <stdio.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <devices/inputevent.h>
#include <devices/printer.h>
#include <devices/timer.h>
#include <devices/input.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <exec/exec.h>
#include <hardware/cia.h>
#include <functions.h>

// prototypes

void ciao(void);

// reference to the absolute address of ciab

extern struct CIA ciab;

// defines

#define SIG_CHANGE   SIGBREAKF_CTRL_C
#define SIG_CLOSE    SIGBREAKF_CTRL_D
#define CHILD_READY  SIGBREAKF_CTRL_D
#define EOS 0
#define PORTNAME "Martin's Clock-Port"

struct TheClock
{
   struct MsgPort    Port;          // Global messageport.
   BPTR              Segment;       // Pointer to handler segment.
   LONG              SegSize;       // Size of TheClock structure.
   struct Task      *Father;        // Calling process.
   struct Task      *Child;         // Waiting process
   int               LeftEdge;      // LeftEdge of our window
   int               Width;         // Width of our window
   int               Online;        // Online flag
   int               Flags;         // display-flags
   int               FlagsBackup;   // backup of the display-flags
   int               Status;        // status-flag
};

// globals

char                  DateBuf[60];
struct TextAttr       TopazText    = { (UBYTE *)"topaz.font",8,0,0};
struct IntuiText      TextPrint    = { 0,1,JAM2,0,0,NULL,(UBYTE *)DateBuf,NULL};
struct NewWindow      ClockWindow  = { 146,1,432,8,1,0,EOS, BORDERLESS, NULL,NULL,EOS,NULL,NULL,0,0,0,0,WBENCHSCREEN};
struct Window        *Window=NULL;
struct timerequest    TimeReq;
struct MsgPort       *TimerPort=NULL;
struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
struct DosLibrary    *DosBase;
struct TheClock      *TheClock;

        /* _main():
         *
         *      Modified Aztec C startup-routine, no CLI parsing,
         *      no Workbench parsing, absolutely nothing.
         */

long
_main()
{
   register struct Process *ThatsMe = (struct Process *)FindTask(NULL);
   register ULONG SignalSet;
   char TempBuf[60];
   char *Days[14]={ "Son","Mon","Die","Mit","Don","Fre","Sam",
                    "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
   struct DateStamp Date;
   long n,eng,Month,Day,Year,chip_free,fast_free,hh=0,mm=0,ss=0,lastsec=-1;
   int i;

      // If somebody called us from CLI...

   if(ThatsMe -> pr_CLI) return(10);

      // Is the TheClock structure anywhere?

   if(!(TheClock = (struct TheClock *)FindPort(PORTNAME))) return(10);

      // open libraries

   if(!(IntuitionBase = OpenLibrary("intuition.library",0))) {
      Signal(TheClock -> Father, CHILD_READY);
      return(20);
   }
   if(!(GfxBase       = OpenLibrary("graphics.library",0))) {
      CloseLibrary(IntuitionBase);
      Signal(TheClock -> Father, CHILD_READY);
      return(20);
   }
   if(!(DosBase       = OpenLibrary("dos.library",0))) {
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      Signal(TheClock -> Father, CHILD_READY);
      return(20);
   }

   if(TimerPort=(struct MsgPort *) CreatePort("Timer Port",0)) {
      if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimeReq,0)==(long)NULL) {
         TimeReq.tr_node.io_Message.mn_ReplyPort=TimerPort;
         TimeReq.tr_node.io_Command=TR_ADDREQUEST;
         TimeReq.tr_node.io_Flags=0;
         TimeReq.tr_node.io_Error=0;
         TimeReq.tr_time.tv_secs=0;
         TimeReq.tr_time.tv_micro=1000000;  // delay
         SendIO((struct IORequest *) &TimeReq.tr_node);
      }
      else ciao();
   }
   else ciao();

   TheClock -> Child = (struct Task *)FindTask(NULL);
   TheClock -> Status = 1;

           // Go into infinite loop waiting for signals.

   FOREVER
   {
      if(TheClock -> Status == 1) {      // switch clock on
         TheClock -> Status = 2;
         ClockWindow.LeftEdge = TheClock -> LeftEdge;
         ClockWindow.Width    = TheClock -> Width;
         if(Window=(struct Window *) OpenWindow(&ClockWindow)) {
            if(Window->IFont->tf_YSize>8) TextPrint.ITextFont=&TopazText;
            TheClock->Status = 0;
         }
         else ciao();

           // Tell father to finish.

         Signal(TheClock -> Father, CHILD_READY);
      }
      if(!TheClock->Status) {     // show mem, date, online-time and/or time
         chip_free = AvailMem(MEMF_CHIP) >> 10;
         fast_free = AvailMem(MEMF_FAST) >> 10;
         DateStamp((struct DateStamp *)&Date) ;
         n = Date.ds_Days - 2251;
         Year = (4 * n + 3) / 1461;
         n -= 1461 * Year / 4;
         Year += 1984;
         Month = (5 * n + 2) / 153;
         Day = n - (153 * Month + 2) / 5 + 1;
         Month += 3; n=TheClock->Flags;
         if(Month>12) { Year++; Month -= 12; }
         DateBuf[0]=EOS;
         if(n & 4) sprintf(DateBuf, "A:%-4d F:%-4d C:%-3d", chip_free+fast_free, fast_free, chip_free);
         if(n & 32) {

            // Check port a of cia b. Is there a carrier?

            if(!(ciab . ciapra & CIAF_COMCD)) // Online ?
            {
               if(!TheClock -> Online) {    // Time reset
                  hh=mm=ss=0; TheClock -> Online = TRUE;
               }

                       // Increment time counter.

               if(lastsec != Date.ds_Tick/TICKS_PER_SECOND) {
                  lastsec = Date.ds_Tick/TICKS_PER_SECOND;
                  if(++ss == 60) {
                     ss=0; if(++mm == 60) { mm=0; ++hh; }
                  }
               }
            }
            else TheClock -> Online = FALSE;
            sprintf(TempBuf, "  %02ld:%02ld:%02ld", hh, mm, ss);
            strcat(DateBuf,TempBuf);
         }
         if(n & 2) {
            eng = (n & 8) ? 7:0;
            if(n & 16) sprintf(TempBuf, "  %s %02ld-%02ld-%02ld", Days[(Day + Year + (Year - (Month < 3)) / 4 + 3 * Month - 2 * (Month > 2) - (Month - 1 - (Month > 8)) / 2 + 2) % 7 +eng], Month, Day, Year-1900);
            else       sprintf(TempBuf, "  %s %02ld.%02ld.%02ld", Days[(Day + Year + (Year - (Month < 3)) / 4 + 3 * Month - 2 * (Month > 2) - (Month - 1 - (Month > 8)) / 2 + 2) % 7 +eng], Day, Month, Year-1900);
            strcat(DateBuf,TempBuf);
         }
         if(n & 1) {
            sprintf(TempBuf, "  %02ld:%02ld:%02ld", Date.ds_Minute/60, Date.ds_Minute%60, Date.ds_Tick/TICKS_PER_SECOND);
            strcat(DateBuf, TempBuf);
         }
         PrintIText(Window->RPort,&TextPrint, 0,0);
      }
      SignalSet = Wait(SIG_CLOSE | SIG_CHANGE | (1 << TimerPort->mp_SigBit));
      if(SignalSet & SIG_CLOSE) {
         ciao();
         CloseLibrary(IntuitionBase);
         CloseLibrary(GfxBase);
         CloseLibrary(DosBase);
         Forbid();
         Signal(TheClock -> Father, CHILD_READY);
         return(0);
      }
      else if(SignalSet & SIG_CHANGE) {
         if(Window) { CloseWindow(Window); Window = NULL; }
         TheClock->Flags = TheClock->FlagsBackup;
         TheClock->Status = 1;
      }
      if(SignalSet & (1 << TimerPort->mp_SigBit)) {
         if(GetMsg(TimerPort)) {
            TimeReq.tr_time.tv_secs=0;
            TimeReq.tr_time.tv_micro=1000000;
            SendIO((struct IORequest *) &TimeReq.tr_node);
         }
      }
   }
}
void
ciao(void)
{
   if(TimerPort) GetMsg(TimerPort);
   if(TimeReq.tr_node.io_Message.mn_ReplyPort) CloseDevice((struct IORequest *)&TimeReq);
   if(TimerPort) { DeletePort(TimerPort); TimerPort = NULL; }
   if(Window) { CloseWindow(Window); Window = NULL; }
}
