/* code07d0.c - Preferences panel
   Copyright © 2000 Mitch Blevins <mblevin@debian.org>
   GNU GPL License
   Based on LinkHistoryHack by Ben Darnel <bgdarnel@unity.ncsu.edu>
   which was...
   Based on SampleHack by Roger Chaplin <foursquaredev@att.net>
*/


#include <Pilot.h>
#include "phlegm.h"
#include "phlegmRsc.h"
#include "callback.h"

static void PrefsInit(FormPtr frm);
static void PrefsOK();
static void PrefsListDrawFunc(UInt index, RectanglePtr bounds, CharPtr* data);
static void DoListSelect(short selection);
static void ScrollList(enum directions direction);
static void AddFavorite(DWord creator, SWord width, JumpRefPref* favapps);

// This is the code that will be called whenever the user taps myhack's "+"
// button in the HackMaster list. HackMaster is not smart about the content of
// this file; it will simply jump to the first executable statement in this
// file. If you need helper functions, prototype them above, and define them
// AFTER the trap patch.
Boolean PrefsHandler(EventPtr event)
{
    FormPtr         frm;
    Boolean handled=false;
    DWord emptycreator;

    switch (event->eType) {
        case frmOpenEvent:
            frm = FrmGetActiveForm();
            PrefsInit(frm);
            FrmDrawForm(frm);
            handled=true;
            break;
      
        case ctlSelectEvent:
            switch (event->data.ctlEnter.controlID) {
                case PrefsCacheButton:
                if (!FrmAlert(CacheAlert)) {
                    PrefSetAppPreferences(MYCRID, REFPREFS, 0, &emptycreator,
                                                0, true);

                }
                break;
                case PrefsOKButton:
                PrefsOK();
                /* FALL THRU */

                case PrefsCancelButton:
                FrmGotoForm(9000);  // return to HackMaster control panel
                handled=true;
                break;
            }
            break;

        case lstSelectEvent:
            DoListSelect(event->data.lstSelect.selection);
            break;

        case keyDownEvent:
            switch (event->data.keyDown.chr) {
                case pageUpChr:
                    ScrollList(up);
                    break;
                case pageDownChr:
                    ScrollList(down);
                    break;
        }
        break;
      
        default:
            break;
    }
   
    return handled;
}

static void PrefsInit(FormPtr frm) {
    Handle happlist;
    SysDBListItemType *papplist;
    Word appcount;
    ListPtr list;
    UInt i, j;
    Word ignPrefsSize, favPrefsSize, ignNumApps;
    JumpRefPref favapps[NUM_ITEMS+1];
    DWord *ignoredapps;
    Boolean changed_the_prefs;

    /* Get the excluded app list */
    ignoredapps = 0;
    ignPrefsSize = 0;
    favPrefsSize = 0;
    if ((PrefGetAppPreferences(MYCRID, IGNOREPREFS, NULL, &ignPrefsSize, true)
	                    ==noPreferenceFound)||(ignPrefsSize==0)) {
        ignNumApps = 0;
    }
    else {
        ignNumApps = ignPrefsSize/sizeof(DWord);
        ignoredapps = MemPtrNew(ignPrefsSize);
        if (ignoredapps) {
            MemSet(ignoredapps, ignPrefsSize, 0);
            if ((PrefGetAppPreferences(MYCRID, IGNOREPREFS, ignoredapps,
                     &ignPrefsSize, true)==noPreferenceFound)||
                     (ignPrefsSize==0)) {
                ignNumApps = 0;
                MemPtrFree(ignoredapps);
                ignoredapps = 0;
            }
        }
        else {
            ignoredapps = 0;
            ignNumApps = 0;
        }
    }
    /* Get the favorites */
    favPrefsSize = (NUM_ITEMS+1)*sizeof(JumpRefPref);
    MemSet(&favapps[0], favPrefsSize, 0);
    if ((PrefGetAppPreferences(MYCRID, REFPREFS, &favapps[0], &favPrefsSize,
                                    true)==noPreferenceFound) ||
                    (favPrefsSize<(NUM_ITEMS+1)*sizeof(JumpRefPref))) {
        MemSet(&favapps[0], favPrefsSize, 0);
    }


    /* Get every stinking little application */
    if (SysCreateDataBaseList('appl', 0, &appcount, &happlist, true)) {

        /* Publish the database list handle */
        FtrSet(MYCRID, FTR_HAPPLIST, (DWord)happlist);
        FtrSet(MYCRID, FTR_APPCOUNT, (DWord)appcount);
        /* Cheat and use version to signify an excluded application */
        papplist = MemHandleLock((VoidHand)happlist);
        for (i=0; i<appcount; i++) {
            papplist[i].version = 0;
            for (j=0; j<=ignNumApps; j++) {
                if (papplist[i].creator == ignoredapps[j] ) {
                    papplist[i].version = IS_IGNORED;
                }
            }
            for (j=0; j<=NUM_ITEMS; j++) {
                if (papplist[i].creator==favapps[j].creator) {
                    if (favapps[j].flags&IS_A_FAV) {
                        papplist[i].version = IS_A_FAV;
                    }
                    favapps[j].flags |= IS_AN_EXISTING_APP;
                }
            }
        }
        MemHandleUnlock((VoidHand)happlist);

        /* Remove any deleted apps from the cache */
        changed_the_prefs = false;
        for (i=0; i<=NUM_ITEMS; i++) {
            if (favapps[i].flags&IS_AN_EXISTING_APP) {
                favapps[i].flags &= ~IS_AN_EXISTING_APP;
            }
            else {
                for (j=i; j<NUM_ITEMS; j++) {
                    MemMove(&favapps[j], &favapps[j+1], sizeof(JumpRefPref));
                }
                MemSet(&favapps[NUM_ITEMS], sizeof(JumpRefPref), 0);
                changed_the_prefs = true;
            }
        }
        if (changed_the_prefs) {
            PrefSetAppPreferences(MYCRID, REFPREFS, 0, &(favapps[0]),
                                     (NUM_ITEMS+1)*sizeof(JumpRefPref), true);
        }

        list = FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, AppList));
        LstSetListChoices(list, NULL, appcount);
        LstSetDrawFunction(list, PrefsListDrawFunc);
        LstSetSelection(list, -1);
    }
    else {
        FtrUnregister(MYCRID, FTR_HAPPLIST);
        FtrUnregister(MYCRID, FTR_APPCOUNT);
    }

    // Cleanup
    if (ignoredapps) MemPtrFree(ignoredapps);
}

static void PrefsOK() {
    SysDBListItemType *papplist;
    Handle happlist;
    DWord appcount;
    UInt i, j, k, m;
    DWord *ignoredapps;
    JumpRefPref favapps[NUM_ITEMS+1];
    Word favPrefsSize;
    DWord emptycreator;
    FontID old_font;
    SWord width;
    Char dbName[dmDBNameLength];

    /* Get the applist */
    if (FtrGet(MYCRID, FTR_HAPPLIST, (DWord*)&happlist)) return;
    if (FtrGet(MYCRID, FTR_APPCOUNT, &appcount)) return;
    papplist = MemHandleLock((VoidHand)happlist);
    /* Get the cache list */
    favPrefsSize = (NUM_ITEMS+1)*sizeof(JumpRefPref);
    MemSet(&favapps[0], favPrefsSize, 0);
    if ((PrefGetAppPreferences(MYCRID, REFPREFS, &favapps[0], &favPrefsSize,
                                    true)==noPreferenceFound) ||
                    (favPrefsSize<(NUM_ITEMS+1)*sizeof(JumpRefPref))) {
        MemSet(&favapps[0], favPrefsSize, 0);
    }

    /* Set the ignored apps */
    j = 0;
    ignoredapps=0;
    for (i=0; i<appcount; i++) {
        if (papplist[i].version&IS_IGNORED) { j++; } // Just counting...
    }
    if (!j) { // Nothing to do...
        emptycreator=0;
        PrefSetAppPreferences(MYCRID, IGNOREPREFS, 0, &emptycreator,
                            0, true);
    }
    else {
        ignoredapps = MemPtrNew(j*sizeof(DWord));
        if (ignoredapps) {
            MemSet(ignoredapps, j*sizeof(DWord), 0);
            j=0;
            for (i=0; i<appcount; i++) {
                if (papplist[i].version&IS_IGNORED) {
                    ignoredapps[j] = papplist[i].creator;
                    for (k=0; k<=NUM_ITEMS; k++) {
                        if ((favapps[k].creator) &&
                                    (favapps[k].creator==ignoredapps[j])) {
                            /* Remove from cache list */
                            for (m=k+1; m<=NUM_ITEMS; m++) {
                                MemMove(&favapps[m-1], &favapps[m],
                                                sizeof(JumpRefPref));
                            }
                            MemSet(&favapps[NUM_ITEMS], sizeof(JumpRefPref), 0);
                        }
                    }
                    j++;
                }
            }
        }
        PrefSetAppPreferences(MYCRID, IGNOREPREFS, 0, ignoredapps,
                           j*sizeof(DWord), true);
    }

    /* Set the favorites */
    for (k=0; k<=NUM_ITEMS; k++) {
        favapps[k].flags = 0;
    }
    for (i=0; i<appcount; i++) {
        if (papplist[i].version&IS_A_FAV) {
            old_font = FntSetFont(boldFont);
            if (DmDatabaseInfo(papplist[i].cardNo, papplist[i].dbID, dbName,
                            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                            NULL, NULL)) {
                width = 60;
            }
            else {
                width = FntCharsWidth(dbName, StrLen(dbName));
            }
            FntSetFont(old_font);
            AddFavorite(papplist[i].creator, width, &favapps[0]);
        }
    }
    PrefSetAppPreferences(MYCRID, REFPREFS, 0, &favapps[0],
                    (NUM_ITEMS+1)*sizeof(JumpRefPref), true);

    /* Cleanup */
    if (ignoredapps) MemPtrFree(ignoredapps);
    MemHandleUnlock((VoidHand)happlist);
}

static void AddFavorite(DWord creator, SWord width, JumpRefPref *favapps) {
    UInt i, j, k;
    Boolean gotit;

    gotit = false;
    k = 0;
    for (i=0; i<=NUM_ITEMS; i++) {
        if ((!favapps[i].creator)||(favapps[i].creator==creator)) {
            k = i;
            gotit = true;
            break;
        }
        else if (i==NUM_ITEMS) {
            for (j=NUM_ITEMS; j>1; j--) {
                if (!(favapps[j].flags&IS_A_FAV)) {
                    k = j;
                    gotit = true;
                    break;
                }
            }
        }
    }
    if (gotit) {
        favapps[k].creator = creator;
        favapps[k].width = width;
        favapps[k].flags = IS_A_FAV;
    }
}

static void PrefsListDrawFunc(UInt index, RectanglePtr bounds, CharPtr* data) {
    SysDBListItemType *papplist;
    Handle happlist;
    VoidHand symbolH;
    Int symbol;
    CALLBACK_PROLOGUE

    /* Get the applist */
    if (FtrGet(MYCRID, FTR_HAPPLIST, (DWord*)&happlist)) {
        //WinDrawChars("Error", 5, bounds->topLeft.x, bounds->topLeft.y);
        return;
    }
    papplist = MemHandleLock((VoidHand)happlist);

    /* Draw the application name */
    symbol = 0;
    if (papplist[index].version&IS_IGNORED) symbol = IgnoreBitmap;
    if (papplist[index].version&IS_A_FAV) symbol = FavoriteBitmap;
    if (symbol) {
        symbolH = DmGetResource('Tbmp', symbol);
        WinDrawBitmap((BitmapPtr)MemHandleLock(symbolH), bounds->topLeft.x,
                        bounds->topLeft.y+1);
        MemHandleUnlock(symbolH);
        DmReleaseResource(symbolH);
    }
    WinDrawChars(papplist[index].name, StrLen(papplist[index].name),
                            bounds->topLeft.x+16, bounds->topLeft.y);

    /* Cleanup */
    MemHandleUnlock((VoidHand)happlist);
    CALLBACK_EPILOGUE
}

static void DoListSelect(short selection) {
    FormPtr frm;
    ListPtr list;
    SysDBListItemType *papplist;
    Handle happlist;

    if (selection < 0) return;
    if (FtrGet(MYCRID, FTR_HAPPLIST, (DWord*)&happlist)) return;
    papplist = MemHandleLock((VoidHand)happlist);
    if (!papplist[selection].version)
            papplist[selection].version = IS_IGNORED;
    else if (papplist[selection].version&IS_IGNORED)
            papplist[selection].version = IS_A_FAV;
    else papplist[selection].version = 0;
    MemHandleUnlock((VoidHand)happlist);
    frm = FrmGetActiveForm();
    list = FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, AppList));
    LstEraseList(list);
    LstSetSelection(list, -1);
    LstDrawList(list);
}

static void ScrollList(enum directions direction) {
    FormPtr frm;
    ListPtr list;

    frm = FrmGetActiveForm();
    list = FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, AppList));

    LstScrollList(list, direction, 7);
}
