/*
 *    MSClock.c        © by Martin Steppler 12.02.91
 *
 *    Yet another clock utility for use with L:MSClock-Handler
 */

// includes

#include <stdio.h>
#include <libraries/dos.h>
#include <devices/timer.h>
#include <devices/input.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <exec/exec.h>
#include <functions.h>

//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"
#define WriteStdOut(str) Write(StdOut, str, (LONG)strlen(str))

#define TIME_WIDTH         80
#define DATE_WIDTH         112
#define ONLINE_WIDTH       80
#define MEM_WIDTH          152
#define FRONTBACKGAD_WIDTH 62

// prototypes

long Chk_Abort() { return(0); }
void main(int, char **);
int GetWidth(int DefFlag);
int GetOverscan(void);

// globals

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
};

struct IntuitionBase *IntuitionBase;
struct DosLibrary    *DosBase;
struct TheClock      *TheClock;

// here we go ...

void
main(argc, argv)
int argc;
char *argv[];
{
   register struct Process *ThatsMe = (struct Process *)FindTask(NULL);
   int DefFlag = 39; // display time, date, online time and mem
   int i, quit=0, help=0;
   BPTR StdOut = (BPTR)Open("*", MODE_OLDFILE);


      // open libraries

   if(IntuitionBase = OpenLibrary("intuition.library",0)) {
      if(DosBase = OpenLibrary("dos.library",0)) {

         // Is the TheClock structure anywhere?

         if(TheClock = (struct TheClock *)FindPort(PORTNAME)) DefFlag = TheClock->Flags;
         for (i = 1; i < argc; i++) {
            if(!strcmp(argv[i], "quit") || !strcmp(argv[i], "-q")) {
               quit = 1;
               break;
            }
            else if(!strcmp(argv[i], "-t")) { DefFlag = (DefFlag &  1) ? (DefFlag & 62):(DefFlag |  1); }
            else if(!strcmp(argv[i], "-d")) { DefFlag = (DefFlag &  2) ? (DefFlag & 61):(DefFlag |  2); }
            else if(!strcmp(argv[i], "-m")) { DefFlag = (DefFlag &  4) ? (DefFlag & 59):(DefFlag |  4); }
            else if(!strcmp(argv[i], "-e")) { DefFlag = (DefFlag &  8) ? (DefFlag & 55):(DefFlag |  8); }
            else if(!strcmp(argv[i], "-r")) { DefFlag = (DefFlag & 16) ? (DefFlag & 47):(DefFlag | 16); }
            else if(!strcmp(argv[i], "-o")) { DefFlag = (DefFlag & 32) ? (DefFlag & 31):(DefFlag | 32); }
            else { help = 1; break; }
         }
         if(help && StdOut) {
             WriteStdOut("\33[1mMSClock V1.3\33[0m © 12.02.91 by Martin Steppler\n");
             WriteStdOut("USAGE:  MSClock [-t] [-d] [-m] [-e] [-r] [-q] [quit]\n");
             WriteStdOut("        -t    time   off/on                default: on\n");
             WriteStdOut("        -d    date   off/on                default: on\n");
             WriteStdOut("        -m    memory off/on                default: on\n");
             WriteStdOut("        -o    online time off/on           default: on\n");
             WriteStdOut("        -e    English weekdays on/off      default: German on\n");
             WriteStdOut("        -r    reverse date display on/off  default: off\n");
             WriteStdOut("        -q    quit MSClock\n");
         }
         else if(!TheClock && !quit) {

                     // No, then Create Process

            if(TheClock = (struct TheClock *)AllocMem(sizeof(struct TheClock),MEMF_PUBLIC | MEMF_CLEAR)) {

                     // Dummy MessagePort.

               TheClock -> Port . mp_Flags         = PA_IGNORE;
               TheClock -> Port . mp_Node . ln_Pri = 0;
               TheClock -> Port . mp_Node . ln_Type= NT_MSGPORT;
               TheClock -> Port . mp_Node . ln_Name= AllocMem(sizeof(PORTNAME),MEMF_PUBLIC);
               TheClock -> Child                   = NULL;
               TheClock -> Father                  = (struct Task *)ThatsMe;
               TheClock -> SegSize                 = sizeof(struct TheClock);
               TheClock -> Width                   = GetWidth(DefFlag);
               TheClock -> LeftEdge                = GetOverscan() - TheClock->Width;
               TheClock -> Online                  = FALSE;
               TheClock -> Flags                   = DefFlag;
               TheClock -> FlagsBackup             = DefFlag;

                     // Init port.

               strcpy(TheClock -> Port . mp_Node . ln_Name,PORTNAME);
               NewList(&TheClock -> Port . mp_MsgList);

                     // Load the handler code.

               if(!(TheClock -> Segment = LoadSeg("MSClock-Handler")))
                  TheClock -> Segment = LoadSeg("L:MSClock-Handler");
               if(!TheClock -> Segment)
               {
                  FreeMem(TheClock -> Port . mp_Node . ln_Name,sizeof(PORTNAME));
                  FreeMem(TheClock,TheClock -> SegSize);
                  if(StdOut)  WriteStdOut("Installation of \33[1mMartin Steppler's Clock\33[0m failed. Don't panic!\n");
               }
               else
               {
                     // Install the port and start the handler.

                  AddPort(&TheClock -> Port);
                  CreateProc("Martin's Clock", 5,TheClock -> Segment,4096);

                     // Wait for child task to ring back...

                  Wait(CHILD_READY);
                  if(!TheClock -> Child)  // failed
                  {
                     RemPort(&TheClock -> Port);
                     FreeMem(TheClock -> Port . mp_Node . ln_Name,sizeof(PORTNAME));
                     if(TheClock -> Segment) UnLoadSeg(TheClock -> Segment);
                     FreeMem(TheClock,TheClock -> SegSize);
                     if(StdOut)  WriteStdOut("Installation of \33[1mMartin Steppler's Clock\33[0m failed. Don't panic!\n");
                  }
                  else             // Yeah, it works
                     if(StdOut)  WriteStdOut("It is my pleasure to install \33[1mMartin Steppler's Clock\33[0m for you!\n");
               }
            }
         }
         else if(TheClock && quit) {
            TheClock -> Father = (struct Task *)ThatsMe;
            Signal(TheClock -> Child,SIG_CLOSE);
            Wait(CHILD_READY);

               // Remove port and associated data.

            RemPort(&TheClock -> Port);
            FreeMem(TheClock -> Port . mp_Node . ln_Name,sizeof(PORTNAME));
            if(TheClock -> Segment) UnLoadSeg(TheClock -> Segment);
            FreeMem(TheClock,TheClock -> SegSize);
            if(StdOut) {
               WriteStdOut("It is my satisfaction to close \33[1mMartin Steppler's Clock\33[0m again\n");
               WriteStdOut("with the knowledge of a job well done!\n");
            }
         }
         else if(TheClock) {

            // store changes and signal child

            TheClock->FlagsBackup = DefFlag;
            TheClock->Width = GetWidth(DefFlag);
            TheClock->LeftEdge = GetOverscan() - TheClock->Width;
            TheClock -> Father = (struct Task *)ThatsMe;
            Signal(TheClock -> Child,SIG_CHANGE);
            Wait(CHILD_READY);
         }
      }
   }
   if(StdOut)          Close(StdOut);
   if(IntuitionBase)   CloseLibrary(IntuitionBase);
   if(DosBase)         CloseLibrary(DosBase);
}

// calculate width of our window

GetWidth(int DefFlag)
{
   int Width = 0;

   if(DefFlag &  1) Width+= TIME_WIDTH;
   if(DefFlag &  2) Width+= DATE_WIDTH;
   if(DefFlag &  4) Width+= MEM_WIDTH;
   if(DefFlag & 32) Width+= ONLINE_WIDTH;

   // default width

   if(!Width) Width = TIME_WIDTH;

   return(Width);
}
GetOverscan(void)
{
   register struct Screen *WBench;
   register ULONG IntuiLock;

           // Start with the first one.

   IntuiLock = LockIBase(0L);
   WBench = IntuitionBase -> FirstScreen;
   UnlockIBase(IntuiLock);

           // Scan the list...
   do
   {
           // The type we want?

      if((WBench -> Flags & SCREENTYPE) == WBENCHSCREEN)
         return(WBench -> Width - FRONTBACKGAD_WIDTH);
   }
   while(WBench = WBench -> NextScreen);

           // Failed!

   return(640 - FRONTBACKGAD_WIDTH);
}
