/*
 * Application startup and shutdown.
 */

#include <PalmOS.h>

#include "flipMain.h"
#include "flipFlip.h"
#include "flipList.h"
#include "flipEdit.h"
#include "flipAbout.h"
#include "palmUtil.h"
#include "resdefs.h"


/*
 * Global variables
 */

/* The currently open word database. */
DmOpenRef wordDB;

/* Metadata about the currently open word database. */
FlipDBInfo wordDBInfo;

/*
 * Application stuff
 */

static struct FormInfo *GetFormInfo (UInt16 formId)
{
	switch (formId) {
	
	case FlipForm: 
		return &FlipFormInfo;
	case WordListForm: 
		return &ListFormInfo;
	case WordEditForm: 
		return &EditFormInfo;
	case AboutForm: 
		return &AboutFormInfo;
	
	default: return NULL;
	}
}

static void LoadPrefs (FlipAppPrefs *prefs)
{
	Int16 found;
	UInt16 size;

	found = PrefGetAppPreferences(flipCreatorId, FLIP_APP_PREFS_ID, 
				      prefs, &size, true);
	if (found == noPreferenceFound || size < sizeof(FlipAppPrefs)) {
		prefs->dbIndex = 0;
		prefs->flipWord = 0;
		prefs->flipFlipped = false;
	}
}

static void SavePrefs (FlipAppPrefs *prefs)
{
	PrefSetAppPreferences(flipCreatorId, FLIP_APP_PREFS_ID, FLIP_PREFS_VERSION, 
			      prefs, sizeof(FlipAppPrefs), true);
}

static Err openDB(FlipAppPrefs *prefs)
{
	Err err;

	err = SwitchDB(&wordDB, &wordDBInfo, prefs->dbIndex);
	if (err == dmErrCantFind) {
		/* db not found */
		if (prefs->dbIndex != 0) {
			/* try db number 0 */
			prefs->dbIndex = 0;
			return openDB(prefs);
		} else {
			/* create a new db, will be number 0 */
			err = CreateEmptyDB();
			if (err)
				return err;
			return openDB(prefs);
		}
	} else if (err) {
		return err;
	}

	FlipWord(prefs->flipWord, prefs->flipFlipped);

	return errNone;
}

static Err StartApplication(void)
{
	FlipAppPrefs prefs;

	LoadPrefs(&prefs);

	return openDB(&prefs);
}

static void StopApplication(void)
{
	Err err;
	FlipAppPrefs prefs;
	FlipDBInfo dbInfo;

	err = FlipGetOpenDatabase(wordDB, &dbInfo);
	err = FlipGetDatabaseIndex(&prefs.dbIndex, &dbInfo);

	FlipGetFlipState(&prefs.flipWord, &prefs.flipFlipped);

	SavePrefs(&prefs);

	FrmCloseAllForms();

	DmCloseDatabase(wordDB);
}

static Boolean HandleCommonMenuItems(UInt16 itemID)
{
	FieldPtr fld;
	
	switch (itemID) {
	case EditUndo:
	case EditCut:
	case EditCopy:
	case EditPaste:
	case EditSelectAll:
		fld = GetFocusField();
		if (!fld) 
			return false;
		if (itemID == EditUndo)
			FldUndo(fld);
		else if (itemID == EditCut)
			FldCut(fld);
		else if (itemID == EditCopy)
			FldCopy(fld);
		else if (itemID == EditPaste)
			FldPaste(fld);
		else if (itemID == EditSelectAll)
			FldSetSelection(fld, 0, FldGetTextLength(fld));
		return true;
		
	case EditKeyboard:
		SysKeyboardDialog(kbdDefault);
		return true;
		
	case EditGrafitti: 
		SysGraffitiReferenceDialog(referenceDefault);
		return true;
		
	case MenuAbout:
		ShowAboutForm();
		return true;
		
	default:
		return false;
	}
}

static Boolean FormHandleEvent(EventPtr event)
{
	FormPtr frmP;
	struct FormInfo *fi;

	frmP = FrmGetActiveForm();
	fi = GetFormInfo(FrmGetActiveFormID());

	switch (event->eType) {
	case frmOpenEvent:
		if (fi && fi->InitForm)
			fi->InitForm();
		if (fi && fi->UpdateForm)
			fi->UpdateForm();
		FrmDrawForm(frmP);
		return true;

	case frmUpdateEvent:
		if (fi && fi->UpdateForm)
			fi->UpdateForm();
		FrmDrawForm(frmP);
		return true;

	case frmCloseEvent:
		if (fi && fi->DeinitForm)
			fi->DeinitForm();
		return false;

	case menuEvent:
		if (HandleCommonMenuItems(event->data.menu.itemID))
			return true;
		/* fall through */
	default:
		if (fi && fi->EventHandler)
			return fi->EventHandler(event);
		return false;
	}
}

static Boolean ApplicationHandleEvent(EventPtr event)
{
	UInt16 formId;
	FormPtr frmP;

	if (event->eType == frmLoadEvent) {
		formId = event->data.frmLoad.formID;
		frmP = FrmInitForm(formId);
		FrmSetActiveForm(frmP);
		FrmSetEventHandler(frmP, FormHandleEvent);

		return true;
	}

	return FormHandleEvent(event);
}

static void EventLoop(void)
{
	Err err;
	EventType event;
	struct FormInfo *fi;

	do {
		EvtGetEvent(&event, evtWaitForever);

		/* Intercept hard buttons etc. */
		fi = GetFormInfo(FrmGetActiveFormID());
		if (fi && fi->EventStealer && fi->EventStealer(&event))
			continue;

		if (SysHandleEvent(&event))
			continue;

		if (MenuHandleEvent(0, &event, &err))
			continue;

		if (ApplicationHandleEvent(&event))
			continue;

		FrmDispatchEvent(&event);

	} while (event.eType != appStopEvent);
}


UInt32 PilotMain(UInt16 cmd, void *cmdPBP, UInt16 launchFlags)
{
	UInt16 err;

	if (cmd == sysAppLaunchCmdNormalLaunch) {
		err = StartApplication();
		if (err)
			return err;

		EventLoop();

		StopApplication();
	}
	return 0;
}