/**
 * 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"

static struct LongFlag propertyFlags[] = {
    { DIPF_IS_LACE             , "DIPF_IS_LACE"             , "$00000001" },
    { DIPF_IS_DUALPF           , "DIPF_IS_DUALPF"           , "$00000002" },
    { DIPF_IS_PF2PRI           , "DIPF_IS_PF2PRI"           , "$00000004" },
    { DIPF_IS_HAM              , "DIPF_IS_HAM"              , "$00000008" },
    { DIPF_IS_ECS              , "DIPF_IS_ECS"              , "$00000010" },
    { DIPF_IS_PAL              , "DIPF_IS_PAL"              , "$00000020" },
    { DIPF_IS_SPRITES          , "DIPF_IS_SPRITES"          , "$00000040" },
    { DIPF_IS_GENLOCK          , "DIPF_IS_GENLOCK"          , "$00000080" },
    { DIPF_IS_WB               , "DIPF_IS_WB"               , "$00000100" },
    { DIPF_IS_DRAGGABLE        , "DIPF_IS_DRAGGABLE"        , "$00000200" },
    { DIPF_IS_PANELLED         , "DIPF_IS_PANELLED"         , "$00000400" },
    { DIPF_IS_BEAMSYNC         , "DIPF_IS_BEAMSYNC"         , "$00000800" },
    { DIPF_IS_EXTRAHALFBRITE   , "DIPF_IS_EXTRAHALFBRITE"   , "$00001000" },
    { DIPF_IS_SPRITES_ATT      , "DIPF_IS_SPRITES_ATT"      , "$00002000" },
    { DIPF_IS_SPRITES_CHNG_RES , "DIPF_IS_SPRITES_CHNG_RES" , "$00004000" },
    { DIPF_IS_SPRITES_BORDER   , "DIPF_IS_SPRITES_BORDER"   , "$00008000" },
    { DIPF_IS_AA               , "DIPF_IS_AA"               , "$00010000" },
    { DIPF_IS_SCANDBL          , "DIPF_IS_SCANDBL"          , "$00020000" },
    { DIPF_IS_SPRITES_CHNG_BASE, "DIPF_IS_SPRITES_CHNG_BASE", "$00040000" },
    { DIPF_IS_SPRITES_CHNG_PRI , "DIPF_IS_SPRITES_CHNG_PRI" , "$00080000" },
    { DIPF_IS_DBUFFER          , "DIPF_IS_DBUFFER"          , "$00100000" },
    { DIPF_IS_PROGBEAM         , "DIPF_IS_PROGBEAM"         , "$00200000" },
    { DIPF_IS_FOREIGN          , "DIPF_IS_FOREIGN"          , "$80000000" },
    { 0,                         NULL,                        NULL }
};

static struct LongFlag notAvailFlags[] = {
    { DI_AVAIL_NOCHIPS       , "DI_AVAIL_NOCHIPS"       , "$0001" },
    { DI_AVAIL_NOMONITOR     , "DI_AVAIL_NOMONITOR"     , "$0002" },
    { DI_AVAIL_NOTWITHGENLOCK, "DI_AVAIL_NOTWITHGENLOCK", "$0004" },
    { 0,                       NULL,                      NULL }
};

static void SetDetails( struct IClass *cl,
                        Object *obj,
                        struct ScreenModeEntry *sme )
{
    struct ScreenModesDetailWinData *smdwd = INST_DATA(cl, obj);
    struct DisplayInfo iddisp;
    struct DimensionInfo iddims;
    struct MonitorInfo idmntr;
    struct NameInfo idname;
    ULONG fh, fv;
    UBYTE colors[20];
    ULONG tcc;
    UBYTE *compathelp;

    GetDisplayInfoData(NULL, (UBYTE *)&iddisp, sizeof(struct DisplayInfo)  , DTAG_DISP, sme->sme_ModeID);
    GetDisplayInfoData(NULL, (UBYTE *)&iddims, sizeof(struct DimensionInfo), DTAG_DIMS, sme->sme_ModeID);
    GetDisplayInfoData(NULL, (UBYTE *)&idmntr, sizeof(struct MonitorInfo)  , DTAG_MNTR, sme->sme_ModeID);

    if (GetDisplayInfoData(NULL, (UBYTE *)&idname, sizeof(struct NameInfo), DTAG_NAME, sme->sme_ModeID)) {
        MySetContents(smdwd->smdwd_ScreenModeMoreText[0], "%s", idname.Name);
    } else {
        MySetContents(smdwd->smdwd_ScreenModeMoreText[0], MUIX_PH "%s" MUIX_PT, sme->sme_Name);
    }
    MySetContents(smdwd->smdwd_ScreenModeMoreText[6], "$%08lx \"%s\" (OpenCnt=%ld)", idmntr.Mspc, idmntr.Mspc->ms_Node.xln_Name, (WORD)idmntr.Mspc->ms_OpenCount);

    MySetContents(smdwd->smdwd_ScreenModeMoreText[1], MUIX_B "$%08lx", iddisp.PropertyFlags);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[2], MUIX_B "$%04lx", iddisp.NotAvailable);

    smdwd->smdwd_PropertyFlags = iddisp.PropertyFlags;
    smdwd->smdwd_NotAvailFlags = iddisp.NotAvailable;

    fv = 1000000L / (idmntr.TotalColorClocks * 28);
    fh = (fv * 100) / idmntr.TotalRows;
    tcc = idmntr.TotalColorClocks * 280;

    if (iddisp.PropertyFlags & DIPF_IS_DUALPF) {
       _snprintf(colors, sizeof(colors), "2x%ld",1 << (iddims.MaxDepth >> 1));
    } else if (iddisp.PropertyFlags & DIPF_IS_HAM) {
       _snprintf(colors, sizeof(colors), "[%ld]",1 << (3 * (iddims.MaxDepth - 2)));
    } else if (iddims.MaxDepth > 24) {
       stccpy(colors, "> 16.8M", sizeof(colors));
    } else {
       _snprintf(colors, sizeof(colors), "%lD", 1 << iddims.MaxDepth);
    }

    MySetContents(smdwd->smdwd_ScreenModeMoreText[ 3], MUIX_R "%ld ns\n%ld x %ld", iddisp.PixelSpeed, iddisp.Resolution.x, iddisp.Resolution.y);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[ 4], MUIX_R "%ld\n%ld x %ld", iddisp.NumStdSprites, iddisp.SpriteResolution.x, iddisp.SpriteResolution.y);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[ 5], MUIX_R "%ld\n%ld:%ld:%ld", iddisp.PaletteRange, iddisp.RedBits, iddisp.GreenBits, iddisp.BlueBits);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[ 7], MUIX_R "%ld\n%ld\n%ld.%03ld µs\n%ld", idmntr.TotalRows, idmntr.TotalColorClocks, tcc / 1000, tcc % 1000, idmntr.MinRow);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[ 8], MUIX_C "%5ld x %5ld\n%5ld x %5ld", iddims.MinRasterWidth, iddims.MinRasterHeight, iddims.MaxRasterWidth, iddims.MaxRasterHeight);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[ 9], MUIX_C "%4ld x %4ld\n%4ld x %4ld", iddims.Nominal.MaxX-iddims.Nominal.MinX + 1, iddims.Nominal.MaxY-iddims.Nominal.MinY + 1, iddims.Nominal.MinX, iddims.Nominal.MinY);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[10], MUIX_C "%4ld x %4ld\n%4ld x %4ld", iddims.StdOScan.MaxX-iddims.StdOScan.MinX + 1, iddims.StdOScan.MaxY-iddims.StdOScan.MinY + 1, iddims.StdOScan.MinX, iddims.StdOScan.MinY);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[11], MUIX_C "%4ld x %4ld\n%4ld x %4ld", iddims.TxtOScan.MaxX-iddims.TxtOScan.MinX + 1, iddims.TxtOScan.MaxY-iddims.TxtOScan.MinY + 1, iddims.TxtOScan.MinX, iddims.TxtOScan.MinY);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[12], MUIX_C "%4ld x %4ld\n%4ld x %4ld", iddims.VideoOScan.MaxX-iddims.VideoOScan.MinX + 1, iddims.VideoOScan.MaxY-iddims.VideoOScan.MinY + 1, iddims.VideoOScan.MinX, iddims.VideoOScan.MinY);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[13], MUIX_C "%4ld x %4ld\n%4ld x %4ld", iddims.MaxOScan.MaxX-iddims.MaxOScan.MinX + 1, iddims.MaxOScan.MaxY-iddims.MaxOScan.MinY + 1, iddims.MaxOScan.MinX, iddims.MaxOScan.MinY);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[14], MUIX_C "%4ld x %4ld\n%4ld x %4ld\n%4ld x %4ld\n%4ld x %4ld\n%4ld x %4ld", idmntr.ViewPosition.x, idmntr.ViewPosition.y, idmntr.DefaultViewPosition.x, idmntr.DefaultViewPosition.y, idmntr.ViewResolution.x, idmntr.ViewResolution.y, idmntr.ViewPositionRange.MinX, idmntr.ViewPositionRange.MinY, idmntr.ViewPositionRange.MaxX, idmntr.ViewPositionRange.MaxY);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[15], MUIX_R "$%08lx\n$%08lx", sme->sme_ModeID, idmntr.PreferredModeID);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[16], "%2ld", idmntr.Compatibility);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[18], MUIX_R "%ld kHz\n%ld Hz",fv / 10, fh);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[19], MUIX_R "%ld\n%s",iddims.MaxDepth, colors);
    MySetContents(smdwd->smdwd_ScreenModeMoreText[20], MUIX_R "%ld x %ld", idmntr.MouseTicks.x, idmntr.MouseTicks.y);

    switch(idmntr.Compatibility) {
        case MCOMPAT_MIXED:
            compathelp = msgScreenModeCompatMixed;
            break;

        case MCOMPAT_SELF:
            compathelp = msgScreenModeCompatSelf;
            break;

        case MCOMPAT_NOBODY:
            compathelp = msgScreenModeCompatNobody;
            break;

        default:
            compathelp = MUIX_PH "< ??? >" MUIX_PT;
    }
    MySetContents(smdwd->smdwd_ScreenModeMoreText[17], "%s", compathelp);

    set(obj, MUIA_Window_Title, MyGetChildWindowTitle("SCREENMODE", sme->sme_Name, smdwd->smdwd_Title, sizeof(smdwd->smdwd_Title)));
}

static ULONG __saveds mNew( struct IClass *cl,
                            Object *obj,
                            struct opSet *msg )
{
    APTR smodemoretext[21];

    if (obj = (Object *)DoSuperNew(cl, obj,
        MUIA_HelpNode, ScreenModeText,
        MUIA_Window_ID, MakeID('.','S','M','D'),
        WindowContents, VGroup,

            Child, ColGroup(2),
                Child, MyLabel2("Name:"),
                Child, smodemoretext[0] = MyTextObject(),
                Child, MyLabel2("Monitor:"),
                Child, smodemoretext[6] = MyTextObject(),
                Child, MyLabel2("Compatibility:"),
                Child, HGroup,
                    Child, smodemoretext[16] = MyTextObject2(),
                    Child, MyLabel2("="),
                    Child, smodemoretext[17] = MyTextObject(),
                End,
            End,
            Child, HGroup,
                Child, VGroup,
                    Child, MyLabel2("ModeID:\nPreferred:"),
                    Child, MyLabel2("Property:"),
                    Child, MyLabel2("NotAvail:"),
                    Child, MyLabel2("PixelSpeed:\nTicks/Pixel:"),
                    Child, MyLabel2("StdSprites:\nTicks/Pixel:"),
                    Child, MyLabel2("Palette:\nRGB bits:"),
                    Child, MyLabel2("MouseTicks:"),
                End,
                Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
                    Child, smodemoretext[15] = MyTextObject(),
                    Child, smodemoretext[ 1] = MakeButton(""),
                    Child, smodemoretext[ 2] = MakeButton(""),
                    Child, smodemoretext[ 3] = MyTextObject(),
                    Child, smodemoretext[ 4] = MyTextObject(),
                    Child, smodemoretext[ 5] = MyTextObject(),
                    Child, smodemoretext[20] = MyTextObject(),
                End,
                Child, HSpace(0),
                Child, VGroup,
                    Child, MyLabel2("MinRaster:\nMaxRaster:"),
                    Child, MyLabel2("Nominal:\nOffset:"),
                    Child, MyLabel2("TxtOScan:\nOffset:"),
                    Child, MyLabel2("StdOScan:\nOffset:"),
                    Child, MyLabel2("MaxOScan:\nOffset:"),
                    Child, MyLabel2("VideoOScan:\nOffset:"),
                End,
                Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
                    Child, smodemoretext[ 8] = MyTextObject(),
                    Child, smodemoretext[ 9] = MyTextObject(),
                    Child, smodemoretext[11] = MyTextObject(),
                    Child, smodemoretext[10] = MyTextObject(),
                    Child, smodemoretext[13] = MyTextObject(),
                    Child, smodemoretext[12] = MyTextObject(),
                End,
                Child, HSpace(0),
                Child, VGroup,
                    Child, MyLabel2("Depth:\nColors:"),
                    Child, MyLabel2("H freq.:\nV freq.:"),
                    Child, MyLabel2("TotalRows:\nColorClocks:\n=\nMinRow:"),
                    Child, MyLabel2("ViewPosition:\nDefault VP:\nViewResolution:\nVP Range min:\nmax:"),
                End,
                Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
                    Child, smodemoretext[19] = MyTextObject(),
                    Child, smodemoretext[18] = MyTextObject(),
                    Child, smodemoretext[ 7] = MyTextObject(),
                    Child, smodemoretext[14] = MyTextObject(),
                End,
            End,
        End,
        TAG_MORE, msg->ops_AttrList))
    {
        struct ScreenModesDetailWinData *smdwd = INST_DATA(cl, obj);
        APTR parent;

        CopyMem(smodemoretext, smdwd->smdwd_ScreenModeMoreText, sizeof(smdwd->smdwd_ScreenModeMoreText));

        set(obj, MUIA_Window_ActiveObject, smodemoretext[1]);

        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);
        DoMethod(smodemoretext[1], MUIM_Notify,              MUIA_Pressed            , FALSE, obj,              1, MUIM_ScreenModesDetailWin_PropertyFlagsMore);
        DoMethod(smodemoretext[2], MUIM_Notify,              MUIA_Pressed            , FALSE, obj,              1, MUIM_ScreenModesDetailWin_NotAvailFlagsMore);
    }

    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 mSet( struct IClass *cl,
                            Object *obj,
                            Msg msg )
{
    struct TagItem *tags, *tag;

    for (tags = ((struct opSet *)msg)->ops_AttrList; tag = NextTagItem(&tags); ) {
        switch (tag->ti_Tag) {
            case MUIA_Window_ParentWindow:
                DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, MUIV_Notify_Application, 5, MUIM_Application_PushMethod, tag->ti_Data, 2, MUIM_Window_RemChildWindow, obj);
                break;

            case MUIA_ScreenModesDetailWin_ScreenMode:
                SetDetails(cl, obj, (struct ScreenModeEntry *)tag->ti_Data);
                break;
        }
    }

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

static ULONG __saveds mPropertyFlagsMore( struct IClass *cl,
                                          Object *obj,
                                          Msg msg )
{
    struct ScreenModesDetailWinData *smdwd = INST_DATA(cl, obj);
    APTR flagsWin;

    if (flagsWin = FlagsWindowObject,
            MUIA_Window_Title, "Property Flags",
            MUIA_Window_ParentWindow, obj,
        End) {
        DoMethod(flagsWin, MUIM_FlagsWin_ShowFlags, smdwd->smdwd_PropertyFlags, MUIV_FlagsWin_FlagsType_Long, propertyFlags, NULL, "PropertyFlags");
    }

    return 0;
}

static ULONG __saveds mNotAvailFlagsMore( struct IClass *cl,
                                          Object *obj,
                                          Msg msg )
{
    struct ScreenModesDetailWinData *smdwd = INST_DATA(cl, obj);
    APTR flagsWin;

    if (flagsWin = FlagsWindowObject,
            MUIA_Window_Title, "NotAvailable",
            MUIA_Window_ParentWindow, obj,
        End) {
        DoMethod(flagsWin, MUIM_FlagsWin_ShowFlags, smdwd->smdwd_NotAvailFlags, MUIV_FlagsWin_FlagsType_Word, notAvailFlags, NULL, "NotAvailable");
    }

    return 0;
}

ULONG __asm __saveds ScreenModesDetailWinDispatcher( 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 OM_SET:                                      return (mSet(cl, obj, (APTR)msg));
        case MUIM_ScreenModesDetailWin_PropertyFlagsMore: return (mPropertyFlagsMore(cl, obj, (APTR)msg));
        case MUIM_ScreenModesDetailWin_NotAvailFlagsMore: return (mNotAvailFlagsMore(cl, obj, (APTR)msg));
    }

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

