/* MSCalendar ! A little FreeWare-Utility from Markus Stipp
   (c) Copyright 1991 by Markus Stipp, All Rights reserved.

   $Revision: 1.10 $

   $Author: mstipp $
   $Date: 91/06/07 13:33:36 $

   $Log:	cal.c,v $
 * Revision 1.10  91/06/07  13:33:36  mstipp
 *       Bug with -f fixed (seems to work now)
 *       Now uses RawKeyConvert() for Keys
 * 
 * Revision 1.9  91/05/30  18:03:11  mstipp
 *       V1.08 always switched to current date if Clockwindow was open
 *

*/

/*---------------------------------------------------------------------*/
/* Prototypes / Structures / Variables etc.                            */
/*---------------------------------------------------------------------*/

#include "cal.h"

void Today(void);
void PrintClock(void);
void PrintCal(int month, int year);
void InitWindow(void);
void DrawLine(int x1, int y1, int x2, int y2);
void HandleKeys(USHORT code,USHORT qual,APTR address);
void Iconify(void);
void UnIconify(void);
int  DOW(int day, int month, int year);
void CleanUp(int error, char* Message);
TM   *GetTime(void);
int  atoi(char *string);
int  strlen(char *string);
void exit(int error);
void InitMain(void);
void GetVals(void);
void CheckVals(void);
void DoMain(void);

static IBASE   *IntuitionBase = NULL;
static GFXBASE *GfxBase = NULL;
struct Library *IconBase = NULL;
struct ConsoleDevice *ConsoleDevice = NULL;
struct IOStdReq ioreq;

CAL     cal;
TM      *tp;
MSGP    *timeport;
TR      tr;
BYTE    BHeight;
UWORD   FHeight,FWidth,FWidth2,BLine,BLine2;
BOOL    gadget,winactive,tdevice,current = FALSE;
TF      *FontBuf;
SCR     scrbuf;

#ifdef GERMAN
char   *monthname[] =
  {
    "Januar   ","Februar  ","März     ","April    ","Mai      ",
    "Juni     ","Juli     ","August   ","September","Oktober  ",
    "November ","Dezember "
  };
#else
char   *monthname[] =
  {
    "January  ","February ","March    ","April    ","May      ",
    "June     ","July     ","August   ","September","October  ",
    "November ","December "
  };
#endif

USHORT daytab[] =
  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


/*---------------------------------------------------------------------*/
/* The main Programs !                                                 */
/*---------------------------------------------------------------------*/

/*---------------------------------------------------------------------*/
/* If started from WB                                                  */
/*---------------------------------------------------------------------*/

int wbmain(struct WBStartup *wbs)
{

/* Variables */

 struct DiskObject *dobj;
 char **toolsarray;
 char *s;
 int val;
 BPTR olddir;

 InitMain();

 IconBase = OpenLibrary("icon.library",33);
 if(IconBase == NULL)
    CleanUp(RETURN_FAIL,"Can't open Icon.Library");

 olddir = CurrentDir(wbs->sm_ArgList->wa_Lock);
 if(dobj= (struct DiskObject *) GetDiskObject(wbs->sm_ArgList->wa_Name));
 {
    toolsarray = (char **)dobj->do_ToolTypes;
    if(s=(char *)FindToolType(toolsarray,"FLAGS"))
    {
       if(MatchToolValue(s,"BEEP"))
          cal.Beep = TRUE;
       if(MatchToolValue(s,"FRONT"))
          cal.Front = TRUE;
       if(MatchToolValue(s,"ICONIFY"))
          cal.Iconify = TRUE;
    }
    if(s=(char *)FindToolType(toolsarray,"XPOS"))
    {
       val = atoi(s);
       cal.xpos = val;
    }
    if(s=(char *)FindToolType(toolsarray,"YPOS"))
    {
       val = atoi(s);
       cal.ypos = val;
    }
    if(s=(char *)FindToolType(toolsarray,"IXPOS"))
    {
       val = atoi(s);
       cal.ixpos = val;
    }
    if(s=(char *)FindToolType(toolsarray,"IYPOS"))
    {
       val = atoi(s);
       cal.iypos = val;
    }
    FreeDiskObject(dobj);

 }
 CurrentDir(olddir);

 CloseLibrary(IconBase);

 DoMain();
 CleanUp(0,NULL);

} /* wbmain */

/*---------------------------------------------------------------------*/
/* If started from CLI                                                 */
/*---------------------------------------------------------------------*/

int main(int ac, char **av)
{

 /* Variables */

 char   *ptr;
 int    i;
 LONG   val;

 InitMain();

/***** Parse the given arguments *****/

 for(i = 1; i < ac; ++i)
 {
    ptr = av[i];
    val = atoi(ptr+2);
    if(*ptr != '-')
       goto def;

    switch (ptr[1])
    {
       case 'x':
          cal.xpos = val;
          break;
       case 'y':
          cal.ypos = val;
          break;
       case 'u':
          cal.ixpos = val;
          break;
       case 'v':
          cal.iypos = val;
          break;
       case 'i':
          cal.Iconify = TRUE;
          break;
       case 'b':
          cal.Beep = TRUE;
          break;
       case 'f':
          cal.Front = TRUE;
          break;
       default:   def:
#ifdef GERMAN
          printf("\nMSCalendar V%d.%02d GERMAN, " __DATE__ "\n",RELEASE,REVISION);
          printf("(c)Copyright 1991 by Markus Stipp, All Rights Reserved\n\n");
          printf("  Usage: %s [-Option] [-Option] [...]\n\n",av[0]);
          printf("    -x###    X-Position vom Kalender (default 0)\n");
          printf("    -y###    Y-Position vom Kalender (default 0)\n");
          printf("    -u###    X-Position vom kleinen Fenster (default 0)\n");
          printf("    -v###    Y-Position vom kleinen Fenster (default 0)\n");
          printf("    -b       Bei vollen Stunden blitzen\n");
          printf("    -f       Kleines Fenster immer im Vordergrund\n");
          printf("    -i       Mit kleinem Fenster starten\n\n");
#else
          printf("\nMSCalendar V%d.%02d, " __DATE__ "\n",RELEASE,REVISION);
          printf("(c)Copyright 1991 by Markus Stipp, All Rights Reserved\n\n");
          printf("  Usage: %s [-option] [-option] [...]\n\n",av[0]);
          printf("    -x###    X-Position of the Calendar (default 0)\n");
          printf("    -y###    Y-Position of the Calendar (default 0)\n");
          printf("    -u###    X-Position of the iconified Window (default 0)\n");
          printf("    -v###    Y-Position of the iconified Window (default 0)\n");
          printf("    -b       Beep at full hours\n");
          printf("    -f       Put the iconified window always to front\n");
          printf("    -i       Start with iconified Window\n\n");
#endif
          CleanUp(0,NULL);
          break;
    } /* switch */
 }    /* for    */

 DoMain();

}           /* main */

/*---------------------------------------------------------------------*/
/* Open Libraries etc.                                                 */
/*---------------------------------------------------------------------*/

void InitMain(void)
{

 cal.Iconify = cal.Beep = cal.Front = FALSE;  /* Default for startup */

/***** Open Libraries *****/

 IntuitionBase = (IBASE *)   OpenLibrary("intuition.library",33);
 GfxBase       = (GFXBASE *) OpenLibrary("graphics.library",33);
   if (GfxBase == NULL || IntuitionBase == NULL)
       CleanUp(RETURN_FAIL,"Can't open Graphics- or Intuition.Library");

/***** Create a MessagePort for the Timer.Device *****/

 timeport = CreatePort(NULL,0);
   if(timeport == NULL)
      CleanUp(RETURN_FAIL,"Can't create Port");

/***** Open the Timer.Device *****/

 if(OpenDevice("timer.device",UNIT_MICROHZ,(IOR *) &tr,0L))
    CleanUp(RETURN_FAIL,"Can't open Timer.Device");
  tdevice = TRUE;

/***** Open Console Device for RawKeyConvert() *****/

 if(OpenDevice("console.device",-1L,(IOR *) &ioreq,0L))
    CleanUp(RETURN_FAIL,"Can't open Console.Device");
 ConsoleDevice = (struct ConsoleDevice *)ioreq.io_Device;

 cal.xpos = cal.ypos = cal.ixpos = cal.iypos = 0;

} /* InitMain */

/*---------------------------------------------------------------------*/
/* Get the Screen's data and set some Variables.                       */
/*---------------------------------------------------------------------*/

void GetVals(void)
{
 Delay(10); /* If someone changes the Font, we must wait a bit */

 Forbid();
 if(!(GetScreenData(&scrbuf,sizeof(SCR),WBENCHSCREEN,NULL)))
    CleanUp (RETURN_FAIL,"Can't get ScreenData");
 Permit();

 FontBuf = (TF *) OpenFont(scrbuf.Font);

 BHeight        = scrbuf.BarHeight+1;
 FHeight        = GfxBase->DefaultFont->tf_YSize;
 FWidth         = GfxBase->DefaultFont->tf_XSize;
 FWidth2        = FontBuf->tf_XSize;
 BLine          = FontBuf->tf_Baseline;
 BLine2         = FHeight - GfxBase->DefaultFont->tf_Baseline;

 cal.height     = BHeight + 1 + 10*(FHeight+4);
 cal.width      = WEEKDAYLENGTH * FWidth + 14;
 cal.iheight    = BHeight-1;
 cal.iwidth     = 37*FWidth2+86;

 boxdata[2]=boxdata[4]=2*FWidth+6;
 boxdata[5]=boxdata[7]=FHeight+2;

 if(cal.height > scrbuf.Height || cal.width  > scrbuf.Width)
    CleanUp(RETURN_FAIL,"Window too big. Too big Font ?");

 if(FontBuf->tf_Flags & FPF_PROPORTIONAL)
    cal.iwidth = 50;
 else
 {
    if(cal.iwidth > scrbuf.Width)
       CleanUp(RETURN_FAIL,"Iconified Window too big !");
 }

 todayswitch.LeftEdge = cal.width/2+1;
 todayswitch.TopEdge  = BHeight + 8*(FHeight +4);
 todayswitch.Width    = cal.width - (cal.width/2)-5;
 todayswitch.Height   = FHeight +3;

 CheckVals();

} /* GetVals */

/*---------------------------------------------------------------------*/
/* Are the Values correct ?                                            */
/*---------------------------------------------------------------------*/

void CheckVals(void)
{

 if(cal.xpos + cal.width > scrbuf.Width)
    cal.xpos = scrbuf.Width - cal.width;

 if(cal.ypos + cal.height > scrbuf.Height)
    cal.ypos = scrbuf.Height - cal.height;

 if(cal.ixpos + cal.iwidth > scrbuf.Width)
    cal.ixpos = scrbuf.Width - cal.iwidth;

 if(cal.iypos + cal.iheight > scrbuf.Height)
    cal.iypos = scrbuf.Height - cal.iheight;

}

/*---------------------------------------------------------------------*/
/* The really main part. Message-Handling etc.                         */
/*---------------------------------------------------------------------*/

void DoMain(void)
{

 BOOL   done = FALSE;
 ULONG  class,signal,isig,tsig;
 USHORT code,qual;
 IMSG   *message;
 MSG    *tmsg;
 APTR   *address;

/***** Open the Window, now *****/

  Today();

  if(cal.Iconify)
     Iconify();
  else
     UnIconify();

/***** Go to sleep and wait for a Message for me *****/

/* Set Values for the Timer.Device first */

 tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
 tr.tr_node.io_Message.mn_Node.ln_Pri = 0;
 tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
 tr.tr_node.io_Message.mn_ReplyPort = timeport;
 tr.tr_node.io_Command = TR_ADDREQUEST;
 tr.tr_time.tv_secs = 0;
 tr.tr_time.tv_micro = 500;

 SendIO((IOR *) &tr);

 isig = 1 << cal.calwin->UserPort->mp_SigBit;
 tsig = 1 << timeport->mp_SigBit;

 while (done == FALSE)
 {
    signal = Wait( isig | tsig );

    if(signal & tsig)  /* If Timer-Signal */
    {
       while(tmsg = (MSG *) GetMsg(timeport));
       {
          if((cal.Front && cal.Iconify && !(cal.rp->Layer == cal.rp->Layer->LayerInfo->top_layer)))
          {
             WindowToFront(cal.calwin);
             RefreshWindowFrame(cal.calwin);
          }
          PrintClock();
          tr.tr_node.io_Command = TR_GETSYSTIME;
          DoIO((IOR *) &tr);

          tr.tr_node.io_Command = TR_ADDREQUEST;
          tr.tr_time.tv_secs = 0;
          tr.tr_time.tv_micro = 1000000-tr.tr_time.tv_micro+2;
          SendIO((IOR *) &tr);
       }
    }

    if(signal & isig)  /* If Intuition-Signal */
    {
       while(message = (IMSG *) GetMsg(cal.calwin->UserPort))
       {
          class = message->Class;
          code  = message->Code;
          qual  = message->Qualifier;
          address = message->IAddress;

          ReplyMsg((MSG *) message);

          switch (class)
          {
           case CLOSEWINDOW:
              AbortIO((IOR *)&tr);
              WaitIO((IOR *)&tr);
              done = TRUE;
              break;
           case RAWKEY:
              ModifyIDCMP(cal.calwin,cal.calwin->IDCMPFlags & ~RAWKEY);
              HandleKeys(code,qual,address);
              ModifyIDCMP(cal.calwin,cal.calwin->IDCMPFlags | RAWKEY);
              break;
           case MOUSEBUTTONS:
              switch(code)
              {
               case MENUUP:
                 if(cal.Iconify)
                    UnIconify();
                 else
                    Iconify();
                 break;
               case SELECTUP:
                 gadget = FALSE;
                 break;
              }
              break;
           case ACTIVEWINDOW:
              winactive = TRUE;
              PrintClock();
              break;
           case INACTIVEWINDOW:
              winactive = FALSE;
              PrintClock();
              break;
           case GADGETDOWN:
              gadget = TRUE;
              break;
           case GADGETUP:
              Today();
              PrintCal(cal.cald.m,cal.cald.y);
              gadget = FALSE;
              break;
           default:
              break;

          } /* switch          */
       }    /* while (message) */
    }       /* if (signal)     */
 }          /* while (done)    */

 CleanUp(0,NULL);

} /* DoMain */

/*---------------------------------------------------------------------*/
/* Close the Cal-Window and open the iconified One                     */
/*---------------------------------------------------------------------*/

void Iconify(void)
{
  int winwi;

  GetVals();

  calwin_data.LeftEdge    = cal.ixpos;
  calwin_data.TopEdge     = cal.iypos;
  calwin_data.Width       = cal.iwidth;
  calwin_data.Height      = cal.iheight;
  calwin_data.Flags      &= ~(ACTIVATE);
  calwin_data.IDCMPFlags &= ~RAWKEY;
  calwin_data.IDCMPFlags |= (ACTIVEWINDOW|INACTIVEWINDOW);

  winactive = FALSE;

  cal.Iconify = TRUE;

  if(cal.calwin)
  {
     cal.xpos = cal.calwin->LeftEdge;
     cal.ypos = cal.calwin->TopEdge;
     CloseWindow(cal.calwin);
  }

  cal.calwin = (WIN *) OpenWindow(&calwin_data);
               if(cal.calwin == NULL)
                  CleanUp(RETURN_FAIL,"Can't open Window");

  cal.rp = cal.calwin->RPort;                /* Set the RastPort */

  if(FontBuf->tf_Flags & FPF_PROPORTIONAL)
  {
     SetFont(cal.rp,FontBuf);

#ifdef GERMAN
     winwi = (86+TextLength(cal.rp," Chip: 000 Fast: 0000  Zeit:00:00:00 ",37));
#else
     winwi = (86+TextLength(cal.rp," Chip: 000 Fast: 0000  Time:00:00:00 ",37));
#endif

     if(winwi > scrbuf.Width)
        CleanUp(RETURN_FAIL,"Iconified Window too big !");
     if((winwi + cal.calwin->LeftEdge) > scrbuf.Width)
        MoveWindow(cal.calwin,scrbuf.Width - (winwi + cal.calwin->LeftEdge),0);
     SizeWindow(cal.calwin,winwi - cal.calwin->Width,0);
  }
  SetFont(cal.rp,GfxBase->DefaultFont);

  PrintClock();

}

/*---------------------------------------------------------------------*/
/* Close the iconified Window and open the Cal-Window                  */
/*---------------------------------------------------------------------*/

void UnIconify(void)
{

  GetVals();

  calwin_data.LeftEdge    = cal.xpos;
  calwin_data.TopEdge     = cal.ypos;
  calwin_data.Width       = cal.width;
  calwin_data.Height      = cal.height;
  calwin_data.Flags      |= (ACTIVATE);
  calwin_data.IDCMPFlags |= RAWKEY;
  calwin_data.IDCMPFlags &= ~(ACTIVEWINDOW|INACTIVEWINDOW);
  winactive = TRUE;

  cal.Iconify = FALSE;

  if(cal.calwin)
  {
     cal.ixpos = cal.calwin->LeftEdge;
     cal.iypos  = cal.calwin->TopEdge;
     CloseWindow(cal.calwin);
  }

  cal.calwin = (WIN *) OpenWindow(&calwin_data);
               if (cal.calwin == NULL)
                   CleanUp(RETURN_FAIL,"Can't open Window");

  cal.rp = cal.calwin->RPort;                /* Set the RastPort */

  InitWindow();
}

/*---------------------------------------------------------------------*/
/* This Procedure draws the Window-Background                          */
/*---------------------------------------------------------------------*/

void InitWindow(void)
{
  SetFont(cal.rp,GfxBase->DefaultFont);

  SetBPen(cal.rp,1);
  SetAPen(cal.rp,1);
  RectFill(cal.rp,cal.calwin->BorderLeft,BHeight,cal.calwin->Width - (cal.calwin->BorderRight+1),BHeight + 10* (FHeight +4) - cal.calwin->BorderBottom);
  SetAPen(cal.rp,0);
  DrawLine(cal.calwin->BorderLeft,BHeight + (FHeight +4)-1,cal.calwin->Width-(cal.calwin->BorderRight+1), BHeight + (FHeight +4)-1);
  DrawLine(cal.calwin->BorderLeft,BHeight + 2*(FHeight +4)-1,cal.calwin->Width-(cal.calwin->BorderRight+1), BHeight + 2*(FHeight +4)-1);
  DrawLine(cal.calwin->BorderLeft,BHeight + 8*(FHeight +4)-1,cal.calwin->Width-(cal.calwin->BorderRight+1), BHeight + 8*(FHeight +4)-1);
  DrawLine(cal.calwin->BorderLeft,BHeight + 9*(FHeight +4)-1,cal.calwin->Width-(cal.calwin->BorderRight+1), BHeight + 9*(FHeight +4)-1);
  DrawLine(cal.calwin->Width/2,BHeight + 8*(FHeight +4)-2,cal.calwin->Width/2, BHeight + 10*(FHeight +4) -2);

  Move(cal.rp,cal.calwin->BorderLeft+4,BHeight + 2*(FHeight+4) - BLine2-2);
  Text(cal.rp,WEEKDAYS,WEEKDAYLENGTH);

  PrintCal(cal.cald.m,cal.cald.y);
  PrintClock();
}

/*---------------------------------------------------------------------*/
/* This Procedure prints out the Calendar-entries. It takes the month  */
/* and the year as arguments.                                          */
/* month: 0-11                                                         */
/* year : 1901-2099                                                    */
/*---------------------------------------------------------------------*/

void PrintCal(int month, int year)
{
  char  buffer[5];
  int leap,i,j;
  int weekday = DOW(1,month,year);

  SetAPen(cal.rp,1);
  RectFill(cal.rp,cal.calwin->BorderLeft,BHeight + 2*(FHeight+4),cal.calwin->Width - (cal.calwin->BorderRight+1),BHeight + 8*(FHeight+4)-2);
  SetAPen(cal.rp,2);
  Move(cal.rp,50,BHeight+(FHeight+4)-BLine2-2);
  Text(cal.rp,monthname[month],9);
  sprintf(buffer,"%d",year);
  Move(cal.rp,30+calwin_data.Width/2,BHeight+(FHeight+4)-BLine2-2);
  Text(cal.rp,buffer,strlen(buffer));

  leap = year%4 == 0 && year%100 !=0 || year%400 == 0;
  if(leap == 1)
     daytab[1] = 29;

  if(year == tp->tm_year+1900 && month == tp->tm_mon)
     current = TRUE;
  else
     current = FALSE;

  for(i = 1, j = 3; i <= daytab[month]; i++)
  {
    if(weekday == 7)
    {
       weekday = 0;
       j++;
    }
    sprintf(buffer,"%2d",i);
    if(weekday == 5)
       SetAPen(cal.rp,0);
    if(weekday == 6)
       SetAPen(cal.rp,3);
    Move(cal.rp,cal.calwin->BorderLeft+8+weekday*(4*FWidth), BHeight+j*(FHeight+4)-BLine2-2);
    Text(cal.rp,buffer,2);
    if(tp->tm_mday == i && current)
       DrawBorder(cal.rp,&dayborder,7+weekday*(4*FWidth),BHeight+(j-1)*(FHeight+4));
    weekday++;
    SetAPen(cal.rp,2);
  }
  daytab[1] = 28;
}

/*---------------------------------------------------------------------*/
/* This Procedure prints the Clock and the free Memory                 */
/*---------------------------------------------------------------------*/

void PrintClock(void)
{
  ULONG  Chip,Fast;
  char buffer[37];
  TF  *oldfont;

  Chip = (AvailMem(MEMF_CHIP)/1024);
  Fast = (AvailMem(MEMF_FAST)/1024);

  tp = GetTime();
  if(tp->tm_sec == 0 && tp->tm_min == 0 && cal.Beep)
     DisplayBeep(cal.calwin->WScreen);

  if((cal.cald.d != tp->tm_mday || cal.cald.m != tp->tm_mon || cal.cald.y != tp->tm_year+1900) && current)
  {
     cal.cald.d = tp->tm_mday;
     cal.cald.m = tp->tm_mon;
     cal.cald.y = tp->tm_year+1900;
     if(!cal.Iconify)
        PrintCal(cal.cald.m,cal.cald.y);
  }


  if(cal.Iconify)
  {
     oldfont = cal.calwin->RPort->Font;
     SetAPen(cal.rp,1);
     if(winactive)
        SetBPen(cal.rp,3);
     else
        SetBPen(cal.rp,0);

     SetFont(cal.rp,FontBuf);

#ifdef GERMAN
     sprintf(buffer," Chip:%4d Fast:%5d  Zeit:%2d:%02d:%02d ",Chip,Fast,tp->tm_hour,tp->tm_min,tp->tm_sec);
#else
     sprintf(buffer," Chip:%4d Fast:%5d  Time:%2d:%02d:%02d ",Chip,Fast,tp->tm_hour,tp->tm_min,tp->tm_sec);
#endif

     Move(cal.rp,30,BLine+1);
     Text(cal.rp,buffer,37);
     SetFont(cal.rp,oldfont);
  }
  else
  {
     SetAPen(cal.rp,0);

     sprintf(buffer,"%02d:%02d:%02d",tp->tm_hour, tp->tm_min, tp->tm_sec);
     Move(cal.rp,(calwin_data.Width/2-8*FWidth)/2,BHeight+9*(FHeight+4)-BLine2-2);
     Text(cal.rp,buffer,8);

     if(!gadget)
     {
        sprintf(buffer,"%02d-%02d-%04d",tp->tm_mday,tp->tm_mon+1,tp->tm_year+1900);
        Move(cal.rp,(calwin_data.Width/2-10*FWidth)/2+calwin_data.Width/2,BHeight+9*(FHeight+4)-BLine2-2);
        Text(cal.rp,buffer,10);
     }

     sprintf(buffer,"Chip: %5d",Chip);
     Move(cal.rp,10,BHeight+10*(FHeight+4)-BLine2-2);
     Text(cal.rp,buffer,11);

     sprintf(buffer,"Fast: %5d",Fast);
     Move(cal.rp,calwin_data.Width/2+10,BHeight+10*(FHeight+4)-BLine2-2);
     Text(cal.rp,buffer,11);
  } /* ifelse Iconify */

}

/*---------------------------------------------------------------------*/
/* This Procedure draws a Line with the given coords                   */
/*---------------------------------------------------------------------*/

void DrawLine(int x1, int y1, int x2, int y2)
{
  Move(cal.rp, x1,y1);
  Draw(cal.rp, x2,y2);
}

/*---------------------------------------------------------------------*/
/* This Function gets the current date.                                */
/*---------------------------------------------------------------------*/

TM *GetTime(void)
{
  time_t t = time(NULL);

  return (localtime(&t));
}

/*---------------------------------------------------------------------*/
/* This Function returns the weekday of the given date.                */
/* d : 1-31                                                            */
/* m : 0-11                                                            */
/* y : 1901-2099 (other years return wrong values)                     */
/* return : 0-6 (0=monday 1=tuesday ...)                               */
/*---------------------------------------------------------------------*/

int DOW( int d, int m, int y )
{
   return (( 3*y - (7*(y+((m+1)+9)/12))/4 + (23*(m+1))/9 + d + 1 ) % 7);
}

/*---------------------------------------------------------------------*/
/* This Procedure makes the Key-Handling. It takes the Key and the     */
/* Qualifier pressed and changes the Calendar-Input                    */
/*---------------------------------------------------------------------*/

void HandleKeys(USHORT code,USHORT qual,APTR address)
{

  UBYTE buffer[1];
  int numchars;
  static struct InputEvent ievent = {NULL,IECLASS_RAWKEY,0,0,0};

  switch (code)
  {
     case RIGHT:
        if(qual == SHIFT || qual == SHIFTR)
           cal.cald.m += 3;
        else
           cal.cald.m += 1;
        if(cal.cald.m >= 12)
        {
           cal.cald.m -= 12;
           cal.cald.y++;
           if(cal.cald.y >= 2100)
              cal.cald.y -= 200;
           if(cal.cald.y <= 1900)
              cal.cald.y++;
        }
        PrintCal(cal.cald.m, cal.cald.y);
        break;
     case LEFT:
        if(qual == SHIFT || qual == SHIFTR)
           cal.cald.m -= 3;
        else
           cal.cald.m -= 1;
        if(cal.cald.m <= -1)
        {
           cal.cald.m += 12;
           cal.cald.y--;
           if(cal.cald.y <= 1900)
              cal.cald.y += 200;
           if(cal.cald.y >= 2100)
              cal.cald.y--;
        }
        PrintCal(cal.cald.m, cal.cald.y);
        break;
     case UP:
        if(qual == SHIFT || qual == SHIFTR)
           cal.cald.y += 10;
        else
           cal.cald.y += 1;
        if(cal.cald.y >= 2100)
           cal.cald.y -= 200;
        if(cal.cald.y <= 1900)
           cal.cald.y++;
        PrintCal(cal.cald.m, cal.cald.y);
        break;
     case DOWN:
        if(qual == SHIFT || qual == SHIFTR)
           cal.cald.y -= 10;
        else
           cal.cald.y -= 1;
        if(cal.cald.y <= 1900)
           cal.cald.y += 200;
        if(cal.cald.y >= 2100)
           cal.cald.y--;
        PrintCal(cal.cald.m, cal.cald.y);
        break;
     default:
        ievent.ie_Code = code;
        ievent.ie_Qualifier = qual;
        ievent.ie_position.ie_addr = *((APTR*) address);
        numchars = RawKeyConvert(&ievent,buffer,1,0L);
        if (numchars == 1)
        {
          switch(buffer[0])
          {
            case 'i':
               Iconify();
               break;
            case 't':
               Today();
               PrintCal(cal.cald.m,cal.cald.y);
               break;
            default:
               break;
          }
        }
        break;
  }
}

/*---------------------------------------------------------------------*/
/* This Procedure switches the Calendar to Today                       */
/*---------------------------------------------------------------------*/

void Today(void)
{
  tp = GetTime();
  cal.cald.d   = tp->tm_mday;
  cal.cald.m   = tp->tm_mon;
  cal.cald.y   = tp->tm_year+1900;
  current = TRUE;
}

/*---------------------------------------------------------------------*/
/* This Function cleans all up. It takes an Errorcode which will be    */
/* returned to the  CLI                                                */
/*---------------------------------------------------------------------*/

void CleanUp(int error, char *Message)
{
  if(cal.calwin)    CloseWindow(cal.calwin);
  if(GfxBase)       CloseLibrary((struct Library *)GfxBase);
  if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  if(timeport)      DeletePort(timeport);
  if(tdevice)       CloseDevice((IOR *) &tr);
  if(ConsoleDevice) CloseDevice((IOR *) &ioreq);

  if(Message)       printf("MSCal: %s\n",Message);
  exit(error);
}


