/*
*
* Pretty Calculator for Palm/Pilot
*
*   written by Y.Kazama
*
*/

#include <Common.h>
#include <System/SysAll.h>
#include <UI/UIAll.h>
#include "MathLib.h"
#include "resource.h"
#include "PCalcMain.h"
#include "MainForm.h"
#include "PrefForm.h"
#include "SelProgForm.h"
#include "SelConstForm.h"
#include "EditProgForm.h"
#include "EditConstForm.h"
#include "DataBase.h"
#include "ConvDblToStr.h"


/* prototypes. */
static Err  StartApplication(void);
static void EventLoop(void);
static void StopApplication(void);


/* define functions. */

DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
{
 Err error;

 if (cmd == sysAppLaunchCmdNormalLaunch) {

   error = StartApplication();
   if (error) return error;

   EventLoop();

   StopApplication();
 }
 return 0;
}


static Err StartApplication(void)
{
 Err error;
 SWord prefExist;
 Word prefSize;
 UInt i;

 /* load MathLib library. */
 error = SysLibFind(MathLibName, &MathLibRef);
 if (error) error = SysLibLoad(LibType, MathLibCreator, &MathLibRef);
 if (error) {
   FrmCustomAlert(alertInformID, "Cannot find 'MathLib' library.", "", "");
   return error;
 }

 error = MathLibOpen(MathLibRef, MathLibVersion);
 if (error) {
   FrmCustomAlert(alertInformID, "Cannot open 'MathLib' library.", "", "");
   return error;
 }

 /* get preferences data. */
 prefSize = sizeof(g);
 prefExist = PrefGetAppPreferences(kPcalcAppID, 0, &g, &prefSize, false);
 // must check prefSize var.

 if (prefExist == noPreferenceFound) {
   /* initialize preferences. */
   Byte nan[8] = {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

   g.Notation     = FIX_MODE;
   g.AngleUnit    = DEG_MODE;
   g.DisplayDigit = 8;
   g.InsertDigit  = 10;
   g.NotatBound   = 7;
   g.LastAnsValid  = false;
   g.FirstInput    = false;
   g.HistPosition  = 0;
   g.DispAddFormat = ADD_SEP_INTP | ADD_SEP_FRACP;
   for (i = 0; i < kNumHistory; i++) StrCopy(g.HistoryStr[i], "");
   for (i = 0; i <= kNumMemory; i++) g.Memory[i] = *((double*)nan);
 }

 /* initialize variables. */
 gProgramMode     = false;
 gLastExecProgRec = -1;
 g.LastAnsValid   = false;

 /* open constant database. */
 gConstantDB = DmOpenDatabaseByTypeCreator(kConstantDBType,
                                           kPcalcAppID, dmModeReadWrite);
 if (!gConstantDB) {
   error = DmCreateDatabase(0, kConstantDBName, kPcalcAppID,
                            kConstantDBType, false);
   if (error) {
     FrmCustomAlert(alertInformID,
                    "Cannot create 'Constant' database.", "", "");
     return error;
   }

   gConstantDB = DmOpenDatabaseByTypeCreator(kConstantDBType, kPcalcAppID,
                                             dmModeReadWrite);
   if (!gConstantDB) {
     FrmCustomAlert(alertInformID,
                    "Cannot open 'Constant' database.", "", "");
     return DmGetLastErr();
   }
 }

 /* open program database. */
 gProgramDB = DmOpenDatabaseByTypeCreator(kProgramDBType,
                                          kPcalcAppID, dmModeReadWrite);
 if (!gProgramDB) {
   error = DmCreateDatabase(0, kProgramDBName, kPcalcAppID,
                            kProgramDBType, false);
   if (error) {
     FrmCustomAlert(alertInformID,
                    "Cannot create 'Program' database.", "", "");
     return error;
   }

   gProgramDB = DmOpenDatabaseByTypeCreator(kProgramDBType,
                                            kPcalcAppID, dmModeReadWrite);
   if (!gProgramDB) {
     FrmCustomAlert(alertInformID,
                    "Cannot open 'Program' database.", "", "");
     return DmGetLastErr();
   }
 }

 /* go to initial form. */
 FrmGotoForm(formMainID);

 return 0;
}


static Boolean ApplicationHandleEvent(EventPtr event)
{
 FormPtr form;
 Int formID;
 Boolean handled = false;

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

   switch (formID) {
   case formMainID:
     FrmSetEventHandler(form, MainFormHandleEvent);
     break;
   case formPrefID:
     FrmSetEventHandler(form, PrefFormHandleEvent);
     break;
   case formEditProgID:
     FrmSetEventHandler(form, EditProgFormHandleEvent);
     break;
   case formEditConstID:
     FrmSetEventHandler(form, EditConstFormHandleEvent);
     break;
   case formSelectConstID:
     FrmSetEventHandler(form, SelConstFormHandleEvent);
     break;
   case formSelectProgID:
     FrmSetEventHandler(form, SelProgFormHandleEvent);
     break;
   }
   handled = true;
 }
 return handled;
}


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

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


static void StopApplication(void)
{
 Err   error;
 UInt  usecount;
 SWord prefVer = 1;

 /* close MathLib. */
 error = MathLibClose(MathLibRef, &usecount);
 if (error) {
   FrmCustomAlert(alertInformID, "Cannot close 'MathLib' library.", "", "");
   ErrFatalDisplayIf(error, "Cannot close 'MathLib' library."); //  soft-reset.
 }
 if (usecount == 0) SysLibRemove(MathLibRef);

 /* save preference. */
 PrefSetAppPreferences(kPcalcAppID, 0, prefVer, &g, sizeof(g), false);

 /* close database. */
 DmCloseDatabase(gConstantDB);
 DmCloseDatabase(gProgramDB);
}