/*
 *  Uhr.c
 *
 *  Author: Stefan Sticht
 *
 *  Copyright: source is public domain, no copyright
 *
 *  Version history:
 *
 *  V0.01   initial release
 *  V0.02   using now cback.o
 *  V0.03   RMBTRAP flag set
 *  V0.04   added LockIBase before looking at IntuitionBase
 *          (thanks to Holger Gzella for bug report),
 *          added screen title
 *  V0.05   structure for timerequest is now in MEMF_PUBLIC
 *          (thanks to Holger Gzella for opening my eyes)
 *          now using CreateMsgPort() instead of CreatePort()
 */

#define VERSION "V0.05"

#include <stdlib.h>
#include <string.h>
#include <devices/timer.h>
#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#include <clib/exec_protos.h>
#include <pragmas/exec_pragmas.h>
#include <clib/graphics_protos.h>
#include <pragmas/graphics_pragmas.h>
#include <clib/intuition_protos.h>
#include <pragmas/intuition_pragmas.h>

#define PROGRAMTITLE "Uhr"

#ifdef __SASC
extern struct Library *DOSBase;
extern struct Library *SysBase;
/*
 *  data for cback.o
 */
long _stack = 2048l;
char *_procname = PROGRAMTITLE;
long _priority = 0l;
long _BackGroundIO = 0l;
#endif

#define RC_WARN         5l
#define RC_ERROR        10l
#define RC_FAIL         20l

#define NORMAL 0
#define FORCE  1

struct Library *GfxBase;
struct IntuitionBase *IntuitionBase;
struct timerequest *timereq;
struct MsgPort *timerport;

#define DUMMYTEXTLEN    18l
#define DUMMYTEXT       "MM 44.04.44 44:44 "

#define WIDTH_OF_DEPTH_GADGET 23

#define P_WA_Left       0
#define P_WA_Top        1
#define P_WA_Width      2
#define P_WA_Height     3
#define P_WA_PubScreen  6
struct TagItem mywindowtags[] = {
    WA_Left,        0l,
    WA_Top,         0l,
    WA_Width,       120l,
    WA_Height,      16l,
    WA_IDCMP,       IDCMP_CLOSEWINDOW,
    WA_Flags,       WFLG_DRAGBAR | WFLG_CLOSEGADGET | WFLG_SMART_REFRESH | WFLG_RMBTRAP,
    WA_PubScreen,   0l,
    WA_ScreenTitle, (ULONG)PROGRAMTITLE " " VERSION " von Stefan Sticht",
    TAG_END
    };

char version[] ="\0$VER: " PROGRAMTITLE " " VERSION;

long getmessages(struct Window *win);
void updateclock(struct Window *win, short mode);

void _main(char *line)
{
    struct Screen *scr;
    struct Window *win;
    long rc = 0l;

    if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36l)) {

        if (GfxBase = OpenLibrary("graphics.library", 36l)) {

            if (timereq = AllocMem(sizeof(struct timerequest), MEMF_PUBLIC | MEMF_CLEAR)) {

                if (timerport = CreateMsgPort()) {

                    if (!OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timereq, 0l)) {

                        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;

                        if (scr = LockPubScreen("Workbench")) {

                            mywindowtags[P_WA_Width].ti_Data = (ULONG)(TextLength(&scr->RastPort, DUMMYTEXT, DUMMYTEXTLEN) + 32l);
                            mywindowtags[P_WA_Left].ti_Data = (ULONG)(scr->Width - mywindowtags[P_WA_Width].ti_Data - WIDTH_OF_DEPTH_GADGET);
                            mywindowtags[P_WA_Height].ti_Data = (ULONG)(scr->BarHeight + 1);

                            if (win = OpenWindowTagList(NULL, mywindowtags)) {

                                updateclock(win, FORCE);
                                timereq->tr_time.tv_secs = 0l;
                                timereq->tr_time.tv_micro = 10l;
                                SendIO(&(timereq->tr_node));
                                getmessages(win);

                                CloseWindow(win);

                                }

                            else rc = 25;

                            UnlockPubScreen(NULL, scr);
                            }

                        else rc = 26;

                        CloseDevice((struct IORequest *)&timereq);

                        } /* if OpenDevice() */

                    else rc = 27;

                    DeleteMsgPort((struct MsgPort *)timerport);

                    } /* if timerport */

                else rc = 28;

                FreeMem(timereq, sizeof(struct timerequest));

                } /* if timereq = AllocMem */

            else rc = 29;

            CloseLibrary(GfxBase);

            } /* if GfxBase */

        else rc = 30;

        CloseLibrary((struct Library *)IntuitionBase);

        } /* if IntutionBase */

    else rc = 31;

    exit(rc);
}

long getmessages(struct Window *win)
{
    struct IntuiMessage *msg;
    unsigned long sigreceived;
    ULONG class;
    unsigned short request = FALSE;
    unsigned short quit = FALSE;

    while (!quit) {

        sigreceived = Wait((1l << win->UserPort->mp_SigBit) | (1l << timerport->mp_SigBit));

        if (sigreceived & (1l << win->UserPort->mp_SigBit)) {

            while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)) && !quit) {

                /*
                 *  save and free message
                 */
                class = msg->Class;
                ReplyMsg((struct Message *)msg);

                if (class == CLOSEWINDOW) quit = TRUE;

                } /* while msg */

            }

        if (sigreceived & (1l << timerport->mp_SigBit)) {

            GetMsg(timerport);
            request = FALSE;

            if (!quit) {

                /*
                 *  if quit is already TRUE, there's no need for it...
                 */
                timereq->tr_time.tv_secs = 1l;
                timereq->tr_time.tv_micro = 0l;
                SendIO(&(timereq->tr_node));
                request = TRUE;

                }

            updateclock(win, NORMAL);

            }

        } /* while !quit */

    if (request) {
        /*
         *  cancel pending IORequest
         */
        AbortIO(&(timereq->tr_node));
        Wait(1L << timerport->mp_SigBit );
        GetMsg(timerport);
        }

    return(0l);
}

void updateclock(struct Window *win, short mode)
{
    static char date[LEN_DATSTRING];
    static char time[LEN_DATSTRING];
    static char day[LEN_DATSTRING];
    static char buffer[19] = "Mo 01.01.91 12:12";
    static struct DateTime datetime = {
                        /* struct DateStamp dat_Stamp; DOS DateStamp */
        {0,                 /* LONG ds_Days; Number of days since Jan. 1, 1978 */
        0,                  /* LONG ds_Minute; Number of minutes past midnight */
        0},                 /* LONG ds_Tick; Number of ticks past minute */
        FORMAT_CDN,     /* UBYTE dat_Format; controls appearance of dat_StrDate */
        0,              /* UBYTE dat_Flags; see BITDEF's below */
        day,            /* UBYTE *dat_StrDay; day of the week string */
        date,           /* UBYTE *dat_StrDate; date string */
        time            /* UBYTE *dat_StrTime; time string */
        };
    ULONG lock;

    DateStamp(&datetime.dat_Stamp);
    DateToStr(&datetime);

    if ((time[6] == '0' && time[7] == '0') || mode == FORCE) {

        if (day[0] == 'T') {
            buffer[0] = 'D';
            if (day[1] == 'u') buffer[1] = 'i';
            if (day[1] == 'h') buffer[1] = 'o';
            }
        else if (day[0] == 'W') {
            buffer[0] = 'M';
            buffer[1] = 'i';
            }
        else if (day[0] == 'S' && day[1] == 'u') {
            buffer[0] = 'S';
            buffer[1] = 'o';
            }
        else {
            buffer[0] = day[0];
            buffer[1] = day[1];
            }
        buffer[3] = date[0];
        buffer[4] = date[1];
        buffer[6] = date[3];
        buffer[7] = date[4];
        buffer[9] = date[6];
        buffer[10] = date[7];
        strncpy(buffer + 12, time, 5);
        SetWindowTitles(win, buffer, (UBYTE*)~0);

        lock = LockIBase(0l);
        if (IntuitionBase->FirstScreen == win->WScreen) {
            UnlockIBase(lock);
            WindowToFront(win);
            }
        else UnlockIBase(lock);

        }

}
