/**
 * 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 MUIP_FlagsWin_ShowFlagsMessage {
    ULONG MethodID;
    ULONG value;
    ULONG type;
    void *bitarray;
    void *maskarray;
    UBYTE *title;
};

struct FlagsEntry {
    UBYTE fe_Name[64];
    UBYTE fe_Value[32];
};

static __asm __saveds LONG flaglist_con2func(register __a2 Object *obj, register __a1 struct NList_ConstructMessage *msg, register __a0 struct Hook *hook)
{
    return AllocListEntry(msg->pool, msg->entry, sizeof(struct FlagsEntry));
}

MakeHook(flaglist_con2hook, flaglist_con2func);

static __asm __saveds LONG flaglist_des2func(register __a2 Object *obj, register __a1 struct NList_DestructMessage *msg, register __a0 struct Hook *hook)
{
    FreeListEntry(msg->pool, &msg->entry);

    return 0;
}

MakeHook(flaglist_des2hook, flaglist_des2func);

static __asm __saveds LONG flaglist_dsp2func(register __a2 Object *obj, register __a1 struct NList_DisplayMessage *msg, register __a0 struct Hook *hook)
{
    struct FlagsEntry *fe = (struct FlagsEntry *)msg->entry;

    if (fe) {
        msg->strings[0] = fe->fe_Name;
        msg->strings[1] = fe->fe_Value;
    } else {
        msg->strings[0] = MUIX_B "Name";
        msg->strings[1] = MUIX_B "Value";
    }

    return 0;
}

MakeHook(flaglist_dsp2hook, flaglist_dsp2func);

static __asm __saveds LONG flaglist_cmp2func(register __a2 Object *obj, register __a1 struct NList_CompareMessage *msg, register __a0 struct Hook *hook)
{
    struct FlagsEntry *fe1, *fe2;

    fe1 = (struct FlagsEntry *)msg->entry1;
    fe2 = (struct FlagsEntry *)msg->entry2;

    return stricmp(fe1->fe_Value, fe2->fe_Value);
}

MakeHook(flaglist_cmp2hook, flaglist_cmp2func);

static ULONG __saveds mNew( struct IClass *cl,
                            Object *obj,
                            struct opSet *msg )
{
    APTR flagtext, flaglist;

    if (obj = (Object *)DoSuperNew(cl, obj,
        MUIA_Window_ID, MakeID('F','L','A','G'),
        WindowContents, VGroup,
            Child, HGroup,
                Child, HSpace(0),
                Child, flagtext = MyLabel2(""),
                Child, HSpace(0),
            End,
            Child, flaglist = MyNListviewObject(MakeID('F','L','L','V'), "BAR,BAR", &flaglist_con2hook, &flaglist_des2hook, &flaglist_dsp2hook, &flaglist_cmp2hook, FALSE),
        End,
        TAG_MORE, msg->ops_AttrList))
    {
        struct FlagsWinData *fwd = INST_DATA(cl, obj);
        APTR parent;

        fwd->fwd_FlagsText = flagtext;
        fwd->fwd_FlagsList = flaglist;

        set(obj, MUIA_Window_ActiveObject, flaglist);

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

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

    return (ULONG)obj;
}

static ULONG __saveds mDispose( struct IClass *cl,
                                Object *obj,
                                struct opSet *msg )
{
    struct FlagsWinData *fwd = INST_DATA(cl, obj);

    set(obj, MUIA_Window_Open, FALSE);
    DoMethod(fwd->fwd_FlagsList, MUIM_NList_Clear);

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

static ULONG __saveds mShowFlags( struct IClass *cl,
                                  Object *obj,
                                  Msg msg )
{
    struct FlagsEntry *fe;

    if (fe = tbAllocVecPooled(globalPool, sizeof(struct FlagsEntry))) {
        struct FlagsWinData *fwd = INST_DATA(cl, obj);
        struct MUIP_FlagsWin_ShowFlagsMessage *sfm = (struct MUIP_FlagsWin_ShowFlagsMessage *)msg;
        UBYTE binflags[16];

        switch (sfm->type) {
            case MUIV_FlagsWin_FlagsType_Byte:
                Flags2BinStr(sfm->value, binflags, sizeof(binflags));
                MySetContents(fwd->fwd_FlagsText, "%s = %s", sfm->title, binflags);
                break;

            case MUIV_FlagsWin_FlagsType_Word:
                MySetContents(fwd->fwd_FlagsText, "%s = $%04lx", sfm->title, sfm->value);
                break;

            case MUIV_FlagsWin_FlagsType_Long:
            default:
                MySetContents(fwd->fwd_FlagsText, "%s = $%08lx", sfm->title, sfm->value);
                break;
        }

        if (sfm->bitarray) {
            struct LongFlag *lf = (struct LongFlag *)sfm->bitarray;
            ULONG i;

            i = 0;
            while (lf[i].lf_Name) {
                if (sfm->value & lf[i].lf_Value) {

                    stccpy(fe->fe_Name, lf[i].lf_Name, sizeof(fe->fe_Name));
                    stccpy(fe->fe_Value, lf[i].lf_Text, sizeof(fe->fe_Value));

                    InsertSortedEntry(fwd->fwd_FlagsList, fe);
                }
                i++;
            }
        }
        if (sfm->maskarray) {
            struct MaskedLongFlag *mlf = (struct MaskedLongFlag *)sfm->maskarray;
            ULONG i;

            i = 0;
            while (mlf[i].mlf_Name) {
                if ((sfm->value & mlf[i].mlf_Mask) == mlf[i].mlf_Value) {

                    stccpy(fe->fe_Name, mlf[i].mlf_Name, sizeof(fe->fe_Name));
                    stccpy(fe->fe_Value, mlf[i].mlf_Text, sizeof(fe->fe_Value));

                    InsertSortedEntry(fwd->fwd_FlagsList, fe);
                }
                i++;
            }
        }

        tbFreeVecPooled(globalPool, fe);
    }

    set(obj, MUIA_Window_Open, TRUE);

    return 0;
}

ULONG __asm __saveds FlagsWinDispatcher( 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_FlagsWin_ShowFlags: return (mShowFlags(cl, obj, (APTR)msg));
    }

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

