#include <PalmOS.h>
#include "helloRsc.h"


static void DebugError(const Char *msg, Err error)
{
    Char buffer[11];
    StrIToA(buffer, error);
    FrmCustomAlert(DebugAlert, "ERROR:\n", msg, buffer);
}


static void GetField(Char *buffer, UInt16 formid, UInt16 fieldid)
{
    FormType    *form;
    FieldType   *field;
    MemHandle   textH;
    Char        *textS;

    form = FrmGetFormPtr(formid);
    field=FrmGetObjectPtr(form, FrmGetObjectIndex(form, fieldid) );
    textH = FldGetTextHandle(field);
    if (textH) {
        textS = MemHandleLock(textH);
        StrCopy(buffer, textS);
        MemHandleUnlock(textH);
    } else {
        buffer[0] = '\0';
    }
}


static void DisplayField(const Char *buffer, UInt16 formid, UInt16 fieldid)
{
    FormType    *form;
    FieldType   *field;
    MemHandle   textH;
    Char        *text;
    Int16       buflen = StrLen(buffer)+1;

    form  = FrmGetFormPtr(formid);
    field = FrmGetObjectPtr(form, FrmGetObjectIndex(form, fieldid) );
    textH = FldGetTextHandle(field);

    if (textH) {
        Err     error = errNone;
        Int16   texlen;

        FldSetTextHandle(field, NULL);
        text   = MemHandleLock(textH);
        texlen = StrLen(text)+1;
        if (texlen<buflen) {
            MemHandleUnlock(textH);
            error = MemHandleResize(textH, buflen + sizeOf7BitChar(chrNull) );
            ErrFatalDisplayIf(error, "Out of memory");
            text   = MemHandleLock(textH);
        }
    } else {
        textH = MemHandleNew(buflen);
        ErrFatalDisplayIf(! textH, "Out of memory");
        text = MemHandleLock(textH);
    }

    StrCopy(text, buffer);
    MemHandleUnlock(textH);
    FldSetTextHandle(field, textH);
    FldDrawField(field);
}


/* fale Database of 10 elements */
static UInt16       index=0;
static UInt32       total=0;


static void DBShow()
{
    char bufindx[10];

    if (total>0) {
        StrIToA(bufindx, index+1);
        DisplayField(bufindx, MainForm, MainFIndex);
        /* retrieve data[index] */
        DisplayField("database storage is not implemented yet", MainForm, MainFData);
    } else {
        DisplayField("N/A", MainForm, MainFIndex);
        DisplayField("",    MainForm, MainFData);
    }
}


static void DBUpdate()
{
    MemHandle   handle;
    Char       *text;
    FormType   *form;
    FieldType  *field;

    if (total>0) {
        form   = FrmGetFormPtr(MainForm);
        field  = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFData) );

        handle = FldGetTextHandle(field);
        if (handle) {
            text = MemHandleLock((void *)handle);
            /* store data[index] */
            MemHandleUnlock((void *)handle);
            DBShow();
        } else {
            FrmCustomAlert(DebugAlert, "Nothing to store!", NULL, NULL);
        }
    } else {
        FrmCustomAlert(DebugAlert, "Cannot update empty database,\nuse Insert instead!", NULL, NULL);
    }
}


static void DBInsert()
{
    MemHandle   handle;
    Char       *text;
    FormType   *form;
    FieldType  *field;



    form   = FrmGetFormPtr(MainForm);
    field  = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFData) );
    handle = FldGetTextHandle(field);
    if (handle) {
        text = MemHandleLock((void *)handle);
        /* store data[at the end or insert at index] */
        MemHandleUnlock((void *)handle);
        index=total;
        total++;
        DBShow();
    } else {
        FrmCustomAlert(DebugAlert, "Nothing to store!", NULL, NULL);
    }
}


static void DBDelete()
{
    if (total>0) {
        /* delete data[index] */
        total--;
        if (index>=total)
            index=total-1;
        DBShow();
    } else {
        FrmCustomAlert(DebugAlert, "Nothing left to delete!", NULL, NULL);
    }
}


static void DBFirst()
{
    index=0;
    DBShow();
}


static void DBLast()
{
    if (total>0)
        index=total-1;
    else
        index=0;
    DBShow();
}


static void DBPrev()
{
    if (index>0) {
        index--;
        DBShow();
    } else {
        FrmCustomAlert(DebugAlert, "Already at the beginning!", NULL, NULL);
    }
}


static void DBNext()
{
    if (total>0 && index<total-1) {
        index++;
        DBShow();
    } else {
        FrmCustomAlert(DebugAlert, "Already at the end!", NULL, NULL);
    }
}









static Err StartApplication(void)
{
    FrmGotoForm(MainForm);
    return errNone;
}


static void StopApplication(void)
{
}


static Boolean MainMenuHandleEvent(UInt16 menuID)
{
    Boolean    handled = false;
    FormType   *form;
    FieldType  *field;


    form =  FrmGetActiveForm();
    field = FrmGetObjectPtr(form, FrmGetFocus(form));

    switch (menuID) {
        case MainEditUndo:
            FldUndo(field);
            handled = true;
            break;
        case MainEditCut:
            FldCut(field);
            handled = true;
            break;
        case MainEditCopy:
            FldCopy(field);
            handled = true;
            break;
        case MainEditPaste:
            FldPaste(field);
            handled = true;
            break;
        case MainEditSelectAll:
            FldSetSelection(field, 0, FldGetTextLength(field));
            handled = true;
            break;

        case MainEditKeyboard:
            SysKeyboardDialog(kbdDefault);
            handled = true;
            break;

        case MainEditGraffitiHelp:
            SysGraffitiReferenceDialog(referenceDefault);
            handled = true;
            break;

        case MainOptionsAbout:
            FrmAlert(AboutAlert);
            handled = true;
            break;

        default:
            break;
    }

    return handled;
}


static Boolean MainFormHandleEvent(EventPtr event)
{
    Boolean  handled = false;

    switch (event->eType) {
        case frmOpenEvent:
        {
            FormType  *form = FrmGetFormPtr(MainForm);
            FrmDrawForm(form);

            DBShow(); /* update display for the first time */

            FrmSetFocus(form, FrmGetObjectIndex(form, MainFData));
            handled = true;
        }
            break;

        case ctlSelectEvent:
            switch (event->data.ctlSelect.controlID) {

                case MainBFirst:
                    DBFirst();
                    handled = true;
                    break;

                case MainBPrev:
                    DBPrev();
                    handled = true;
                    break;

                case MainBNext:
                    DBNext();
                    handled = true;
                    break;

                case MainBLast:
                    DBLast();
                    handled = true;
                    break;

                case MainBRefresh:
                    DBShow();
                    handled = true;
                    break;

                case MainBUpdate:
                    DBUpdate();
                    handled = true;
                    break;

                case MainBInsert:
                    DBInsert();
                    handled = true;
                    break;

                case MainBDelete:
                    DBDelete();
                    handled = true;
                    break;

                default:
                    break;
            }
            break;

        case menuEvent:
            handled = MainMenuHandleEvent(event->data.menu.itemID);
            break;

        default:
            break;
    }

    return handled;
}


static Boolean ApplicationHandleEvent(EventPtr event)
{
    FormType  *form;
    UInt16    formID;
    Boolean   handled = false;


    if (event->eType == frmLoadEvent) {
        formID = event->data.frmLoad.formID;
        form = FrmInitForm(formID);
        FrmSetActiveForm(form);

        switch (formID) {
            case MainForm:
                FrmSetEventHandler(form, MainFormHandleEvent);
                break;

            default:
                break;
        }
        handled = true;
    }

    return handled;
}


static void EventLoop(void)
{
    EventType  event;
    UInt16     error;

    do {
        EvtGetEvent(&event, evtWaitForever);
        if (! SysHandleEvent(&event))
            if (! MenuHandleEvent(0, &event, &error))
                if (! ApplicationHandleEvent(&event))
                    FrmDispatchEvent(&event);
    } while (event.eType != appStopEvent);
}


UInt32 PilotMain(UInt16 launchCode, MemPtr cmdPBP, UInt16 launchFlags)
{
    Err  err=errNone;

    switch (launchCode) {
        case sysAppLaunchCmdNormalLaunch:
            if ((err = StartApplication()) == 0) {
                EventLoop();
                StopApplication();
            }
            break;

        default:
            break;
    }

    return err;
}