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