#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 <dos/dos.h>
#include <clib/dos_protos.h>

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

#define ALL_REACTION_CLASSES
#include <reaction/reaction.h>

#define BOXWIDTH   (10 + (32 * 8))
#define BOXHEIGHT  ( 6 + ( 3 * 8))

MODULE UBYTE IOBuffer[LONGESTFIELD + 1];

AGLOBAL struct Library*    BattMemBase = NULL;

// from rp.c
IMPORT ABOOL               BattBuffer[96];
IMPORT SBYTE               page;
IMPORT struct Menu*        MenuPtr;
IMPORT struct TextFont*    FontPtr;
IMPORT struct Screen*      ScreenPtr;
IMPORT struct Window*      MainWindowPtr;
IMPORT TEXT                aslresult[PATHNAMEFIELD + 1];
IMPORT Object*             WinObject[FUNCTIONS + 1];

AGLOBAL struct Gadget*     batt_gadgets[GIDS_9 + 1];

MODULE struct
{   TEXT output[PATHNAMEFIELD + 1];
} batt =
{   ""
};

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

AGLOBAL void batt1(void)
{   ULONG       hostid = 0;
    struct Hook Hook9Struct;

    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++;
    }

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

    InitHook(&Hook9Struct, Hook9Func, NULL);

    /* Create the window object. */
    lockscreen();

    if (!(WinObject[9] =
    NewObject
    (
    WINDOW_GetClass(), NULL,
    WA_PubScreen,                 ScreenPtr,
    WA_ScreenTitle,               "Report+",
    WA_Title,                     "Report+: Battery-backed Memory Editor",
    WA_Activate,                  TRUE,
    WA_DepthGadget,               TRUE,
    WA_DragBar,                   TRUE,
    WA_CloseGadget,               TRUE,
    WA_IDCMP,                     IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS,
    WINDOW_IDCMPHook,             &Hook9Struct,
    WINDOW_IDCMPHookBits,         IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS,
    WINDOW_MenuStrip,             MenuPtr,
    WINDOW_Position,              WPOS_CENTERSCREEN,
    WINDOW_ParentGroup,           batt_gadgets[GID_9_LY1] =
                                  NewObject(LAYOUT_GetClass(), NULL,
        // root-layout
        LAYOUT_Orientation,       LAYOUT_ORIENT_VERT,
        LAYOUT_SpaceOuter,        TRUE,
        LAYOUT_DeferLayout,       TRUE,
        LAYOUT_AddChild,          NewObject(LAYOUT_GetClass(), NULL,
            // layout
            LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
            LAYOUT_VertAlignment, LALIGN_CENTER,
            LAYOUT_HorizAlignment,LALIGN_CENTER,
            LAYOUT_BevelStyle,    BVS_NONE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),    NULL,
                    LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,    TRUE,
                    LAYOUT_VertAlignment, LALIGN_CENTER,
                    LAYOUT_HorizAlignment,LALIGN_LEFT,
                    LAYOUT_BevelStyle,    BVS_FIELD,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB1] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB1,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "AMIGA AMNESIA ($00)",
                        GA_Selected,          (BOOL) ((BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] & 1)? 0 : 1),
                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB2] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB2,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "SHARED AMNESIA ($40)",
                        GA_Selected,          (BOOL) ((BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] & 1)? 0 : 1),
                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB3] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB3,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "SCSI TIMEOUT ($01)",
                        GA_Selected,          (BOOL) BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR],
                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB4] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB4,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "SCSI LUNS ($02)",
                        GA_Selected,          (BOOL) BattBuffer[BATTMEM_SCSI_LUNS_ADDR],
                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB5] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB5,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "SCSI SYNC XFER ($44)",
                        GA_Selected,          (BOOL) BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR],
                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB6] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB6,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "SCSI FAST SYNC ($45)",
                        GA_Selected,          (BOOL) ((BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] & 1)? 0 : 1),

                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,          batt_gadgets[GID_9_CB7] =
                    NewObject
                    (   CHECKBOX_GetClass(),  NULL,
                        GA_ID,                GID_9_CB7,
                        GA_RelVerify,         TRUE,
                        GA_Text,              "SCSI TAG QUEUES ($46)",
                        GA_Selected,          (BOOL) BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR],
                    TAG_END),
                    CHILD_WeightedHeight,     0,
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),    NULL,
                        LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                        LAYOUT_VertAlignment, LALIGN_CENTER,
                        LAYOUT_HorizAlignment,LALIGN_LEFT,
                        LAYOUT_BevelStyle,    BVS_NONE,
                        LAYOUT_AddImage,
                        NewObject
                        (   LABEL_GetClass(), NULL,
                            LABEL_Text,       "SCSI HOST ID ($41-43):",
                        TAG_END),
                        CHILD_WeightedWidth,  0,
                        LAYOUT_AddChild,          batt_gadgets[GID_9_IN1] =
                        NewObject
                        (   INTEGER_GetClass(),   NULL,
                            GA_ID,                GID_9_IN1,
                            GA_RelVerify,         TRUE,
                            GA_TabCycle,          TRUE,
                            INTEGER_Number,       hostid,
                            INTEGER_Minimum,      0,
                            INTEGER_Maximum,      7,
                            INTEGER_MinVisible,   1,
                        TAG_END),                                      
                        CHILD_WeightedHeight,     0,
                    TAG_END),
                    CHILD_WeightedHeight,         0,
            TAG_END),
            CHILD_WeightedWidth,      0,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),    NULL,
                    LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
                    LAYOUT_VertAlignment, LALIGN_CENTER,
                    LAYOUT_HorizAlignment,LALIGN_CENTER,
                    LAYOUT_BevelStyle,    BVS_NONE,
                    LAYOUT_AddChild,      batt_gadgets[GID_9_SP1] =
                    NewObject
                    (   SPACE_GetClass(), NULL,
                        GA_ID,            GID_9_SP1,
                        GA_RelVerify,     TRUE,
                        SPACE_MinWidth,   BOXWIDTH,
                        SPACE_MinHeight,  BOXHEIGHT,
                        SPACE_BevelStyle, BVS_FIELD,
                    TAG_END),
                    CHILD_WeightedHeight, 0,
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),    NULL,
                        LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                        LAYOUT_VertAlignment, LALIGN_CENTER,
                        LAYOUT_HorizAlignment,LALIGN_CENTER,
                        LAYOUT_BevelStyle,    BVS_NONE,
                        LAYOUT_AddChild,      batt_gadgets[GID_9_BU1] =
                        NewObject
                        (   NULL,             "button.gadget",
                            GA_ID,            GID_9_BU1,
                            GA_RelVerify,     TRUE,
                            GA_Text,          "_Revert",
                        TAG_END),
                        CHILD_WeightedWidth,  50,
                        LAYOUT_AddChild,      batt_gadgets[GID_9_BU2] =
                        NewObject
                        (   NULL,             "button.gadget",
                            GA_ID,            GID_9_BU2,
                            GA_RelVerify,     TRUE,
                            GA_Text,          "_Write",
                        TAG_END),
                        CHILD_WeightedWidth,  50,
                    TAG_END),
                    CHILD_WeightedHeight,     0,
            TAG_END),
            CHILD_WeightedHeight,         0,
        TAG_END),
        CHILD_WeightedHeight,         0,
    TAG_END),
    TAG_END
    )))
    {   rq("Can't create ReAction object(s)!");
    }
    unlockscreen();
    openwindow();
    ActivateLayoutGadget(batt_gadgets[GID_9_LY1], MainWindowPtr, NULL, (Object) batt_gadgets[GID_9_IN1]);

    OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
    OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
    OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));

    SetFont(MainWindowPtr->RPort, FontPtr);

    readbatt(TRUE);

    loop();
    closewindow();
}

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

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB1], MainWindowPtr, NULL,
        GA_Selected, (BOOL) ((BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] & 1)? 0 : 1),
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB1], MainWindowPtr, NULL);

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB2], MainWindowPtr, NULL,
        GA_Selected, (BOOL) ((BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] & 1)? 0 : 1),
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB2], MainWindowPtr, NULL);

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB3], MainWindowPtr, NULL,
        GA_Selected, (BOOL) BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR],
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB3], MainWindowPtr, NULL);

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB4], MainWindowPtr, NULL,
        GA_Selected, (BOOL) BattBuffer[BATTMEM_SCSI_LUNS_ADDR],
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB4], MainWindowPtr, NULL);

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB5], MainWindowPtr, NULL,
        GA_Selected, (BOOL) BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR],
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB5], MainWindowPtr, NULL);

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB6], MainWindowPtr, NULL,
        GA_Selected, (BOOL) ((BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] & 1)? 0 : 1),
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB6], MainWindowPtr, NULL);

    SetGadgetAttrs
    (   batt_gadgets[GID_9_CB7], MainWindowPtr, NULL,
        GA_Selected, (BOOL) BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR],
    TAG_END);
    RefreshGadgets((struct Gadget *) batt_gadgets[GID_9_CB7], MainWindowPtr, NULL);

    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++;
    }

    SetGadgetAttrs
    (   batt_gadgets[GID_9_IN1], MainWindowPtr, NULL,
        INTEGER_Number, hostid,
    TAG_END);
}

MODULE void drawbit(ULONG bit, UBYTE colour)
{   Move
    (   MainWindowPtr->RPort,
        batt_gadgets[GID_9_SP1]->LeftEdge + 5 +         (8 * (bit % 32)),
        batt_gadgets[GID_9_SP1]->TopEdge  + 2 + FONTY + (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 gid)
{   ULONG thisbit, hostid;

    switch(gid)
    {
    case GID_9_BU1:
        readbatt(TRUE);
        updatebattgadgets();
    break;
    case GID_9_BU2:
        writebatt(TRUE);
    break;
    case GID_9_IN1:
        if (!(GetAttr
        (   INTEGER_Number, batt_gadgets[GID_9_IN1], (ULONG *) &hostid
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (hostid < 0 || hostid > 7)
        {   hostid = 7;
        }
        SetGadgetAttrs
        (   batt_gadgets[GID_9_IN1], MainWindowPtr, NULL,
            INTEGER_Number, hostid,
            TAG_END
        );
        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);
    break;
    case GID_9_CB1:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB1], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] = 0;
        } else
        {   BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR] = 1;
        }
        drawbit(BATTMEM_AMIGA_AMNESIA_ADDR, WHITE);
    break;
    case GID_9_CB2:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB2], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] = 0;
        } else
        {   BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR] = 1;
        }
        drawbit(BATTMEM_SHARED_AMNESIA_ADDR, WHITE);
    break;
    case GID_9_CB3:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB3], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR] = 1;
        } else
        {   BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR] = 0;
        }
        drawbit(BATTMEM_SCSI_TIMEOUT_ADDR, WHITE);
    break;
    case GID_9_CB4:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB4], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_SCSI_LUNS_ADDR] = 1;
        } else
        {   BattBuffer[BATTMEM_SCSI_LUNS_ADDR] = 0;
        }
        drawbit(BATTMEM_SCSI_LUNS_ADDR, WHITE);
    break;
    case GID_9_CB5:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB5], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR] = 1;
        } else
        {   BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR] = 0;
        }
        drawbit(BATTMEM_SCSI_SYNC_XFER_ADDR, WHITE);
    break;
    case GID_9_CB6:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB6], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] = 0;
        } else
        {   BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR] = 1;
        }
        drawbit(BATTMEM_SCSI_FAST_SYNC_ADDR, WHITE);
    break;
    case GID_9_CB7:
        if (!(GetAttr
        (   GA_Selected, batt_gadgets[GID_9_CB7], (ULONG *) &thisbit
        )))
        {   rq("Unsupported inquiry!"); // should never happen
        }
        if (thisbit)
        {   BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR] = 1;
        } else
        {   BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR] = 0;
        }
        drawbit(BATTMEM_SCSI_TAG_QUEUES_ADDR, WHITE);
    break;
    default:
    break;
}   }

AGLOBAL void writebatt(ABOOL verify)
{   ULONG i;

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

AGLOBAL void batt_open(void)
{   BPTR  FileHandle;
    ULONG i;

    if (asl("~(#?.info)"))
    {   if (!(FileHandle = (BPTR) Open(aslresult, MODE_OLDFILE)))
        {   DisplayBeep(NULL);
            return;
        }
        /* The format of "battery RAM" files (suggested extension
          ".battery") is simply a raw dump of the 12 bytes. */

        if (Read(FileHandle, IOBuffer, 12) == -1)
        {   DisplayBeep(NULL);
        } else
        {   for (i = 0; i <= 95; i++)
            {   if (IOBuffer[i / 8] & (1 << (i % 8)))
                {   BattBuffer[i] = TRUE;
                } else BattBuffer[i] = FALSE;
                drawbit(i, WHITE);
        }   }
        Close(FileHandle);
    }
    updatebattgadgets();
}

AGLOBAL void batt_save(ABOOL saveas)
{   BPTR  FileHandle;
    ULONG i;

    if (!batt.output[0] || saveas) // if we need a filename
    {   if (saveasl("Save Battery RAM", "~(#?.info)"))
        {   strcpy(batt.output, aslresult);
        } else return;
    }

    if (!(FileHandle = (BPTR) Open(aslresult, MODE_NEWFILE)))
    {   DisplayBeep(NULL);
        return;
    }
    for (i = 0; i <= 11; i++)
    {   IOBuffer[i] = 0;
    }
    for (i = 0; i <= 95; i++)
    {   if (BattBuffer[i])
        {   IOBuffer[i / 8] |= BattBuffer[i] << (i % 8);
    }   }
    if (Write(FileHandle, IOBuffer, 12) == -1)
    {   DisplayBeep(NULL);
    }
    Close(FileHandle);
}

AGLOBAL ULONG Hook9Func(struct Hook *h, VOID *o, VOID *msg)
{   /* "When the hook is called, the data argument points to the 
    window object and message argument to the IntuiMessage." */

    AUTO    ULONG class;
    AUTO    UWORD code, qual;
    AUTO    SWORD mousex, mousey, realx, realy, bit;
    PERSIST ULONG count = 0;

    geta4(); // wait till here before doing anything

     class = ((struct IntuiMessage *) msg)->Class;
      code = ((struct IntuiMessage *) msg)->Code;
      qual = ((struct IntuiMessage *) msg)->Qualifier;
    mousex = ((struct IntuiMessage *) msg)->MouseX;
    mousey = ((struct IntuiMessage *) msg)->MouseY;

    if (class == IDCMP_RAWKEY)
    {   switch(code)
        {
        case SCAN_HELP:
            helpabout();
        break;
        case SCAN_ESCAPE:
            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
            {   cleanexit(EXIT_SUCCESS);
            } else page = 0;
        break;
        default:
        break;
    }   }
    else
    {   assert(class == IDCMP_MOUSEBUTTONS);

        if
        (   mousex >= batt_gadgets[GID_9_SP1]->LeftEdge
         && mousex <= batt_gadgets[GID_9_SP1]->LeftEdge + batt_gadgets[GID_9_SP1]->Width
         && mousey >= batt_gadgets[GID_9_SP1]->TopEdge
         && mousey <= batt_gadgets[GID_9_SP1]->TopEdge  + batt_gadgets[GID_9_SP1]->Height
        )
        {   realx = (mousex - batt_gadgets[GID_9_SP1]->LeftEdge - 5) / 8;
            realy = (mousey - batt_gadgets[GID_9_SP1]->TopEdge  - 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;
            if (!(count % 2))
            {   BattBuffer[bit] ^= 1;
                drawbit(bit, WHITE);
                updatebattgadgets();
            }
            count++;
    }   }
    return(1);
}
