#include <exec/types.h>
#include <proto/exec.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <proto/intuition.h>
#include <libraries/gadtools.h>
#include <proto/gadtools.h>
#include <libraries/resource.h>
#include <proto/resource.h>
#include <resources/battmem.h>
#include <resources/battmembitsamiga.h>
#include <resources/battmembitsshared.h>
#include <proto/battmem.h>
#include <graphics/gfx.h>
#include <clib/graphics_protos.h>

#include <ctype.h>
#include <stdlib.h>
#include "amigan.h"

#define BOXLEFTX   48
#define BOXRIGHTX  (BOXLEFTX + 10 + (32 * 8))
#define BOXTOPY    24
#define BOXBOTTOMY (BOXTOPY  +  6 + ( 3 * 8))

MODULE struct Gadget  *BU91_Revert         = NULL,
                      *BU91_Write          = NULL,
                      *CB91_SharedAmnesia  = NULL,
                      *IN91_SCSIHostID     = NULL,
                      *CB91_SCSISyncXfer   = NULL,
                      *CB91_SCSIFastSync   = NULL,
                      *CB91_SCSITagQueues  = NULL,
                      *CB91_AmigaAmnesia   = NULL,
                      *CB91_SCSITimeout    = NULL,
                      *CB91_SCSILUNS       = NULL;

MODULE ABOOL          BattBuffer[96];

AGLOBAL struct Library*    BattMemBase     = NULL;

// from rp.c
IMPORT ABOOL               fillwindows;
IMPORT SBYTE               page;
IMPORT struct NewGadget    Gadget;
IMPORT struct Gadget      *BU99_Right,
                          *ST99_Output,
                          *BU99_OutputASL,
                          *PrevGadPtr;
IMPORT struct Window*      MainWindowPtr;
IMPORT struct VisualInfo*  VisualInfoPtr;

MODULE void updatebattgadgets(void);
MODULE void drawbit(ULONG bit, UBYTE colour);
MODULE void readbatt(ABOOL print);
MODULE void writebatt(void);

AGLOBAL void batt1(void)
{   ULONG hostid = 0;

    if (!BattMemBase)
    {   if (!(BattMemBase = OpenResource(BATTMEMNAME)))
        {   rq("Can't open battery RAM resource!");
    }   }

    verynewwindow
    (   BATT1WIDTH, BATT1HEIGHT,
        "Report+: Battery-backed Memory",
        BUTTONIDCMP
    );
    if (fillwindows)
    {   SetAPen(MainWindowPtr->RPort, 0);
        RectFill(MainWindowPtr->RPort, BOXLEFTX, BOXTOPY, BOXRIGHTX, BOXBOTTOMY);
    }

    setgadget(48, 54, 133, 12, "_Revert", NULL);
    BU91_Revert = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    setgadget(181, 54, 133, 12, "_Write", NULL);
    BU91_Write = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );

    readbatt(FALSE);
    setgadget(360, 24, 0, 0, "AMIGA_AMNESIA ($00)", PLACETEXT_RIGHT);
    CB91_AmigaAmnesia = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        (BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] & 1)? 0 : 1,
        TAG_DONE
    );
    setgadget(360, 38, 0, 0, "SHARED_AMNESIA ($40)", PLACETEXT_RIGHT);
    CB91_SharedAmnesia = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        (BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] & 1)? 0 : 1,
        TAG_DONE
    );
    setgadget(360, 52, 0, 0, "SCSI_TIMEOUT ($01)", PLACETEXT_RIGHT);
    CB91_SCSITimeout = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR],
        TAG_DONE
    );
    setgadget(360, 66, 0, 0, "SCSI_LUNS ($02)", PLACETEXT_RIGHT);
    CB91_SCSILUNS = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        BattBuffer[BATTMEM_SCSI_LUNS_ADDR],
        TAG_DONE
    );
    setgadget(334, 80, 52, 12, "SCSI_HOST_ID ($41-43)", PLACETEXT_RIGHT);
    if (!BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR])
    {   hostid += 4;
    }
    if (!BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 1])
    {   hostid += 2;
    }
    if (!BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 2])
    {   hostid++;
    }
    IN91_SCSIHostID = PrevGadPtr = (struct Gadget *) CreateGadget
    (   INTEGER_KIND,
        PrevGadPtr,
        &Gadget,
        GTIN_Number, hostid,
        GA_TabCycle, TRUE,
        TAG_DONE
    );
    setgadget(360, 94, 0, 0, "SCSI_SYNC_XFER ($44)", PLACETEXT_RIGHT);
    CB91_SCSISyncXfer = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR],
        TAG_DONE
    );
    setgadget(360, 108, 0, 0, "SCSI_FAST_SYNC ($45)", PLACETEXT_RIGHT);
    CB91_SCSIFastSync = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        (BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] & 1)? 0 : 1,
        TAG_DONE
    );
    setgadget(360, 122, 0, 0, "SCSI_TAG_QUEUES ($46)", PLACETEXT_RIGHT);
    CB91_SCSITagQueues = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked,
        BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR],
        TAG_DONE
    );

    drawgadgets((UWORD) ~0);

    DrawBevelBox(MainWindowPtr->RPort, BOXLEFTX, BOXTOPY, BOXRIGHTX - BOXLEFTX, BOXBOTTOMY - BOXTOPY, GT_VisualInfo, VisualInfoPtr, GTBB_Recessed, FALSE, TAG_DONE);
    SetDrMd(MainWindowPtr->RPort, JAM1);
    SetAPen(MainWindowPtr->RPort, BLACK);
    Move(MainWindowPtr->RPort, 16, BOXTOPY + 10);
    Text(MainWindowPtr->RPort, "$00:", 4);
    Move(MainWindowPtr->RPort, 16, BOXTOPY + 18);
    Text(MainWindowPtr->RPort, "$20:", 4);
    Move(MainWindowPtr->RPort, 16, BOXTOPY + 26);
    Text(MainWindowPtr->RPort, "$40:", 4);
    SetDrMd(MainWindowPtr->RPort, JAM2);

    readbatt(TRUE);

    ActivateGadget(IN91_SCSIHostID, MainWindowPtr, NULL);
    loop();
    closewindow();
}

MODULE void updatebattgadgets(void)
{   ULONG hostid = 0;

    GT_SetGadgetAttrs(CB91_AmigaAmnesia, MainWindowPtr, NULL,
                      GTCB_Checked,
                      (BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] & 1)? 0 : 1,
                      TAG_DONE);
    GT_SetGadgetAttrs(CB91_SharedAmnesia, MainWindowPtr, NULL,
                      GTCB_Checked,
                      (BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] & 1)? 0 : 1,
                      TAG_DONE);
    GT_SetGadgetAttrs(CB91_SCSITimeout, MainWindowPtr, NULL,
                      GTCB_Checked,
                      BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR],
                      TAG_DONE);
    GT_SetGadgetAttrs(CB91_SCSILUNS, MainWindowPtr, NULL,
                      GTCB_Checked,
                      BattBuffer[BATTMEM_SCSI_LUNS_ADDR],
                      TAG_DONE);
    if (!BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR])
    {   hostid += 4;
    }
    if (!BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 1])
    {   hostid += 2;
    }
    if (!BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 2])
    {   hostid++;
    }
    GT_SetGadgetAttrs(IN91_SCSIHostID, MainWindowPtr, NULL,
                      GTIN_Number, hostid,
                      TAG_DONE);
    GT_SetGadgetAttrs(CB91_SCSISyncXfer, MainWindowPtr, NULL,
                      GTCB_Checked,
                      BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR],
                      TAG_DONE);
    GT_SetGadgetAttrs(CB91_SCSIFastSync, MainWindowPtr, NULL,
                      GTCB_Checked,
                      (BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] & 1)? 0 : 1,
                      TAG_DONE);
    GT_SetGadgetAttrs(CB91_SCSITagQueues, MainWindowPtr, NULL,
                      GTCB_Checked,
                      BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR],
                      TAG_DONE);
}

MODULE void drawbit(ULONG bit, UBYTE colour)
{   Move(MainWindowPtr->RPort, BOXLEFTX + 4 + (8 * (bit % 32)), BOXTOPY + 10 + (8 * (bit / 32)));

    if
    (   (bit >= 0x0  && bit <= 0x2)
     || (bit >= 0x40 && bit <= 0x46)
    )
    {   if (colour == BLACK)
        {   colour = GREY;
        }
        SetAPen(MainWindowPtr->RPort, colour);
        SetBPen(MainWindowPtr->RPort, BLACK);
    } else
    {   SetAPen(MainWindowPtr->RPort, colour);
        SetBPen(MainWindowPtr->RPort, GREY);
    }

    if (BattBuffer[bit] & 1)
        Text(MainWindowPtr->RPort, "1", 1);
    else
        Text(MainWindowPtr->RPort, "0", 1);
    return;
}

MODULE void readbatt(ABOOL print)
{   ULONG i;

    ObtainBattSemaphore();
    for (i = 0; i <= 95; i++)
    {   if (ReadBattMem(&BattBuffer[i], i, 1))
        {   ReleaseBattSemaphore();
            rq("Can't read battery-backed memory!");
    }   }
    if (print)
        for (i = 0; i <= 95; i++)
            drawbit(i, BLACK);
    ReleaseBattSemaphore();
}

AGLOBAL void batt_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual, SWORD mousex, SWORD mousey)
{   UWORD realx, realy, bit;
    ULONG hostid;

    if (class == IDCMP_MOUSEBUTTONS)
    {   if (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
        {   if (mousex >= BOXLEFTX && mousex <= BOXRIGHTX && mousey >= BOXTOPY && mousey <= BOXBOTTOMY)
            {   realx = (mousex - BOXLEFTX - 2) / 8;
                realy = (mousey - BOXTOPY - 4) / 8;
                if (realx < 0)
                    realx = 0;
                elif (realx > 31)
                    realx = 31;
                if (realy < 0)
                    realy = 0;
                elif (realy > 2)
                    realy = 2;
                bit = (realy * 32) + realx;
                BattBuffer[bit] ^= 1;
                drawbit(bit, WHITE);
                updatebattgadgets();
    }   }   }
    elif (class == IDCMP_VANILLAKEY)
    {   code = toupper(code);
        if (code == 'R')
        {   readbatt(TRUE);
            updatebattgadgets();

        } elif (code == 'W')
            writebatt();
        elif (code == ESCAPE)
            page = 0;
    } elif (class == IDCMP_GADGETUP)
    {   if (addr == BU99_Right)
            page = 0;
        elif (addr == CB91_AmigaAmnesia)
        {   if (CB91_AmigaAmnesia->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] = 0;
            else BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] = 1;
            drawbit(BATTMEM_AMIGA_AMNESIA_ADDR, WHITE);
        } elif (addr == CB91_SharedAmnesia)
        {   if (CB91_SharedAmnesia->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] = 0;
            else BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] = 1;
            drawbit(BATTMEM_SHARED_AMNESIA_ADDR, WHITE);
        } elif (addr == CB91_SCSITimeout)
        {
           if (CB91_SCSITimeout->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR] = 1;
            else BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR] = 0;
            drawbit(BATTMEM_SCSI_TIMEOUT_ADDR, WHITE);
        } elif (addr == CB91_SCSILUNS)
        {   if (CB91_SCSILUNS->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_SCSI_LUNS_ADDR] = 1;
            else BattBuffer[BATTMEM_SCSI_LUNS_ADDR] = 0;
            drawbit(BATTMEM_SCSI_LUNS_ADDR, WHITE);
        } elif (addr == IN91_SCSIHostID)
        {   hostid = ((struct StringInfo *) IN91_SCSIHostID->SpecialInfo)->LongInt;
            if (hostid < 0 || hostid > 7)
            {   hostid = 7;
            }
            GT_SetGadgetAttrs
            (   IN91_SCSIHostID,
                MainWindowPtr, NULL,
                GTIN_Number, hostid,
                TAG_DONE
            );
            BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR]     = (hostid & 4)? 0 : 1;
            BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 1] = (hostid & 2)? 0 : 1;
            BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 2] = (hostid & 1)? 0 : 1;
            drawbit(BATTMEM_SCSI_HOST_ID_ADDR    , WHITE);
            drawbit(BATTMEM_SCSI_HOST_ID_ADDR + 1, WHITE);
            drawbit(BATTMEM_SCSI_HOST_ID_ADDR + 2, WHITE);
        } elif (addr == CB91_SCSISyncXfer)
        {   if (CB91_SCSISyncXfer->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR] = 1;
            else BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR] = 0;
            drawbit(BATTMEM_SCSI_SYNC_XFER_ADDR, WHITE);
        } elif (addr == CB91_SCSIFastSync)
        {   if (CB91_SCSIFastSync->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] = 0;
            else BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] = 1;
            drawbit(BATTMEM_SCSI_FAST_SYNC_ADDR, WHITE);
        } elif (addr == CB91_SCSITagQueues)
        {   if (CB91_SCSITagQueues->Flags & GFLG_SELECTED)
                BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR] = 1;
            else BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR] = 0;
            drawbit(BATTMEM_SCSI_TAG_QUEUES_ADDR, WHITE);
        } elif (addr == BU91_Revert)
        {
            readbatt(TRUE);
            updatebattgadgets();
        } elif (addr == BU91_Write)
        {   writebatt();
}   }   }

MODULE void writebatt(void)
{   ULONG i;

    ObtainBattSemaphore();
    for (i = 0; i <= 95; i++)
    {   if (WriteBattMem(&BattBuffer[i], i, 1))
        {   ReleaseBattSemaphore();
            rq("Can't write battery-backed memory!");
    }   }
    ReleaseBattSemaphore();
    readbatt(TRUE);
}
