/*
 * This is an example of adding a gadget to the clock area
 */

#define __USE_SYSBASE
long    __oslibversion = 37L;

#include <exec/types.h>
#include <exec/exec.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <devices/timer.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/graphics.h>

#include "messages.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

VOID ShutDown(STRPTR, UBYTE);
VOID SendStartMsg(START_MSG *, APTR, UBYTE);
BOOL StartTimer(VOID);
VOID CloseTimer(VOID);
VOID CheckAud(VOID);
VOID CopyBitMap(struct BitMap *, struct BitMap *);
BOOL DoReq(VOID);
VOID SetUpBitmaps(VOID);

UBYTE ver[] = {"$VER: AudMon v1.0 "__AMIGADATE__};

IFF_SCALED          nbm;        /* A BitMap to attatch to the RastPort */
IFF_SCALED          iffs[16];
START_MSG           smsg;       /* The message to send */
START_MENU_GADGET   gad;        /* The gadget */
struct MsgPort     *my_port;    /* A port for StartMenu to send messages to */

struct timerequest *TimerIO;
struct MsgPort     *TimerPort;
struct Library     *TimerBase;

main()
{
    struct Message *m;
    struct MsgPort *start_port;
    START_MSG      *rep_smsg;
    ULONG t_sig, p_sig, sig, cnt = 0;
    BOOL done = FALSE;

    /* Set up the timer */
    if (!(StartTimer()))
        ShutDown("Could not get timer device", 5);

    /* Try to find StartMenu */
    while (cnt++ < 10) {
        if (start_port = FindPort(STARTMENU_PORT_NAME)) break;
        else Delay(250);
    }
    if (!start_port)
        ShutDown("Could not find StartMenu.", 5);

    /* Create a port */
    if (!(my_port = CreatePort(0, 0)))
        ShutDown("Could not create a message port.", 5);

    /* Prepare the Message */
    smsg.sm_Msg.mn_Node.ln_Type = NT_MESSAGE;
    smsg.sm_Msg.mn_Length = START_MSG_SIZE;
    smsg.sm_Msg.mn_ReplyPort = my_port;

    SetUpBitmaps();

    /* Ask StartMenu to create a gadget */
    gad.smg_BitMap = nbm.iffs_ScaledBM;
    gad.smg_Mask   = nbm.iffs_Mask;
    gad.smg_Port   = my_port;
    SendStartMsg(&smsg, (APTR)(&gad), ADD_CLOCK_GADGET);

    /* Check the gadget */
    if (NULL == gad.smg_Gadget)
        ShutDown("Could not create gadget.", 5);

    /* Everything ok. Start loop */
    t_sig = 1L << TimerPort->mp_SigBit;
    p_sig = 1L << my_port->mp_SigBit;
    while (!done) {
        sig = Wait(t_sig | p_sig);

        /* A message from StartMenu - copy and reply ASAP!!! */
        if (sig & p_sig) {
            while (rep_smsg = (START_MSG *)GetMsg(my_port)) {
                if (rep_smsg->sm_Command == GADGET_STATUS) {
                    /* An IDCMP message */
                    ReplyMsg((struct Message *)rep_smsg);
                    done = DoReq();
                }
                else {
                    /* Any other message is a quit message */
                    ReplyMsg((struct Message *)rep_smsg);
                    gad.smg_Gadget = NULL;  /* Set this so we don't free it */
                    done = TRUE;
                }
            }
        }
        else if (sig & t_sig) {
            while (m = GetMsg(TimerPort)) /* NULL */ ;

            TimerIO->tr_node.io_Command = TR_ADDREQUEST;
            TimerIO->tr_time.tv_secs = 1;
            TimerIO->tr_time.tv_micro = 0;
            SendIO((struct IORequest *) TimerIO);
            CheckAud();
        }
    }

    ShutDown(NULL, 0);
}

VOID ShutDown(STRPTR s, UBYTE rc)
{
    FREE_BITMAP fbm;
    int x;

    CloseTimer();

    /* Remove our gadget */
    if (gad.smg_Gadget) {
        RE_GADGET re;
        re.re_Gadget = gad.smg_Gadget;
        SendStartMsg(&smsg, (APTR)(&re), REM_CLOCK_GADGET);
    }

    for (x = 0; x < 4; x++) {
        fbm.fbm_BitMap = iffs[x].iffs_ScaledBM;
        fbm.fbm_Mask   = iffs[x].iffs_Mask;
        SendStartMsg(&smsg, (APTR)(&fbm), FREE_BIT_MAP);
    }

    if (my_port) DeletePort(my_port);

    if (s) fprintf(stderr, "AudMon: %s\n", s);

    exit(rc);
}

VOID SendStartMsg(START_MSG *msg, APTR data, UBYTE command)
{
    struct MsgPort *start_port;
    
    if (start_port = FindPort(STARTMENU_PORT_NAME)) {
        msg->sm_Command = command;
        msg->sm_Data    = data;
        PutMsg(start_port, (struct Message *)msg);
        WaitPort(my_port);           /* StartMenu replies to ALL messages!! */
        GetMsg(my_port);
    }
}

BOOL StartTimer(VOID)
{
    if (TimerPort = CreatePort(0,0)) {
        if (TimerIO = (struct timerequest *)CreateIORequest(TimerPort, sizeof(struct timerequest))) {
            if (!OpenDevice( "timer.device", UNIT_VBLANK, (struct IORequest *)TimerIO, NULL )) {
                TimerIO->tr_node.io_Command = TR_ADDREQUEST;
                TimerIO->tr_time.tv_secs    = 1;
                TimerIO->tr_time.tv_micro   = 0;
                SendIO((struct IORequest *)TimerIO);
                TimerBase = (struct Library *)TimerIO->tr_node.io_Device;
                return(TRUE);
            }
            DeleteIORequest((struct IORequest *)TimerIO);
            TimerIO = NULL;
        }
        DeletePort(TimerPort);
        TimerPort = NULL;
    }
    return(FALSE);
}

VOID CloseTimer(VOID)
{
    if (TimerIO) {
        if (TimerIO->tr_node.io_Command == TR_ADDREQUEST)
            AbortIO((struct IORequest *)TimerIO);
        CloseDevice((struct IORequest *)TimerIO);
        DeleteIORequest((struct IORequest *)TimerIO);
        TimerIO = NULL;
    }
    if (TimerPort) {
        DeletePort(TimerPort);
        TimerPort = NULL;
    }
}

VOID CheckAud(VOID)
{
    RE_GADGET re;
    static UWORD *dmaconr = (UWORD *)0xDFF002;
    UWORD cur_aud;
    struct BitMap *cur_bm;
    static struct BitMap *last_bm = NULL;
    
    cur_aud = *dmaconr & 0x000F;
    cur_bm  = iffs[cur_aud].iffs_ScaledBM;

    if (cur_bm != last_bm) {
        last_bm = cur_bm;
        CopyBitMap(nbm.iffs_ScaledBM, cur_bm);
        re.re_Gadget = gad.smg_Gadget;
        SendStartMsg(&smsg, (APTR)(&re), REFRESH_CLOCK_GADGET);
    }
}

VOID CopyBitMap(struct BitMap *to, struct BitMap *from)
{
    int d;
    
    for (d = 0; d < to->Depth; d++)
        memcpy(to->Planes[d], from->Planes[d], to->BytesPerRow * to->Rows);
}

BOOL DoReq(VOID)
{
    struct EasyStruct es = {
        sizeof(struct EasyStruct),
        0,
        "SerMon",
        "Really quit AudMon?",
        "Yes|Don't Quit"
    };

    if (0 == EasyRequest(NULL, &es, NULL))
        return(FALSE);
    return(TRUE);
}

VOID SetUpBitmaps(VOID)
{
    int x;
    UBYTE buf1[128], buf2[128];
    UBYTE *names[] = {"aud1.bru", "aud2.bru", "aud3.bru", "aud4.bru",
                      "aud5.bru", "aud6.bru", "aud7.bru", "aud8.bru",
                      "aud9.bru", "aud10.bru", "aud11.bru", "aud12.bru",
                      "aud13.bru", "aud14.bru", "aud15.bru", "aud16.bru"};
    BPTR lock;

    lock = GetProgramDir();
    NameFromLock(lock, buf1, 128);
    for (x = 0; x < 16; x++) {
        strcpy(buf2, buf1);
        AddPart(buf2, names[x], 128);
        iffs[x].iffs_FileName = buf2;
        SendStartMsg(&smsg, (APTR)(&(iffs[x])), SCALE_IFF);
        if (NULL == iffs[x].iffs_ScaledBM)
            ShutDown("Could not create scaled bitmap.", 5);
   }
    /* Ask StartMenu to create a BitMap */
    nbm.iffs_FileName = buf2;
    SendStartMsg(&smsg, (APTR)(&nbm), SCALE_IFF);
    /* Check the BitMap */
    if (NULL == nbm.iffs_ScaledBM)
        ShutDown("Could not create BitMap.", 5);
}
