/**
 * 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 void SetDetails( struct IClass *cl,
                        Object *obj,
                        struct MountEntry *me )
{
    struct MountsDetailWinData *mdwd = INST_DATA(cl, obj);
    UBYTE *tmp1, *tmp2;
    struct InfoData *id;
    static ULONG memtype[]  = { MEMF_PUBLIC, MEMF_CHIP, MEMF_FAST, MEMF_LOCAL,MEMF_24BITDMA, MEMF_KICK, MEMF_CLEAR, MEMF_LARGEST, MEMF_REVERSE, MEMF_TOTAL, MEMF_ANY };
    static UBYTE *memtypetext[] = { "PUBLIC", "CHIP", "FAST", "LOCAL", "24BITDMA", "KICK", "CLEAR", "LARGEST", "REVERSE", "TOTAL" };

    NoReqOn();

    tmp1 = tbAllocVecPooled(globalPool, PATH_LENGTH);
    tmp2 = tbAllocVecPooled(globalPool, PATH_LENGTH);
    id = tbAllocVecPooled(globalPool, sizeof(struct InfoData));

    if (tmp1 != NULL && tmp2 != NULL && id != NULL) {
        struct DeviceNode *dn = me->me_Device;
        BPTR lock;
        struct FileSysStartupMsg *fssm;

        fssm = (struct FileSysStartupMsg *)BADDR(dn->dn_Startup);

        MySetContents(mdwd->mdwd_MountsMoreText[ 0], me->me_Name);
        MySetContents(mdwd->mdwd_MountsMoreText[ 1], MUIX_R "$%08lx\n" MUIX_R "$%08lx\n" MUIX_R "$%08lx", BADDR(dn->dn_Next), dn->dn_Task, BADDR(dn->dn_Startup));
        MySetContents(mdwd->mdwd_MountsMoreText[ 2], MUIX_R "%lD\n" MUIX_R "%lD\n" MUIX_R "%lD", dn->dn_Type, dn->dn_StackSize, dn->dn_Priority);
        MySetContents(mdwd->mdwd_MountsMoreText[ 3], MUIX_R "$%08lx", dn);
        MySetContents(mdwd->mdwd_MountsMoreText[ 4], MUIX_R "$%08lx\n" MUIX_R "$%08lx\n" MUIX_R "$%08lx", BADDR(dn->dn_Lock), BADDR(dn->dn_SegList), BADDR(dn->dn_GlobalVec));
        MySetContents(mdwd->mdwd_MountsMoreText[ 5], me->me_Handler);

        if ((ULONG)fssm > 42) {
            MySetContents(mdwd->mdwd_MountsMoreText[ 6], MUIX_C "%s", txtNoDisk);
            MySetContents(mdwd->mdwd_MountsMoreText[ 8], MUIX_C "---");
            b2cstrn(dn->dn_Name, tmp1, PATH_LENGTH);
            _strcatn(tmp1, ":", PATH_LENGTH);
            if (lock = Lock(tmp1, SHARED_LOCK)) {
                if (Info(lock, id)) {
                    MySetContents(mdwd->mdwd_MountsMoreText[ 6], MUIX_C "%s", GetDiskState(&id->id_DiskState));
                    MySetContents(mdwd->mdwd_MountsMoreText[ 8], MUIX_C "%s", GetDiskType(&id->id_DiskType));
                }
                UnLock(lock);
            } else {
                struct MsgPort *mp;

                if (mp = CreateMsgPort()) {
                    struct IOStdReq *io;

                    if (io = CreateIORequest(mp, sizeof(struct IOStdReq))) {
                        if (OpenDevice(me->me_DeviceName, fssm->fssm_Unit, (struct IORequest *)io, fssm->fssm_Flags) == 0) {
                            io->io_Command = TD_CHANGESTATE;
                            DoIO((struct IORequest *)io);
                            if (io->io_Error == 0) {
                                if (io->io_Actual) {
                                    MySetContents(mdwd->mdwd_MountsMoreText[ 6], MUIX_C "%s", txtNoDisk);
                                } else {
                                    MySetContents(mdwd->mdwd_MountsMoreText[ 6], MUIX_C "%s", txtUnreadable);
                                }
                            } else {
                                MySetContents(mdwd->mdwd_MountsMoreText[ 6], MUIX_C "%s", txtNoDisk);
                            }

                            CloseDevice ((struct IORequest *)io);
                        } else {
                           MySetContents(mdwd->mdwd_MountsMoreText[ 6], MUIX_C "%s", txtNoDisk);
                        }

                        DeleteIORequest(io);
                    }

                    DeleteMsgPort(mp);
                }

                MySetContents(mdwd->mdwd_MountsMoreText[ 8], MUIX_C "---");
            }

            MySetContents(mdwd->mdwd_MountsMoreText[ 7], "%s/%s", me->me_DeviceName, me->me_Unit);

            if ((ULONG)fssm > 42) {
                struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
                bigint size, cmp, div, quot, rem;
                UBYTE *sizetext;

                MySetContents(mdwd->mdwd_MountsMoreText[ 9], MUIX_R "$%08lx", de);
                MySetContents(mdwd->mdwd_MountsMoreText[10], MUIX_R "$%08lx", fssm->fssm_Flags);

                _snprintf(tmp1, PATH_LENGTH, MUIX_R "%lD\n" MUIX_R "$%08lx\n" MUIX_R "$%08lx\n" MUIX_R "$%08lx\n" MUIX_R "$%08lx\n" MUIX_R "$%08lx\n", de->de_TableSize, de->de_SecOrg, de->de_Reserved, de->de_PreAlloc, de->de_Interleave, de->de_SizeBlock);
                if (de->de_TableSize >= DE_MAXTRANSFER) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_R "$%08lx", de->de_MaxTransfer);
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---", PATH_LENGTH);
                }
                MySetContents(mdwd->mdwd_MountsMoreText[11], tmp1);

                MySetContents(mdwd->mdwd_MountsMoreText[12], MUIX_R "%lD\n" MUIX_R "%lD\n" MUIX_R "%lD\n" MUIX_R "%lD\n" MUIX_R "%lD\n" MUIX_R "%lD\n" MUIX_R "%lD", UMult32(de->de_SizeBlock << 2, de->de_SectorPerBlock), de->de_Surfaces, de->de_SectorPerBlock, de->de_BlocksPerTrack, de->de_LowCyl, de->de_HighCyl, de->de_NumBuffers);

                tmp1[0] = 0x00;
                if (de->de_TableSize >= DE_MASK) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_C "$%08lx\n", de->de_Mask);
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---\n", PATH_LENGTH);
                }
                if (de->de_TableSize >= DE_BOOTPRI) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_C "%ld\n", de->de_BootPri);
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---\n", PATH_LENGTH);
                }
                if (de->de_TableSize >= DE_DOSTYPE) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_C "%s\n", GetDiskType((LONG *)&de->de_DosType));
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---\n", PATH_LENGTH);
                }
                if (de->de_TableSize >= DE_BAUD) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_C "%ld\n", de->de_Baud);
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---\n", PATH_LENGTH);
                }
                if (de->de_TableSize >= DE_CONTROL) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_C "$%08lx\n", de->de_Control);
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---\n", PATH_LENGTH);
                }
                if (de->de_TableSize >= DE_BOOTBLOCKS) {
                    _snprintf(tmp2, PATH_LENGTH, MUIX_C "%ld\n", de->de_BootBlocks);
                    _strcatn(tmp1, tmp2, PATH_LENGTH);
                } else {
                    _strcatn(tmp1, "---\n", PATH_LENGTH);
                }

                size = i64_set(0);
                rem = i64_set(0);

                if (de->de_Surfaces) {
                    bigint sizeBlock, surfaces, blocksPerTrack, cylinders;

                    sizeBlock = i64_set(de->de_SizeBlock << 2);
                    surfaces = i64_set(de->de_Surfaces);
                    blocksPerTrack = i64_set(de->de_BlocksPerTrack);
                    cylinders = i64_set(de->de_HighCyl - de->de_LowCyl + 1);
                    size = i64_mul(sizeBlock, i64_mul(surfaces, i64_mul(blocksPerTrack, cylinders)));
                }

                cmp = i64_set(1024 * 1024 * 10000);
                if (i64_cmp(size, cmp) == I64_GREATER) {
                    sizetext = "GB";
                    size = i64_urshift(size, 26);
                } else {
                    cmp = i64_set(1024 * 10000);
                    if (i64_cmp(size, cmp) == I64_GREATER) {
                        sizetext = "MB";
                        size = i64_urshift(size, 16);
                    } else {
                        cmp = i64_set(10000);
                        if (i64_cmp(size, cmp) == I64_GREATER) {
                            sizetext = "KB";
                            size = i64_urshift(size, 6);
                        } else {
                            sizetext = " bytes";
                        }
                    }
                }

                div = i64_set(16);
                i64_udiv(size, div, &quot, &rem);

                div = i64_set(10);
                rem = i64_urshift(i64_mul(rem, div), 4);

                size = i64_urshift(size, 4);

                i64_itoa(size, tmp2, 10);
                _strcatn(tmp1, tmp2, PATH_LENGTH);
                _strcatn(tmp1, ".", PATH_LENGTH);
                i64_itoa(rem, tmp2, 10);
                _strcatn(tmp1, tmp2, PATH_LENGTH);
                _strcatn(tmp1, sizetext, PATH_LENGTH);
                MySetContents(mdwd->mdwd_MountsMoreText[13], tmp1);

                if (de->de_TableSize >= DE_BUFMEMTYPE) {
                    tmp1[0] = 0x00;

                    if (de->de_BufMemType) {
                        ULONG i;

                        i = 0;
                        while (memtype[i]) {
                            if (de->de_BufMemType & memtype[i]) {
                                if (strlen(tmp1)) _strcatn(tmp1, ", ", PATH_LENGTH);
                                _strcatn(tmp1, memtypetext[i], PATH_LENGTH);
                            }

                            i++;
                        }
                    } else {
                        stccpy(tmp1, "ANY", PATH_LENGTH);
                    }

                    MySetContents(mdwd->mdwd_MountsMoreText[14], "$%08lx", de->de_BufMemType);
                    MySetContents(mdwd->mdwd_MountsMoreText[15], tmp1);
                } else {
                    MySetContents(mdwd->mdwd_MountsMoreText[14], "---");
                    MySetContents(mdwd->mdwd_MountsMoreText[15], "---");
                }
            }

            set(mdwd->mdwd_MountsMoreGroup, MUIA_ShowMe, TRUE);

            set(obj, MUIA_Window_Title, MyGetChildWindowTitle("MOUNTED DEVICE", me->me_Name, mdwd->mdwd_Title, sizeof(mdwd->mdwd_Title)));
        }
    }

    if (tmp1) tbFreeVecPooled(globalPool, tmp1);
    if (tmp2) tbFreeVecPooled(globalPool, tmp2);
    if (id) tbFreeVecPooled(globalPool, id);

    NoReqOff();
}

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

    if (obj = (Object *)DoSuperNew(cl, obj,
        MUIA_HelpNode, MountText,
        MUIA_Window_ID, MakeID('.','M','O','U'),
        WindowContents, VGroup,
            Child, HGroup,
                Child, VGroup,
                    Child, MyLabel2("Name:"),
                    Child, MyLabel2("Next:\nTask:\nStartup:"),
                End,
                Child, VGroup,
                    Child, mountmoretext[0] = MyTextObject(),
                    Child, HGroup,
                        Child, mountmoretext[1] = MyTextObject(),
                        Child, MyLabel2("Type:\nStacksize:\nPriority:"),
                        Child, mountmoretext[2] = MyTextObject(),
                    End,
                End,
                Child, HGroup, 
                    Child, VGroup, MUIA_Group_SameWidth, TRUE,
                        Child, MyLabel2("Address:"),
                        Child, MyLabel2("Lock:\nSegList:\nGlobalVec:"),
                    End,
                    Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
                        Child, mountmoretext[3] = MyTextObject(),
                        Child, mountmoretext[4] = MyTextObject(),
                    End,
                End,
            End,
            Child, HGroup,
                Child, MyLabel2("Handler:"),
                Child, mountmoretext[5] = MyTextObject(),
            End,
            Child, mountmoregroup0 = VGroup, MUIA_ShowMe, FALSE,
                Child, HGroup,
                    Child, VGroup,
                        Child, MyLabel2("Device:"),
                        Child, MyLabel2("DiskState:"),
                        Child, MyLabel2("Environment:"),
                    End,
                    Child, VGroup,
                        Child, mountmoretext[7] = MyTextObject(),
                        Child, HGroup,
                            Child, VGroup,
                                Child, mountmoretext[6] = MyTextObject(),
                                Child, mountmoretext[9] = MyTextObject(),
                            End,
                            Child, VGroup,
                                Child, MyLabel2("DiskType:"),
                                Child, MyLabel2("Flags:"),
                            End,
                            Child, VGroup,
                                Child, mountmoretext[8] = MyTextObject(),
                                Child, mountmoretext[10] = MyTextObject(),
                            End,
                        End,
                    End,
                End,
                Child, HGroup, MUIA_Group_SameSize, TRUE,
                    Child, VGroup,
                        Child, HGroup,
                            Child, MyLabel2("TableSize:\nSecOrg:\nReserved:\nPreAlloc:\nInterleave:\nSizeBlock:\nMaxTransfer:"),
                            Child, mountmoretext[11] = MyTextObject(),
                        End,
                    End,
                    Child, VGroup,
                        Child, HGroup,
                            Child, MyLabel2("BlockSize:\nSurfaces:\nSecsPerBlk:\nBlksPerTrack:\nLowCyl:\nHighCyl:\nNumBuffers:"),
                            Child, mountmoretext[12] = MyTextObject(),
                        End,
                    End,
                    Child, VGroup,
                        Child, HGroup,
                            Child, MyLabel2("Mask:\nBootPri:\nDosType:\nBaud:\nControl:\nBootBlocks:\nSize:"),
                            Child, mountmoretext[13] = MyTextObject(),
                        End,
                    End,
                End,
                Child, HGroup,
                    Child, MyLabel2("BufMemType:"),
                    Child, HGroup, MUIA_Weight, 0,
                        Child, mountmoretext[14] = MyTextObject(),
                    End,
                    Child, MyLabel2(" = "),
                    Child, mountmoretext[15] = MyTextObject(),
                End,
            End,
        End,
        TAG_MORE, msg->ops_AttrList))


    {
        struct MountsDetailWinData *mdwd = INST_DATA(cl, obj);
        APTR parent;

        CopyMem(mountmoretext, mdwd->mdwd_MountsMoreText, sizeof(mdwd->mdwd_MountsMoreText));
        mdwd->mdwd_MountsMoreGroup = mountmoregroup0;

        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 )
{
    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, (APTR)tag->ti_Data, 2, MUIM_Window_RemChildWindow, obj);
                break;

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

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

ULONG __asm __saveds MountsDetailWinDispatcher( 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));
    }

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

