/*
 *  CLOCK.C     simple clock program
 */
#include <local/typedefs.h>
short Params[] = {
    'ST','RT', 0, 0,
    'NW','  ', 0, 8, -1, 10, 40, 20,
    'TE','XT', 0,16, 'HI','\0T','ES','T.', 0, 0, 0, 0,
    'EN','D ', 0, 0
};
#define WPOSX   8
#define WPOSY   9
#define WWIDTH  10
#define WHEIGHT 11
APTR IntuitionBase;
APTR GfxBase;
NW Nw = {
    0, 0, 0, 0, 0, 0,
    CLOSEWINDOW|REFRESHWINDOW|ACTIVEWINDOW|INACTIVEWINDOW,
    SIMPLE_REFRESH|WINDOWCLOSE|BACKDROP|RMBTRAP,
    NULL, NULL, (ubyte *)"", NULL, NULL, 4, 4, -1, -1, WBENCHSCREEN
};
short Sin[60+15] = {
      0,  27,  53,  79, 104, 128, 150, 171, 190, 207, 222, 234, 243, 250, 255,
    256, 255, 250, 243, 234, 222, 207, 190, 171, 150, 128, 104,  79,  53,  27,
      0, -27, -53, -79,-104,-128,-150,-171,-190,-207,-222,-234,-243,-250,-255,
   -256,-255,-250,-243,-234,-222,-207,-190,-171,-150,-128,-104, -79, -53, -27,
      0,  27,  53,  79, 104, 128, 150, 171, 190, 207, 222, 234, 243, 250, 255
};
#define Cos (Sin+15)
_main(ac, av)
char *av[];
{
    IOT  Iot;       /*  timer request,  1 second internals  */
    SCR  Scr;
    WIN  *Win;
    PORT TPort;     /*  port for timer request              */
    long TMask;
    long WMask;
    long error = 20;
    char notdone = 1;
    bzero(&Iot, sizeof(Iot));
    bzero(&TPort, sizeof(TPort));
    if (!(IntuitionBase = OpenLibrary("intuition.library", 0)))
        goto dieilib;
    if (!(GfxBase = OpenLibrary("graphics.library", 0)))
        goto dieglib;
    if (OpenDevice("timer.device", UNIT_VBLANK, &Iot, 0))
        goto diedev;
    if (!GetScreenData(&Scr, sizeof(Scr), WBENCHSCREEN, NULL))
        goto diewin;

    Nw.Width  = Params[WWIDTH];
    Nw.Height = Params[WHEIGHT];
    Nw.LeftEdge = Params[WPOSX];
    Nw.TopEdge  = Params[WPOSY];
    if (Nw.Width <= 0)
        Nw.Width += Scr.Width;
    if (Nw.Height <= 0)
        Nw.Height += Scr.Height;
    if (Nw.LeftEdge < 0)
        Nw.LeftEdge += Scr.Width - Nw.Width;
    if (Nw.TopEdge < 0)
        Nw.TopEdge  += Scr.Height- Nw.Height;
    if (Nw.LeftEdge < 0 || Nw.TopEdge < 0 || Nw.LeftEdge + Nw.Width > Scr.Width || Nw.TopEdge + Nw.Height > Scr.Height) {
        Nw.LeftEdge = Nw.TopEdge = 0;
        Nw.Width = 64;
        Nw.Height= 32;
    }
    if (!(Win = OpenWindow(&Nw)))
        goto diewin;
    ShowTitle(Win->WScreen, 0);
    TPort.mp_Node.ln_Type = NT_MSGPORT;
    TPort.mp_SigTask = FindTask(NULL);
    TPort.mp_SigBit = AllocSignal(-1);
    TPort.mp_Flags  = PA_SIGNAL;
    NewList(&TPort.mp_MsgList);
    Iot.tr_node.io_Message.mn_ReplyPort = &TPort;
    Iot.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
    Iot.tr_node.io_Command = TR_ADDREQUEST;
    Iot.tr_time.tv_secs = 1;
    Iot.tr_time.tv_micro= 0;
    SendIO(&Iot);
    TMask = 1 << TPort.mp_SigBit;
    WMask = 1 << Win->UserPort->mp_SigBit;
    error = 0;
    while (notdone) {
        register long mask = Wait(TMask|WMask);
        if (mask & TMask) {
            register short secs;
            WaitIO(&Iot);
            secs = UpdateWindow(Win);
            Iot.tr_time.tv_secs = 65 - secs;
            Iot.tr_time.tv_micro= 0;
            Iot.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
            SendIO(&Iot);
        }
        if (mask & WMask) {
            register IMESS *im;
            while (im = GetMsg(Win->UserPort)) {
                switch(im->Class) {
                case CLOSEWINDOW:
                    notdone = 0;
                    break;
                case REFRESHWINDOW:
                    BeginRefresh(Win);
                    EndRefresh(Win);
                case ACTIVEWINDOW:
                case INACTIVEWINDOW:
                    UpdateWindow(Win);
                    break;
                }
                ReplyMsg(im);
            }
        }
    }
    AbortIO(&Iot);
    WaitIO(&Iot);
    FreeSignal(TPort.mp_SigBit);
    CloseWindow(Win);
diewin:
    CloseDevice(&Iot);
diedev:
    CloseLibrary(GfxBase);
dieglib:
    CloseLibrary(IntuitionBase);
dieilib:
    _exit(error);
}
/*
 *  Update the window
 *
 *  (1) RectFill
 *  (2) minute and hour hands
 */
UpdateWindow(win)
register WIN *win;
{
    register RP *rp = win->RPort;
    DATESTAMP DS;
    short minutes;
    short hours;
    short radiusx, radiusy;
    short centerx, centery;
    DateStamp(&DS);
    minutes = DS.ds_Minute % 60;
    hours   = (DS.ds_Minute / 12) % 60;     /*  0 to 59 (partial hours indicator)   */
    radiusx = (win->Width - 2) >> 1;
    radiusy = (win->Height- 2) >> 1;
    centerx = 1 + radiusx;
    centery = 1 + radiusy;
    SetAPen(rp, 0);
    RectFill(rp, 0, 0, win->Width - 1, win->Height - 1);
    SetAPen(rp, 1);
    {
        register short i;
        for (i = 0; i < 60; i += 5) {
            Move(rp, centerx + ((radiusx * Sin[i]) >> 8), centery + ((radiusy * -Cos[i]) >> 8));
            Draw(rp, centerx + ((radiusx * Sin[i]) >> 8), centery + ((radiusy * -Cos[i]) >> 8));
        }
    }
    radiusx -= 2;
    radiusy -= 2;
    SetAPen(rp, 3);                 /*  minutes */
    Move(rp, centerx, centery);
    Draw(rp, centerx + ((radiusx * Sin[minutes]) >> 8), centery + ((radiusy * -Cos[minutes]) >> 8));
    SetAPen(rp, 2);                 /*  hours   */
    Move(rp, centerx, centery);
    Draw(rp, centerx + ((radiusx * Sin[hours]) / 384), centery + ((radiusy * -Cos[hours]) / 384));
    return(DS.ds_Tick / 50 % 60);  /*  seconds */
}
#asm
            ; bzero(buf, bytes)
            ;       4sp   8sp
            ;
            ;   SIMPLE STUPID BZERO .. I don't even use DBF (don't want to
            ;                           have to think at this time of night)
_bzero:
            moveq.l #0,D1
            move.l  4(sp),A0
            move.l  8(sp),D0
            beq     bze
bz1         move.b  D1,(A0)+
            subq.l  #1,D0
            bne     bz1
bze         rts
#endasm
