/**
 * Scout - The Amiga System Monitor
 *
 *------------------------------------------------------------------
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * You must not use this source code to gain profit of any kind!
 *
 *------------------------------------------------------------------
 *
 * @author Andreas Gelhausen
 * @author Richard Körber <rkoerber@gmx.de>
 */

#include "system_headers.h"

struct VectorsCallbackUserData {
    APTR ud_ResetVects;
    APTR ud_AutoVects;
    APTR ud_IntVects[2];
};

void ClearResetVectors( void )
{
    SysBase->ColdCapture = NULL;
    SysBase->CoolCapture = NULL;
    SysBase->WarmCapture = NULL;
    SysBase->KickMemPtr = NULL;
    SysBase->KickTagPtr = NULL;
    SysBase->KickCheckSum = NULL;
}

static void ReceiveList( void (* callback)( struct VectorEntry *ve, void *userData ),
                         void *userData )
{
    struct VectorEntry *ve;

    if (ve = tbAllocVecPooled(globalPool, sizeof(struct VectorEntry))) {
        if (SendDaemon("Vectors")) {
            while (ReceiveDecodedEntry((UBYTE *)ve, sizeof(struct VectorEntry))) {
                callback(ve, userData);
            }
        }

        tbFreeVecPooled(globalPool, ve);
    }
}

static void IterateList( void (* callback)( struct VectorEntry *ve, void *userData ),
                         void *userData )
{
    struct VectorEntry *ve;

    if (ve = tbAllocVecPooled(globalPool, sizeof(struct VectorEntry))) {
        UBYTE *VBR = (UBYTE *)GetVBR();
        ULONG vec;

        _snprintf(ve->ve_ResetVectors[0], sizeof(ve->ve_ResetVectors[0]), "$%08lx", SysBase->ColdCapture);
        _snprintf(ve->ve_ResetVectors[1], sizeof(ve->ve_ResetVectors[1]), "$%08lx", SysBase->CoolCapture);
        _snprintf(ve->ve_ResetVectors[2], sizeof(ve->ve_ResetVectors[2]), "$%08lx", SysBase->WarmCapture);
        _snprintf(ve->ve_ResetVectors[3], sizeof(ve->ve_ResetVectors[3]), "$%08lx", SysBase->KickMemPtr);
        _snprintf(ve->ve_ResetVectors[4], sizeof(ve->ve_ResetVectors[4]), "$%08lx", SysBase->KickTagPtr);
        _snprintf(ve->ve_ResetVectors[5], sizeof(ve->ve_ResetVectors[5]), "$%08lx", SysBase->KickCheckSum);

        for (vec = 0; vec < 7; vec++) _snprintf(ve->ve_AutoVectors[vec], sizeof(ve->ve_AutoVectors[vec]), "$%08lx", *((ULONG *)(VBR + 0x0064 + vec * sizeof(ULONG))));

        for (vec = 0; vec < 16; vec++ ) _snprintf(ve->ve_IntVectors[vec], sizeof(ve->ve_IntVectors[vec]), "$%08lx", SysBase->IntVects[vec].iv_Code);

        callback(ve, userData);

        tbFreeVecPooled(globalPool, ve);
    }
}

static void UpdateCallback( struct VectorEntry *ve,
                            void *userData )
{
    struct VectorsCallbackUserData *ud = (struct VectorsCallbackUserData *)userData;

    MySetContents(ud->ud_ResetVects, MUIX_R "%s\n%s\n%s\n%s\n%s\n%s", ve->ve_ResetVectors[0], ve->ve_ResetVectors[1], ve->ve_ResetVectors[2], ve->ve_ResetVectors[3], ve->ve_ResetVectors[4], ve->ve_ResetVectors[5]);
    MySetContents(ud->ud_AutoVects, MUIX_R "%s\n%s\n%s\n%s\n%s\n%s\n%s", ve->ve_AutoVectors[0], ve->ve_AutoVectors[1], ve->ve_AutoVectors[2], ve->ve_AutoVectors[3], ve->ve_AutoVectors[4], ve->ve_AutoVectors[5], ve->ve_AutoVectors[6]);
    MySetContents(ud->ud_IntVects[0], MUIX_R "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", ve->ve_IntVectors[ 0], ve->ve_IntVectors[ 1], ve->ve_IntVectors[ 2], ve->ve_IntVectors[ 3], ve->ve_IntVectors[ 4], ve->ve_IntVectors[ 5], ve->ve_IntVectors[ 6], ve->ve_IntVectors[ 7]);
    MySetContents(ud->ud_IntVects[1], MUIX_R "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", ve->ve_IntVectors[ 8], ve->ve_IntVectors[ 9], ve->ve_IntVectors[10], ve->ve_IntVectors[11], ve->ve_IntVectors[12], ve->ve_IntVectors[13], ve->ve_IntVectors[14], ve->ve_IntVectors[15]);
}

static void PrintCallback( struct VectorEntry *ve,
                           void *userData )
{
    PrintFOneLine((BPTR)userData, "\nReset Vectors:\n\n");
    PrintFOneLine((BPTR)userData, " ColdCapture   : %s     KickMemPtr    : %s\n", ve->ve_ResetVectors[0], ve->ve_ResetVectors[3]);
    PrintFOneLine((BPTR)userData, " CoolCapture   : %s     KickTagPtr    : %s\n", ve->ve_ResetVectors[1], ve->ve_ResetVectors[4]);
    PrintFOneLine((BPTR)userData, " WarmCapture   : %s     KickCheckSum  : %s\n", ve->ve_ResetVectors[2], ve->ve_ResetVectors[5]);

    PrintFOneLine((BPTR)userData, "\nAuto Vector Interrupts:\n\n");
    PrintFOneLine((BPTR)userData, " Level1 ($0064): %s     Level5 ($0074): %s\n", ve->ve_AutoVectors[0], ve->ve_AutoVectors[4]);
    PrintFOneLine((BPTR)userData, " Level2 ($0068): %s     Level6 ($0078): %s\n", ve->ve_AutoVectors[1], ve->ve_AutoVectors[5]);
    PrintFOneLine((BPTR)userData, " Level3 ($006c): %s     Level7 ($007c): %s\n", ve->ve_AutoVectors[2], ve->ve_AutoVectors[6]);
    PrintFOneLine((BPTR)userData, " Level4 ($0070): %s\n",                        ve->ve_AutoVectors[3]);

    PrintFOneLine((BPTR)userData, "\nInterrupt Vectors:\n\n");
    PrintFOneLine((BPTR)userData, " TBE      0    : %s     AUDIO1   8    : %s\n", ve->ve_IntVectors[ 0], ve->ve_IntVectors[ 8]);
    PrintFOneLine((BPTR)userData, " DISKBLK  1    : %s     AUDIO2   9    : %s\n", ve->ve_IntVectors[ 1], ve->ve_IntVectors[ 9]);
    PrintFOneLine((BPTR)userData, " SOFTINT  2    : %s     AUDIO3  10    : %s\n", ve->ve_IntVectors[ 2], ve->ve_IntVectors[10]);
    PrintFOneLine((BPTR)userData, " PORTS    3    : %s     RBF     11    : %s\n", ve->ve_IntVectors[ 3], ve->ve_IntVectors[11]);
    PrintFOneLine((BPTR)userData, " COPPER   4    : %s     DSKSYNC 12    : %s\n", ve->ve_IntVectors[ 4], ve->ve_IntVectors[12]);
    PrintFOneLine((BPTR)userData, " VERTB    5    : %s     EXTER   13    : %s\n", ve->ve_IntVectors[ 5], ve->ve_IntVectors[13]);
    PrintFOneLine((BPTR)userData, " BLITTER  6    : %s     INTEN   14    : %s\n", ve->ve_IntVectors[ 6], ve->ve_IntVectors[14]);
    PrintFOneLine((BPTR)userData, " AUDIO0   7    : %s     NMI     15    : %s\n", ve->ve_IntVectors[ 7], ve->ve_IntVectors[15]);
}

static void SendCallback( struct VectorEntry *ve,
                          void *userData )
{
    SendEncodedEntry((UBYTE *)ve, sizeof(struct VectorEntry));
}

static ULONG __saveds mNew( struct IClass *cl,
                            Object *obj,
                            struct opSet *msg )
{
    static UBYTE *vectorPages[] = { "ResetVecs", "AutoVecInts", "IntVecs", NULL };
    APTR pages, resetVectText, autoVectText, intVect1Text, intVect2Text, updateButton, printButton, exitButton;

    if (obj = (Object *)DoSuperNew(cl, obj,
        MUIA_HelpNode, VectorsText,
        MUIA_Window_ID, MakeID('V','E','C','T'),
        WindowContents, VGroup,

            Child, pages = RegisterGroup(vectorPages),

                Child, HGroup,
                    GroupFrameT("Reset Vectors"),
                    Child, HGroup,
                        Child, MyLabel2(MUIX_R "ColdCapture:\nCoolCapture:\nWarmCapture:\nKickMemPtr:\nKickTagPtr:\nKickCheckSum:"),
                        Child, resetVectText = MyTextObject2(),
                    End,
                End,

                Child, HGroup,
                    GroupFrameT("Auto Vector Interrupts"),
                    Child, HGroup,
                        Child, MyLabel2(MUIX_R "Level1 ($0064):\nLevel2 ($0068):\nLevel3 ($006c):\nLevel4 ($0070):\nLevel5 ($0074):\nLevel6 ($0078):\nLevel7 ($007c):"),
                        Child, autoVectText = MyTextObject2(),
                    End,
                End,

                Child, HGroup,
                    GroupFrameT("Interrupt Vectors"),
                    Child, HGroup,
                        Child, MyLabel(MUIX_R "TBE\nDSKBLK\nSOFTINT\nPORTS\nCOPPER\nVERTB\nBLITTER\nAUDIO0"),
                        Child, MyLabel(MUIX_R " 0:\n1:\n2:\n3:\n4:\n5:\n6:\n7:"),
                        Child, intVect1Text = MyTextObject2(),
                    End,
                    Child, HGroup,
                        Child, MyLabel (MUIX_R "AUDIO1\nAUDIO2\nAUDIO3\nRBF\nDSKSYNC\nEXTER\nINTEN\nNMI"),
                        Child, MyLabel (MUIX_R "8:\n9:\n10:\n11:\n12:\n13:\n14:\n15:"),
                        Child, intVect2Text = MyTextObject2(),
                    End,
                End,
            End,

            Child, MyVSpace(4),

            Child, HGroup, MUIA_Group_SameSize, TRUE,
                Child, updateButton = MakeButton(txtUpdate),
                Child, printButton  = MakeButton(txtPrint),
                Child, exitButton   = MakeButton(txtExit),
            End,
        End,
        TAG_MORE, msg->ops_AttrList))
    {
        struct VectorsWinData *vwd = INST_DATA(cl, obj);
        APTR parent;

        vwd->vwd_ResetVectorText = resetVectText;
        vwd->vwd_AutoVectorText = autoVectText;
        vwd->vwd_InterruptVector1Text = intVect1Text;
        vwd->vwd_InterruptVector2Text = intVect2Text;

        parent = (APTR)GetTagData(MUIA_Window_ParentWindow, (ULONG)NULL, msg->ops_AttrList);

        set(obj, MUIA_Window_Title, MyGetWindowTitle("VECTORS", vwd->vwd_Title, sizeof(vwd->vwd_Title)));
        set(obj, MUIA_Window_ActiveObject, pages);
        set(pages, MUIA_CycleChain, TRUE);
        MySetContents(vwd->vwd_ResetVectorText, MUIX_R "$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", 0, 0, 0, 0, 0, 0);
        MySetContents(vwd->vwd_AutoVectorText, MUIX_R "$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", 0, 0, 0, 0, 0, 0, 0);
        MySetContents(vwd->vwd_InterruptVector1Text, MUIX_R "$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", 0, 0, 0, 0, 0, 0, 0, 0);
        MySetContents(vwd->vwd_InterruptVector2Text, MUIX_R "$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", 0, 0, 0, 0, 0, 0, 0, 0);

        DoMethod(parent,       MUIM_Window_AddChildWindow, obj);
        DoMethod(obj,          MUIM_Notify, MUIA_Window_CloseRequest, TRUE,  MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_Window_RemChildWindow, obj);
        DoMethod(updateButton, MUIM_Notify, MUIA_Pressed,             FALSE, obj,                     1, MUIM_VectorsWin_Update);
        DoMethod(printButton,  MUIM_Notify, MUIA_Pressed,             FALSE, obj,                     1, MUIM_VectorsWin_Print);
        DoMethod(exitButton,   MUIM_Notify, MUIA_Pressed,             FALSE, obj,                     3, MUIM_Set, MUIA_Window_CloseRequest, TRUE);
    }

    return (ULONG)obj;
}

static ULONG __saveds mDispose( struct IClass *cl,
                                Object *obj,
                                struct opSet *msg )
{
    set(obj, MUIA_Window_Open, FALSE);

    return (DoSuperMethodA(cl, obj, msg));
}

static ULONG __saveds mUpdate( struct IClass *cl,
                               Object *obj,
                               Msg msg )
{
    struct VectorsWinData *vwd = INST_DATA(cl, obj);
    struct VectorsCallbackUserData ud;

    ud.ud_ResetVects = vwd->vwd_ResetVectorText;
    ud.ud_AutoVects = vwd->vwd_AutoVectorText;
    ud.ud_IntVects[0] = vwd->vwd_InterruptVector1Text;
    ud.ud_IntVects[1] = vwd->vwd_InterruptVector2Text;

    if (clientstate) {
        ReceiveList(UpdateCallback, &ud);
    } else {
        IterateList(UpdateCallback, &ud);
    }

    return 0;
}

static ULONG __saveds mPrint( struct IClass *cl,
                              Object *obj,
                              Msg msg )
{
    PrintVectors(NULL);

    return 0;
}

ULONG __asm __saveds VectorsWinDispatcher( register __a0 struct IClass *cl,
                                           register __a2 Object *obj,
                                           register __a1 Msg msg )
{
    switch (msg->MethodID) {
        case OM_NEW:                 return (mNew(cl, obj, (APTR)msg));
        case OM_DISPOSE:             return (mDispose(cl, obj, (APTR)msg));
        case MUIM_VectorsWin_Update: return (mUpdate(cl, obj, (APTR)msg));
        case MUIM_VectorsWin_Print:  return (mPrint(cl, obj, (APTR)msg));
    }

    return (DoSuperMethodA(cl, obj, msg));
}

void PrintVectors( char *filename )
{
    BPTR handle;

    if (handle = HandlePrintStart(filename)) {
        IterateList(PrintCallback, (void *)handle);
    }

    HandlePrintStop();
}

void SendVectorList( void )
{
    IterateList(SendCallback, NULL);
}

