/* code03e8.c - SoftKeyStroke trap handler
   Copyright © 2000 Mitch Blevins <mblevin@debian.org>
   Distributed under the GNU GPL.
   Base on LinkHistoryHack by Ben Darnell <bgdarnel@unity.ncsu.edu>
   which was based on...
   Based on SampleHack by Roger Chaplin <foursquaredev@att.net>
*/

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


static void DoAction(Boolean useList);

// This is the code that will be called whenever ANY app calls EvtGetEvent,
// and myhack is enabled in HackMaster. 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.
Err EvtProcessSoftKeyStroke(PointType* start, PointType* end)
{
   DWord               temp;
   Err              (*oldTrap)(PointType*, PointType*);

   // get the address of the old EvtProcessSoftKeyStroke() from HackMaster
   FtrGet(MYCRID, 0x3e8, &temp);
   // set the function pointer to the old trap
   oldTrap = (Err (*)(PointType*, PointType*)) temp;

   if (start->x < 27) {
       if ((start->y > 163) && (start->y < 192)) {
           /* Application button */
           if ((end->x > 26) && (end->x < 109) &&
               (end->y > 163) && (end->y < 209)) {
               /* Upper-left graffiti area */
               DoAction(false);
               return 0;
           }
       }
       else if ((start->y > 191) && (start->y < 221)) {
           /* Menu button */
           if (end->x < 27) {
               if ((end->y > 163) && (end->y < 192)) {
                   /* Application button */
                   // Only if list is not already up...
                   if (FtrGet(MYCRID, FTR_DUPLICATE, &temp)) DoAction(true);
                   return 0;
               }
           }
       }
   }

   return oldTrap(start, end);
}

static void DrawList(UInt itemnum, RectanglePtr bounds, JumpRefPref *refs) {
    UInt i;
    UInt cardNo;
    LocalID dbID;
    DmOpenRef dbR;
    FontID old_font;
    unsigned char z[34];
    Char name[dmDBNameLength];
    Int resindex;
    VoidHand hres;
    BitmapPtr pres;
    DmSearchStateType searchstate;
    Err err;

    for (i=0; i<=NUM_ITEMS; i++) {
        if (!(refs+i)->creator) break;
    }
    err = 0;
    err=DmGetNextDatabaseByTypeCreator(true, &searchstate, sysFileTApplication,
                    (refs+(i-1-itemnum))->creator, true, &cardNo, &dbID);

    // Set the app name
    MemSet(name, dmDBNameLength, 0);
    name[0]='E'; name[1]='r'; name[2]='r';
    if (!err) {
        err = DmDatabaseInfo(cardNo, dbID, name, NULL, NULL, NULL, NULL, NULL,
                    NULL, NULL, NULL, NULL, NULL);
    }
    // Set bitmap to unassigned by default
    MemSet(z, 34, 0);
    /* Do we really need the default small icon?
    z[1]=0x0f; z[3]=0x09; z[5]=0x02; z[16]=0x01; z[18]=0x0e; z[19]=0xe0;
    z[20]=0x0c; z[21]=0x60; z[22]=0x08; z[23]=0x20; z[24]=0x10;
    z[25]=0x10; z[26]=0x08; z[27]=0x20; z[28]=0x0c; z[29]=0x60;
    z[30]=0x0e; z[31]=0xe0; z[32]=0x01;
    */

    // Open database and read the info
    if (!err) {
        dbR = DmOpenDatabase(cardNo, dbID, dmModeReadOnly);
        if (dbR) {
            resindex = DmFindResource(dbR, 'tAIB', 1001, NULL);
            if (resindex!=-1) {
                hres=DmGetResourceIndex(dbR, resindex);
                pres=(BitmapPtr)MemHandleLock(hres);
                MemMove(z, pres, 34);
                MemHandleUnlock(hres);
                DmReleaseResource(hres);
            }
            DmCloseDatabase(dbR);
        }
    }

    WinEraseRectangle(bounds, 0);
    WinDrawBitmap((BitmapPtr)z, bounds->topLeft.x, bounds->topLeft.y+1);
    if (((refs+(i-1-itemnum))->flags)&IS_A_FAV) old_font=FntSetFont(boldFont);
    else old_font=FntSetFont(stdFont);
    WinDrawChars(name, StrLen(name), bounds->topLeft.x+17, bounds->topLeft.y);
    FntSetFont(old_font);
}

static void DoAction(Boolean useList) {
    ListType list;
    UInt skipfirst;
    Word prefssize;
    short sel;
    UInt i, cardNo, jumpNum;
    LocalID dbID;
    DWord currCreator;
    JumpRefPref jumpRefs[NUM_ITEMS+1];
    DmSearchStateType searchstate;
    Err err;

    CALLBACK_PROLOGUE;

    // Click to confirm to the user
    SndPlaySystemSound(sndClick);

    // Get the list of cached apps
    prefssize = (NUM_ITEMS+1)*sizeof(JumpRefPref);
    MemSet(&(jumpRefs[0]), prefssize, 0);
    if ((PrefGetAppPreferences(MYCRID, REFPREFS, &(jumpRefs[0]), &prefssize,                        true)==noPreferenceFound)||
                    (prefssize<(NUM_ITEMS+1)*sizeof(JumpRefPref))) {
        MemSet(&(jumpRefs[0]), (NUM_ITEMS+1)*sizeof(JumpRefPref), 0);
    }

    // Are we already on the most recent?
    skipfirst = 0;
    if (!SysCurAppDatabase(&cardNo, &dbID)) {
        if (!DmDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL,
                  NULL, NULL, NULL, NULL, NULL, &currCreator)) {
            if (jumpRefs[0].creator==currCreator)  skipfirst = 1;
            //if ((currCreator=='HsPr')&&(jumpRefs[0].creator=='calc'))
             //       skipfirst = 1;
        }
    }

    // Decide which action to take...
    if (useList) {
        // Find the list height and width
        MemSet(&list, sizeof(ListType), 0);
        list.numItems = 0;
        for (i=skipfirst; i<=NUM_ITEMS; i++) {
            if (!jumpRefs[i].creator) break;
            if (jumpRefs[i].width > list.bounds.extent.x)
                    list.bounds.extent.x = jumpRefs[i].width;
            list.numItems++;
        }
        if (!list.numItems) {
            SndPlaySystemSound(sndWarning);
            goto cleanup;
        }
        list.bounds.extent.x += 22; //padding
        list.bounds.extent.y = list.numItems*FntCharHeight();
        list.bounds.topLeft.x = 0;
        list.bounds.topLeft.y = 159-list.bounds.extent.y;
        list.attr.usable = true;
        list.font = stdFont;
        list.topItem = 0;
        list.drawItemsCallback=(ListDrawDataFuncPtr)DrawList;
        list.itemsText = (CharPtr*)(&jumpRefs[0]); // This is cheating
        LstSetSelection(&list, -1);

        // Popup the list
        FtrSet(MYCRID, FTR_DUPLICATE, i); // just a warning...
        sel = LstPopupList(&list);
        FtrUnregister(MYCRID, FTR_DUPLICATE); // Okay, safe now.
        if (sel >= 0) jumpNum = list.numItems-1+skipfirst-sel;
        else goto cleanup;

    }
    else jumpNum = skipfirst;

    // Jump to the app
    if(!jumpRefs[jumpNum].creator) {
        // Must not be a real app
        SndPlaySystemSound(sndWarning);
        goto cleanup;
    }
    err = 0;
    err=DmGetNextDatabaseByTypeCreator(true, &searchstate, sysFileTApplication,
                    jumpRefs[jumpNum].creator, true, &cardNo, &dbID);
    if (err) {
        /* Remove the offending entry */
        for (i=jumpNum; i<NUM_ITEMS; i++) {
            MemMove(&jumpRefs[i], &jumpRefs[i+1], sizeof(JumpRefPref));
        }
        MemSet(&jumpRefs[NUM_ITEMS], sizeof(JumpRefPref), 0);
        PrefSetAppPreferences(MYCRID, REFPREFS, 0, &(jumpRefs[0]),
                                     (NUM_ITEMS+1)*sizeof(JumpRefPref), true);
        SndPlaySystemSound(sndWarning);
        goto cleanup;
    }
    else SysUIAppSwitch(cardNo, dbID, sysAppLaunchCmdNormalLaunch, NULL);

cleanup:
    CALLBACK_EPILOGUE;
}

