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


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';
    }
}


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);
}


static DmOpenRef    dbRef=0;
static UInt16       index=0;
static UInt32       total=0;


void DBOpen()
{
    Err    error    = errNone;
    UInt16 cardNo   = 0;
    Char   fname[32]= "HelloDatabaseName-LFlb";
    UInt32 creator  = 'LFlb';
    UInt32 type     = 'DATA';
    UInt16 mode     = dmModeReadWrite;

    dbRef = DmOpenDatabaseByTypeCreator(type, creator, mode);
    if (dbRef==0) {
        error = DmCreateDatabase(cardNo, fname, creator, type, false);
        if (error!=errNone) {
            DebugError("While creating the database: ", error);
            return;
        }
        dbRef = DmOpenDatabaseByTypeCreator(type, creator, mode);
        if (dbRef==0) {
            error=DmGetLastErr();
            DebugError("While opening the database after creation: ", error);
            return;
        }
    }
}


void DBSize()
{
    Err error       = errNone;
    LocalID dbID;
    UInt16 cardNo;
    UInt32 sizeBrutto;
    UInt32 sizeNetto;

    error=DmOpenDatabaseInfo(dbRef, &dbID, NULL, NULL, &cardNo, NULL);
    if (error!=errNone) {
        DebugError("While looking up the dbID for the open database: ", error);
        total=0;
        return;
    }
    error=DmDatabaseSize(cardNo, dbID, &total, &sizeBrutto, &sizeNetto);
    if (error!=errNone) {
        DebugError("While checking the database size: ", error);
        total=0;
        return;
    }
}


void DBClose()
{
    Err error = DmCloseDatabase(dbRef);
    if (error!=errNone) {
        DebugError("While closing the database: ", error);
    }
    dbRef=0;
}



void DBAccRead(Char* data, UInt16 position)
{
    Err error = errNone;
    MemHandle   handle;
    Char       *text;

    /* handle=DmGetRecord(dbRef, position); */
    handle=DmQueryRecord(dbRef, position);
    if (handle) {
        text = MemHandleLock(handle);
        StrCopy(data, text);
        MemHandleUnlock(handle);
        /* DmReleaseRecord(dbRef, position, false); /* release it if DmGetRecord was used */
    } else {
        error = DmGetLastErr();
        data[0]='\0';
        DebugError("While reading the record: ", error);
    }
}


void DBAccWrite(Char* data, UInt16 position)
{
    Err         error = errNone;
    MemHandle   handle;
    char        *record;

    /* handle=DmGetRecord(dbRef, position); - if we would not have to resize it */
    handle=DmResizeRecord(dbRef, position, StrLen(data)+1);
    if (!handle) {
        error = DmGetLastErr();
        DebugError("While resizing the database record before writing: ", error);
        return;
    }
    record = MemHandleLock(handle);
    error=DmWrite(record, 0, data, StrLen(data)+1);
    MemHandleUnlock(handle);
    if (error!=errNone) {
        DebugError("While writing the record to the database: ", error);
        return;
    }
    error = DmReleaseRecord(dbRef, position, true);
    if (error!=errNone) {
        DebugError("While releasing the record after writing to the database: ", error);
        return;
    }
}


void DBAccInsert(Char* data, UInt16 position)
{
    Err         error = errNone;
    MemHandle   handle;
    char        *record;

    handle=DmNewRecord(dbRef, &position, StrLen(data)+1);
    if (!handle) {
        error = DmGetLastErr();
        DebugError("While appending the record to the database: ", error);
        return;
    }
    record = MemHandleLock(handle);
    error=DmWrite(record, 0, data, StrLen(data)+1);
    MemHandleUnlock(handle);
    if (error!=errNone) {
        DebugError("While writing the record to the database: ", error);
        return;
    }
    error = DmReleaseRecord(dbRef, position, true);
    if (error!=errNone) {
        DebugError("While releasing the record after writing to the database: ", error);
        return;
    }
}


void DBAccAppend(Char* data)
{
    DBAccInsert(data, dmMaxRecordIndex);
}


void DBShow()
{
    char bufindx[10];
    char bufdata[32];

    if (total>0) {
        StrIToA(bufindx, index+1);
        DisplayField(bufindx, MainForm, MainFIndex);
        DBAccRead(bufdata, index);
        DisplayField(bufdata, MainForm, MainFData);
    } else {
        DisplayField("N/A", MainForm, MainFIndex);
        DisplayField("",    MainForm, MainFData);
    }
}


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);
            DBAccWrite(text, 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);
    }
}


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);
        DBAccAppend(text);
        MemHandleUnlock((void *)handle);
        index=total;
        total++;
        DBShow();
    } else {
        FrmCustomAlert(DebugAlert, "Nothing to store!", NULL, NULL);
    }
}


void DBDelete()
{
    if (total>0) {
        /* Err error = DmDeleteRecord(dbRef, index); */
        Err error = DmRemoveRecord(dbRef, index);
        if (error==errNone) {
            total--;
            if (index>=total)
                index=total-1;
            DBShow();
        } else {
            DebugError("While deleting record: ", error);
        }
    } else {
        FrmCustomAlert(DebugAlert, "Nothing left to delete!", NULL, NULL);
    }
}


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


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


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


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