/******************************************************************************
FILE:  ExpenseTracker.c

SERVICES:  AEE Expense Tracking BREW example application

GENERAL DESCRIPTION:
  ExpenseTracker is a simple daily expense tracking application
  that allows the user to record new expenses as they are accrued
  to a database.  Expenses can be view and updated based on search
  criteria and text reports generated from the contents of the
  database.
 
PUBLIC CLASSES AND STATIC FUNCTIONS:
	Classes:
    IMenuCtl
    ITextCtl
    IDateCtl
    IStatic
    IDialog
    IDatabase
    IDBMgr
    IDBRecord
    IFileMgr
    IFile

INITIALIZATION & SEQUENCING REQUIREMENTS:

	See Exported Routines

       Copyright © 2002 QUALCOMM Incorporated.
               All Rights Reserved.
            QUALCOMM Proprietary/GTDR
******************************************************************************/
#include "ExpenseTracker.h"
#include "AEEModGen.h"
#include "AEEStdLib.h"
#include "ExpenseTracker.bid"
#include "ExpenseTracker.brh"
#include "ET_DBFunctions.h"
#include "nmdef.h"

/*****************************************************************************
  Function Prototypes
*****************************************************************************/

static boolean ET_InitAppData(CExpenseTrackerApp * pApp);
static boolean ET_CreateMainControls(CExpenseTrackerApp* pApp);
static void    ET_FreeAppData(CExpenseTrackerApp* pApp);
static void    ET_ReleaseMainControls(CExpenseTrackerApp* pApp);
static void    ReleaseObj(void ** ppObj);

static boolean ET_HandleEvent(CExpenseTrackerApp * pApp, AEEEvent eCode, uint16 wParam, uint32 dwParam );

// Display Functions

static void ET_DisplaySplashScreen(CExpenseTrackerApp * pApp);
static void ET_DisplayMainMenu( CExpenseTrackerApp* pApp );
static void ET_DisplayAddScreen(CExpenseTrackerApp* pApp);
static void ET_DisplayViewScreen( CExpenseTrackerApp* pApp );
static void ET_DisplayExpenseScreen( CExpenseTrackerApp* pApp );
static void ET_DisplayOptionsScreen( CExpenseTrackerApp* pApp );
static void ET_DisplayReportScreen( CExpenseTrackerApp* pApp );
static void ET_DisplayHelpScreen(CExpenseTrackerApp * pApp);
static void ET_DisplayAboutScreen(CExpenseTrackerApp * pApp);

// Database Related Functions

static void ET_ReadViewSelections( CExpenseTrackerApp* pApp );
static void ET_SetAddScreenSelections( CExpenseTrackerApp* pApp, uint16 nRecordID);
static void ET_SaveReportStartCB(void* pData);
static void ET_SaveReportEndCB(void* pData);

// General Purpose Routines

static void ET_DisplayBanner( CExpenseTrackerApp* pApp, uint16 nResStringID );
static void ET_DisplayControl( CExpenseTrackerApp* pApp, uint16 nTitleID, IControl* pCtl, int16 yPos );
static void ET_Reset(CExpenseTrackerApp * pApp, boolean bShowTitleBar );
static void ET_Prompt(CExpenseTrackerApp * pApp, const AECHAR* szTitle, uint16 wIDTitle, const AECHAR* szText, uint16 wIDText, const char* pFileName, uint16* wButtons, uint16 wDefID, uint32 dwProps);

/*===========================================================================

FUNCTION: AEEClsCreateInstance

DESCRIPTION:
	This function is invoked while the app is being loaded. All Modules must provide this 
	function. Ensure to retain the same name and parameters for this function.
	In here, the module must verify the ClassID and then invoke the AEEApplet_New() function
	that has been provided in AEEAppGen.c. 

  After invoking AEEApplet_New(), this function can do app specific initialization. In this
  example, a generic structure is provided so that app developers need not change app specific
  initialization section every time except for a call to ET_InitAppData(). 
  This is done as follows: ET_InitAppData() is called to initialize AppletData 
  instance. It is app developers responsibility to fill-in app data initialization 
  code of ET_InitAppData(). App developer is also responsible to release memory 
  allocated for data contained in AppletData -- this can be done in 
  ET_FreeAppData().

PARAMETERS:
	clsID [in] - Specifies the ClassID of the applet which is being loaded

	pIShell [in] - Contains pointer to the IShell interface. 

	pIModule [pin] - Contains pointer to the IModule interface to the current module to which
    this app belongs

	ppObj [out] - On return, *ppObj must point to a valid IApplet structure. Allocation
	  of memory for this structure and initializing the base data members is done by AEEApplet_New().

DEPENDENCIES:
  None

RETURN VALUE:
  AEE_SUCCESS - If the app needs to be loaded and if AEEApplet_New() invocation was
     successful
  EFAILED - If the app does not need to be loaded or if errors occurred in 
     AEEApplet_New(). If this function returns FALSE, the app will not be loaded.

SIDE EFFECTS:
  None
===========================================================================*/
int AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po,void ** ppObj)
{
   CExpenseTrackerApp *   pApp = NULL; 

   if(!AEEApplet_New(sizeof(CExpenseTrackerApp), ClsId, pIShell,po,(IApplet**)ppObj,(AEEHANDLER)ET_HandleEvent,(PFNFREEAPPDATA)ET_FreeAppData))
      return ENOMEMORY;
	
   pApp = (CExpenseTrackerApp *)*ppObj;

   if (!ET_InitAppData(pApp)) {
      IAPPLET_Release((IApplet*)pApp);
      *ppObj = NULL;
		return EFAILED;
   }

   return(AEE_SUCCESS);
}

/*===========================================================================

FUNCTION: ET_InitAppData

DESCRIPTION:
  This function initializes app specific data and allocates required memory 
  memory for app data.  It also functions to create all necessary GUI objects.

PARAMETERS:
	pApp [in] - Applet Structure

DEPENDENCIES:
  Assumes pApp is not NULL

RETURN VALUE:
  TRUE: If the app has app data is allocated and initialized successfully
  FALSE: App data could not be allocated or initialzied

SIDE EFFECTS:
  None
===========================================================================*/
static boolean ET_InitAppData(CExpenseTrackerApp * pApp)
{
   AEEDeviceInfo* pDeviceInfo;
   AEEImageInfo* pImageInfo;
   IDBMgr * pDBMgr = NULL;
   IShell * pIShell = pApp->a.m_pIShell; // Cache Shell Pointer

   // Create all of the common GUI controls that will be used for all
   // interfaces except the Add/Edit and View dialogs (these will be 
   // created and deleted as needed).
   if(!ET_CreateMainControls(pApp))
      return FALSE;

   // Load the titlebar image
   if((pApp->m_pTitleBarImg = ISHELL_LoadResImage(pIShell, EXPENSETRACKER_RES_FILE, IDB_TITLEBAR)) == NULL)
      return FALSE;

   // Make the image transparent

   IIMAGE_SetParm( pApp->m_pTitleBarImg, IPARM_ROP, AEE_RO_TRANSPARENT, 0 );

   // Create the IDBMgr object
   if(ISHELL_CreateInstance(pIShell, AEECLSID_DBMGR, (void**)(&pDBMgr)) != SUCCESS)
      return FALSE;

   // Open the ExpenseTracker database.  If it does not exist then create it.
   // Once the database is opened, the IDBMgr is not longer needed so it is released.
   if((pApp->m_pDatabase = IDBMGR_OpenDatabase(pDBMgr, EXPENSETRACKER_DB_FILE, TRUE)) == NULL) {
      IDBMGR_Release(pDBMgr);
      return FALSE;
   }
   else
   {
      IDBMGR_Release(pDBMgr);
   }

   // Get device, image and font size information.  These measurements are used 
   // to determine the display rectangle of coordinates where screen GUI objects
   // can be displayed.

   pApp->m_nFontHeight = IDISPLAY_GetFontMetrics( pApp->a.m_pIDisplay, AEE_FONT_NORMAL, NULL, NULL ) + 1;

   pDeviceInfo = (AEEDeviceInfo*) MALLOC( sizeof( AEEDeviceInfo ) );
   pImageInfo = (AEEImageInfo*) MALLOC( sizeof( AEEImageInfo ) );

   ISHELL_GetDeviceInfo( pApp->a.m_pIShell, pDeviceInfo );
   IIMAGE_GetInfo( pApp->m_pTitleBarImg, pImageInfo );

   SETAEERECT( &pApp->m_rScreenRect, 0, pImageInfo->cy, pDeviceInfo->cxScreen, pDeviceInfo->cyScreen - pImageInfo->cy );

   // AEEDeviceInfo objects tend to require alot of space.  Its best to create them,
   // extract the exact information required by the application and then release
   // them.

   FREEIF( pDeviceInfo );
   FREEIF( pImageInfo );
   return TRUE;
}

/*===========================================================================

FUNCTION: ET_CreateMainControls

DESCRIPTION:
	Creates controls used by the applet

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   Assumes pApp is not NULL

RETURN VALUE:
   TRUE - Controls created successfully
   FALSE - Control creation failed

SIDE EFFECTS:
   None
===========================================================================*/
static boolean ET_CreateMainControls( CExpenseTrackerApp* pApp )
{
   AEERect rc;
   AEEItemStyle rNormalStyle;
   AEEItemStyle rSelStyle;

   // Create the main application controls.
   if((ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_MENUCTL, (void**)(&pApp->m_pMenu)) != SUCCESS) ||
      (ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_SOFTKEYCTL, (void**)(&pApp->m_pSK)) != SUCCESS) ||
      (ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_DATECTL, (void**)(&pApp->m_pDate)) != SUCCESS) ||
      (ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_LISTCTL, (void**)(&pApp->m_pList)) != SUCCESS) ||
      (ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_TEXTCTL, (void**)(&pApp->m_pText)) != SUCCESS ))
      return FALSE;

  // Create the CAmountCtl control.
  if((pApp->m_pAmount = CAMOUNTCTL_CreateInstance(pApp->a.m_pIShell)) == NULL)
      return FALSE;

  // Let's reset text control size so on subsequent this won't misbehave by erasing screen
  SETAEERECT(&rc, 0, 0, 0, 0);
  ITEXTCTL_SetRect(pApp->m_pText, &rc);

  // Set the style of the menu control so that all the icons are displayed as
  // transparent.  This is set based on the default menu styles.

  ISHELL_GetItemStyle( pApp->a.m_pIShell, AEE_IT_MENU, &rNormalStyle, &rSelStyle );
  rNormalStyle.roImage = AEE_RO_TRANSPARENT;
  rSelStyle.roImage = AEE_RO_TRANSPARENT;
  IMENUCTL_SetStyle( pApp->m_pMenu, &rNormalStyle, &rSelStyle );

  return TRUE;
}

/*===========================================================================

FUNCTION: ET_FreeAppData

DESCRIPTION:
  Frees data contained in app data and memory for app data itself.
  App developer needs to free data contained in AppletData.

PARAMETERS:
	pApp [in] - Applet Structure

DEPENDENCIES:
   Assumes pApp is not NULL

RETURN VALUE:
   None

SIDE EFFECTS:
   None
===========================================================================*/
static void ET_FreeAppData( CExpenseTrackerApp* pApp )
{
   // Release each of the  common controls.
   ET_ReleaseMainControls(pApp);

   // Release banner
   ReleaseObj((void**)&pApp->m_pTitleBarImg);

   // Release the expense tracker database
   ReleaseObj((void**)&pApp->m_pDatabase);

   // Cancel any remaining callbacks
   CALLBACK_Cancel( &pApp->m_rSaveReportCB );
}

/*===========================================================================

FUNCTION: ET_ReleaseMainControls

DESCRIPTION:
  Frees each of the controls used by the application.

PARAMETERS:
	pApp [in] - Applet Structure

DEPENDENCIES:
   Assumes pApp is not NULL

RETURN VALUE:
   None

SIDE EFFECTS:
   None
===========================================================================*/
static void ET_ReleaseMainControls(CExpenseTrackerApp* pApp)
{   
   // Release each of the controls
   ReleaseObj((void**)&pApp->m_pMenu);
   ReleaseObj((void**)&pApp->m_pIStatic);
   ReleaseObj((void**)&pApp->m_pSK);
   ReleaseObj((void**)&pApp->m_pDate);
   ReleaseObj((void**)&pApp->m_pList);
   ReleaseObj((void**)&pApp->m_pText);

   // Release m_pAmount.  This is done seperately since CAmountCtl is not
   // really a BREW control.
   if (pApp->m_pAmount)
      CAMOUNTCTL_Release(pApp->m_pAmount);
}

/*===========================================================================

FUNCTION: ReleaseObj

DESCRIPTION:
  This is a convenience function which releases BREW controls.  It also
  checks that the pointer is not NULL before attempting to release the
  control.

PARAMETERS:
	ReleaseObj [in/out] - Pointer to the data pointer of the control.

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
   None
===========================================================================*/
static void ReleaseObj(void ** ppObj)
{
   if ( ppObj && *ppObj ) 
   {
      (void)IBASE_Release(((IBase *)*ppObj));
      *ppObj = NULL;
   }
}

/*===========================================================================

FUNCTION: ET_HandleEvent

DESCRIPTION:
	This is the main EventHandler for this app. All events to this app are handled in this
	function. All apps must supply an Event Handler.  Key events are passed to specific
  event-handlers depending on the current state of the application.

PARAMETERS:
	pApp [in] - Pointer to the AEEApplet structure. This structure contains information specific
  	to this applet. It was initialized during the AEEClsCreateInstance() function.

	eCode [in] - Specifies the Event sent to this applet

  wParam [in] - Event specific data.

  dwParam [in] - Event specific data.

DEPENDENCIES:
  None

RETURN VALUE:
  TRUE - If the app has processed the event
  FALSE - If the app did not process the event

SIDE EFFECTS:
  None
===========================================================================*/
static boolean ET_HandleEvent(CExpenseTrackerApp * pApp, AEEEvent eCode, uint16 wParam, uint32 dwParam )
{
   JulianType rJulianDate;
   uint16 wButtons[3];
   IDialog* pDlg;
   int len;
   int32 curPos;

   // Let each of the controls have a crack at the event.  If one of them is able to handle
   // the event then return TRUE indicating that the event has been handled.

   if (pApp->m_pIStatic && ISTATIC_HandleEvent(pApp->m_pIStatic, eCode, wParam, dwParam))
      return TRUE;
   if (IMENUCTL_HandleEvent(pApp->m_pMenu, eCode, wParam, dwParam))
      return TRUE;
   if (IMENUCTL_HandleEvent(pApp->m_pSK, eCode, wParam, dwParam))
      return TRUE;
   if (IMENUCTL_HandleEvent(pApp->m_pList, eCode, wParam, dwParam))
      return TRUE;
   if (IDATECTL_HandleEvent(pApp->m_pDate, eCode, wParam, dwParam))
      return TRUE;

   // Allow the left and right arrow keys to be used to move from Description field 
   // to other fields, if the cursor is at the start or end of the Description field
   curPos = ITEXTCTL_GetCursorPos(pApp->m_pText);
   len = WSTRLEN(ITEXTCTL_GetTextPtr(pApp->m_pText));
   if (ITEXTCTL_HandleEvent(pApp->m_pText, eCode, wParam, dwParam))
   {
      // If there is text, then make sure the cursor is at the start or end
      if (len)
      {
         // If the cursor is anywhere between the start and end, let the control handle
         // the event
         if (curPos >= TC_CURSORSTART + 1 &&    // cursor beyond start
               curPos <= len - 1)             // cursor before end
            return TRUE;

         // Check the left and right arrow and CLR key events
         switch( wParam)
         {
         case AVK_RIGHT:
            if (curPos == TC_CURSORSTART || curPos == (len - 1))
               return TRUE;
            break;
         case AVK_LEFT:
            if (curPos == (TC_CURSORSTART + 1) || curPos == len)
               return TRUE;
            break;
         case AVK_CLR:
            return TRUE;
         }
      }
   }

   if (CAMOUNTCTL_HandleEvent(pApp->m_pAmount, eCode, wParam, dwParam))
      return TRUE;

   // None of the app controls is able to handle the event, so the app needs to see if
   // this is an event it needs to handle.  If so, perform the necessary event processing
   // and return TRUE.  Otherwise, do nothing and return FALSE.

   switch( eCode )
   {
   case EVT_APP_START:  // The app has started so display the splash screen.
      ET_DisplaySplashScreen(pApp);
      return TRUE;

   case EVT_APP_STOP:   // Acknowledge that the stop event was received.
      return TRUE;

   case EVT_DIALOG_INIT:   // This app need only acknowledge that this event was received.
      return TRUE;

   case EVT_DIALOG_START:  // This app need only acknowledge that this event was received.
      return TRUE;

   case EVT_DIALOG_END:    // This app need only acknowledge that this event was received.
      return TRUE;

   case EVT_APP_SUSPEND:
     // Cancel all timers, alarms and callbacks.
     CALLBACK_Cancel( &pApp->m_rSaveReportCB );
     ISHELL_CancelTimer( pApp->a.m_pIShell, (PFNNOTIFY) ET_DisplayMainMenu, (void*) pApp );

     // Set all controls to InActive
     IMENUCTL_SetActive( pApp->m_pMenu, FALSE );
     IMENUCTL_SetActive( pApp->m_pSK, FALSE );
     IMENUCTL_SetActive( pApp->m_pList, FALSE );
     IDATECTL_SetActive( pApp->m_pDate, FALSE );
     ITEXTCTL_SetActive( pApp->m_pText, FALSE );
     CAMOUNTCTL_SetActive( pApp->m_pAmount, FALSE );
     if( pApp->m_pIStatic )
       ISTATIC_SetActive( pApp->m_pIStatic, FALSE );

     // Release the 'View' dialog if it has been created.
     pDlg = ISHELL_GetActiveDialog( pApp->a.m_pIShell );
     ReleaseObj( (void**) &pDlg );
     return TRUE;

   case EVT_APP_RESUME:
     // Display the banner at the top of the screen

     IIMAGE_Draw(pApp->m_pTitleBarImg, 0, 0);

     // Redraw the screen based on the current app state and activate the
     // appropriate controls.
 
     switch( pApp->m_eAppState )
     {
     case APP_STATE_SPLASH:
       ET_DisplayMainMenu( pApp );
       return TRUE;

     case APP_STATE_VIEW_LIST:
     case APP_STATE_EDIT:
       ET_DisplayExpenseScreen( pApp );
       return TRUE;

     case APP_STATE_MAIN:
     case APP_STATE_OPTIONS:
       IMENUCTL_SetActive( pApp->m_pMenu, TRUE );
       return TRUE;

     case APP_STATE_LOAD_LIST:
       ET_DisplayReportScreen( pApp );
       return TRUE;

     case APP_STATE_ADD:
       ET_DisplayAddScreen( pApp );
       return TRUE;

     case APP_STATE_VIEW:
       ET_DisplayViewScreen( pApp );
       return TRUE;

     case APP_STATE_REPORT:
     case APP_STATE_SAVE_CONFIRM:
     case APP_STATE_SAVE:
     case APP_STATE_HELP:
     case APP_STATE_ABOUT:
       IMENUCTL_SetActive( pApp->m_pSK, TRUE );
       if( pApp->m_pIStatic )
       {
         ISTATIC_SetActive( pApp->m_pIStatic, TRUE );
         ISTATIC_Redraw( pApp->m_pIStatic );
       }
       return TRUE;
     }
     return TRUE;

   case EVT_COPYRIGHT_END:  // Sent when the copyright dialog is released.
      ET_DisplayMainMenu(pApp);
      return TRUE;
         
   case EVT_CTL_TAB:  // A control is about to lose focus so make it inactive and
                      // activate the next control.
      if( pApp->m_eAppState == APP_STATE_ADD || pApp->m_eAppState == APP_STATE_EDIT )
      {
         switch( wParam )
         {
         case CTL_TAB_RIGHT:  // Handle tab-right events
            if( IDATECTL_IsActive( pApp->m_pDate ) )
            {
               IDATECTL_SetActive( pApp->m_pDate, FALSE );
               IMENUCTL_SetActive( pApp->m_pList, TRUE );
               return TRUE;
            }
            if( IMENUCTL_IsActive( pApp->m_pList ) )
            {
               IMENUCTL_SetActive( pApp->m_pList, FALSE );
               CAMOUNTCTL_SetActive( pApp->m_pAmount, TRUE );
               return TRUE;
            }
            if( CAMOUNTCTL_IsActive( pApp->m_pAmount ) )
            {
               CAMOUNTCTL_SetActive( pApp->m_pAmount, FALSE );
               ITEXTCTL_SetActive( pApp->m_pText, TRUE );
               return TRUE;
            }
            if( ITEXTCTL_IsActive( pApp->m_pText ) )
            {
               ITEXTCTL_SetActive( pApp->m_pText, FALSE );
               IMENUCTL_SetActive( pApp->m_pSK, TRUE );     
               return TRUE;
            }
            if( IMENUCTL_IsActive( pApp->m_pSK ) )
            {
               IMENUCTL_SetActive( pApp->m_pSK, FALSE );
               IDATECTL_SetActive( pApp->m_pDate, TRUE );
               return TRUE;
            }                  
            break;

         case CTL_TAB_LEFT:  // Handle tab-left events
            if( IDATECTL_IsActive( pApp->m_pDate ) )
            {
               IDATECTL_SetActive( pApp->m_pDate, FALSE );
               IMENUCTL_SetActive( pApp->m_pSK, TRUE );
               return TRUE;
            }
            if( IMENUCTL_IsActive( pApp->m_pList ) )
            {
               IMENUCTL_SetActive( pApp->m_pList, FALSE );
               IDATECTL_SetActive( pApp->m_pDate, TRUE );
               return TRUE;
            }
            if( CAMOUNTCTL_IsActive( pApp->m_pAmount ) )
            {
               CAMOUNTCTL_SetActive( pApp->m_pAmount, FALSE );
               IMENUCTL_SetActive( pApp->m_pList, TRUE );
               return TRUE;
            }
            if( ITEXTCTL_IsActive( pApp->m_pText ) )
            {
               ITEXTCTL_SetActive( pApp->m_pText, FALSE );
               CAMOUNTCTL_SetActive( pApp->m_pAmount, TRUE );
               return TRUE;
            }
            if( IMENUCTL_IsActive( pApp->m_pSK ) )
            {
               IMENUCTL_SetActive( pApp->m_pSK, FALSE );
               ITEXTCTL_SetActive( pApp->m_pText, TRUE );
               return TRUE;
            }
            break;
         }
      }
      return FALSE;

   case EVT_CTL_SEL_CHANGED:
      // If the expense list screen is showing and the user changes the selected
      // expense item in the menu control, get the description of the transaction
      // from the database and display it at the top of the screen.
      if (pApp->m_eAppState == APP_STATE_VIEW_LIST)
      {            
         AECHAR psTitle[ MAX_DESC_SIZE + 1 ];            
         IMenuCtl * pMenu = (IMenuCtl*)dwParam;
         uint16 nRecordID = IMENUCTL_GetSel(pMenu) - EXPENSE_LIST_ID;
         ET_GetExpenseItem( pApp, nRecordID, NULL, psTitle, NULL, NULL );         
         IMENUCTL_SetTitle(pMenu, NULL, NULL, psTitle);
         IMENUCTL_Redraw(pMenu);
         return TRUE;
      }
      break;

   case EVT_COMMAND:  // Handle 'SELECT' button events
      switch(wParam)
      {
      case IDC_ADD_NEW:  // User selected 'Add New' from the Main Menu
         pApp->m_eAppState = APP_STATE_ADD;
         ET_DisplayAddScreen(pApp);
         return TRUE;

      case IDC_DONE:  // User pressed the 'Done' button
         MEMSET(&rJulianDate, 0, sizeof(rJulianDate));
         IDATECTL_GetDate( pApp->m_pDate, (int*) &rJulianDate.wYear, (int*) &rJulianDate.wMonth, (int*) &rJulianDate.wDay );

         // If the 'Add' screen is displayed, add the expense entry to the database
         if( pApp->m_eAppState == APP_STATE_ADD )
         {
            AECHAR * pText = ITEXTCTL_GetTextPtr( pApp->m_pText );
            ET_AddExpenseItem( pApp, 
                               JULIANTOSECONDS(&rJulianDate), 
                               (unsigned char) IMENUCTL_GetSel( pApp->m_pList ),
                               (pText ? pText : (AECHAR*)""),
                               CAMOUNTCTL_GetValue( pApp->m_pAmount ) );
         }

         // If the 'Edit' screen is displayed, update the expense entry in the database.
         if( pApp->m_eAppState == APP_STATE_EDIT )
         {
            AECHAR * pText = ITEXTCTL_GetTextPtr( pApp->m_pText );
           ET_UpdateExpenseItem( pApp,
                                 pApp->m_nRecordEditNum,
                                 JULIANTOSECONDS(&rJulianDate),
                                 (unsigned char) IMENUCTL_GetSel( pApp->m_pList ),
                                 (pText ? pText : (AECHAR*)""),
                                 CAMOUNTCTL_GetValue( pApp->m_pAmount ) );
         }
         ET_DisplayMainMenu(pApp);
         return TRUE;

      case IDC_ERASE:  // User pressed the erase button in the 'Edit' screen so delete
                       // the entry from the database.
         ET_DeleteExpenseItem( pApp, pApp->m_nRecordEditNum );
         ET_DisplayMainMenu(pApp);
         return TRUE;

      case IDC_VIEW:  // User selected the 'View' option from the Main Menu
         ET_DisplayViewScreen( pApp );
         return TRUE;

      case IDLI_VIEW_MENU_VIEW:
         // User pressed the 'View' button on the view screen.  Find all the expense items in the
         // database that match the entered search criteria and display them.
         ET_ReadViewSelections( pApp );
         ET_DisplayExpenseScreen( pApp );
         return TRUE;

      case IDC_NO:       // The user selected 'Options' from the Main Menu or pressed 'No' in a 
      case IDC_OPTIONS:  // confirmation screen so display the 'Options' menu on the screen.
         ET_DisplayOptionsScreen( pApp );
         return TRUE;

      case IDC_LOAD_REPORT:  // The user selected 'Load Report' from the options menu
         ET_DisplayReportScreen(pApp);
         return TRUE;

      case IDC_SAVE_REPORT:  // The user selected 'Save Report' from the options menu.
         // Display a confirmation screen requesting the user to confirm that they wish to
         // save the database to a report.
         MEMSET(wButtons, 0, sizeof(wButtons));
         wButtons[0] = IDC_YES;
         wButtons[1] = IDC_NO;
         pApp->m_eAppState = APP_STATE_SAVE_CONFIRM;
         ET_Reset(pApp, TRUE);
         ET_Prompt(pApp, NULL, IDC_SAVE_REPORT, NULL, IDS_SAVE_CONFIRMATION_STRING, NULL, (unsigned short*)&wButtons, wButtons[0], 0);
         return TRUE;

      case IDC_YES:  // The user selected 'Yes' in the save confirmation screen
         pApp->m_eAppState = APP_STATE_SAVE;
         CALLBACK_Init( &pApp->m_rSaveReportCB, (PFNNOTIFY) ET_SaveReportStartCB, pApp );
         ET_DisplayBanner( pApp, IDS_SAVING_DATABASE );
         ISHELL_Resume( pApp->a.m_pIShell, &pApp->m_rSaveReportCB );
         return TRUE;

      case IDC_HELP:  // The user selected 'Help' from the Main Menu
         ET_DisplayHelpScreen(pApp);
         return TRUE;

      case IDC_ABOUT:  // The user selected 'About' from the Main Menu
         ET_DisplayAboutScreen(pApp);
         return TRUE;

      case IDC_OK:  // The user pressed the 'OK' button in the help or about screen
         ET_DisplayMainMenu(pApp);
         return TRUE;

      default:
         // If the wParam ID matches the ID of a report listed in the report list screen
         // load the report and display it on the screen.
         if (wParam >= REPORT_LIST_ID)
         {
            CtlAddItem ai;               
            uint16 nItemID = IMENUCTL_GetSel(pApp->m_pMenu);
            char* pFileName = (char*) MALLOC( MAX_FILE_NAME + 1 );
        
            IMENUCTL_GetItem(pApp->m_pMenu, nItemID, &ai);
            if( pFileName )
            {
               WSTRTOSTR(ai.pText, pFileName, MAX_FILE_NAME + 1);
               STRLOWER(pFileName);
               STRCAT( pFileName, REPORT_FILE_EXTENSION );

               pApp->m_eAppState = APP_STATE_REPORT;
               ET_Reset(pApp, TRUE);
            }
            ET_Prompt(pApp, NULL, IDS_REPORT, NULL, 0, pFileName, 0, 0, ST_NOSCROLL);
            FREEIF( pFileName );
            return TRUE;
         }
         // If the wParam ID matches the ID of an expense item listed in the expense list screen
         // load the expense information from the database and display it in the 'Edit' screen.
         if (wParam >= EXPENSE_LIST_ID)
         {
            uint16 nRecordID = wParam - EXPENSE_LIST_ID; 
            pApp->m_eAppState = APP_STATE_EDIT;
            ET_DisplayAddScreen(pApp);
            ET_SetAddScreenSelections(pApp, nRecordID);
            return TRUE;
         }
         break;
      }         
      break;

   case EVT_KEY:  // Handle KEY events when a phone button is pressed
      switch(wParam)
      {
      case AVK_CLR:
         // If the clear button is pressed, back up one screen depending on the
         // current application state
         switch (pApp->m_eAppState)
         {
         case APP_STATE_ADD:
         case APP_STATE_VIEW:
         case APP_STATE_OPTIONS:
         case APP_STATE_HELP:
            ET_DisplayMainMenu(pApp);
            return TRUE;

         case APP_STATE_VIEW_LIST:
           ET_DisplayViewScreen( pApp );
           return TRUE;

         case APP_STATE_EDIT:
            ET_DisplayExpenseScreen(pApp);
            return TRUE;

         case APP_STATE_LOAD_LIST:
         case APP_STATE_SAVE_CONFIRM:
         case APP_STATE_SAVE:
            if (wParam == APP_STATE_SAVE)
            {
               if (pApp->m_rSaveReportCB.pfnCancel)
                  CALLBACK_Cancel(&pApp->m_rSaveReportCB);
            }
            ET_DisplayOptionsScreen(pApp);
            return TRUE;

         case APP_STATE_REPORT:
            ET_DisplayReportScreen(pApp);
            return TRUE;
         }
         break;
            
      case AVK_LEFT:
         if (ITEXTCTL_IsActive(pApp->m_pText))
         {
            ISHELL_SendEvent( pApp->a.m_pIShell, pApp->a.clsID, EVT_CTL_TAB, CTL_TAB_LEFT, NULL );
            return TRUE;
         }
         break;

      case AVK_RIGHT:
         if (ITEXTCTL_IsActive(pApp->m_pText))
         {
            ISHELL_SendEvent( pApp->a.m_pIShell, pApp->a.clsID, EVT_CTL_TAB, CTL_TAB_RIGHT, NULL );
            return TRUE;
         }
         break;
            
      case AVK_SELECT:  // Handle 'SELECT' button presses if the text control has focus.
         if (ITEXTCTL_IsActive(pApp->m_pText))
         {
            ISHELL_SendEvent( pApp->a.m_pIShell, pApp->a.clsID, EVT_CTL_TAB, CTL_TAB_RIGHT, NULL );
            return TRUE;
         }
         break;
      }
   }
   return FALSE;
}

/*****************************************************************************
  Display Functions
*****************************************************************************/

/*===========================================================================

FUNCTION: ET_DisplaySplashScreen 

DESCRIPTION:
	This function displays the splash screen.  A timer is set to call 
  ET_DisplayMainMenu after the timer fires to start the application.
  If the splash image cannot be loaded, then just display the main menu.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
  None

RETURN VALUE:
  None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Set application state to APP_STATE_SPLASH.
===========================================================================*/

static void ET_DisplaySplashScreen(CExpenseTrackerApp * pApp)
{
   IImage* pImage = NULL;
   AEEImageInfo rImageInfo;

   // Load the splash image from the rsource file
   pImage = ISHELL_LoadResImage( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDB_SPLASH );

   if(pImage)
   {
      // Clear screen and draw the image in the center of the screen
      IDISPLAY_ClearScreen( pApp->a.m_pIDisplay );
      IIMAGE_GetInfo( pImage, &rImageInfo );
      IIMAGE_Draw(pImage, ((pApp->m_rScreenRect.x + pApp->m_rScreenRect.dx)/2) - (rImageInfo.cx/2), ((pApp->m_rScreenRect.y + pApp->m_rScreenRect.dy)/2) - (rImageInfo.cy/2));
      IDISPLAY_Update( pApp->a.m_pIDisplay );
      IIMAGE_Release( pImage );  // the image is drawn so we don't need it any more

      // Set the callback timer to call this function again
      ISHELL_SetTimer( pApp->a.m_pIShell, BANNER_DISPLAY_TIMER, (PFNNOTIFY) ET_DisplayMainMenu, (void*) pApp );
   }
   else
   {
      ET_DisplayMainMenu( pApp );
   }
   pApp->m_eAppState = APP_STATE_SPLASH;
}

/*===========================================================================

FUNCTION: ET_DisplayMainMenu

DESCRIPTION:
	This function displays the application Main Menu.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Set application state to APP_STATE_MAIN.
===========================================================================*/

static void ET_DisplayMainMenu( CExpenseTrackerApp* pApp )
{
   CtlAddItem ai;

   ET_Reset(pApp, TRUE);

   // Set Title
   IMENUCTL_SetTitle( pApp->m_pMenu, EXPENSETRACKER_RES_FILE, IDS_MAIN_MENU, NULL);

   // Add Items in the Menu
   ai.pText = NULL;
   ai.pImage = NULL;
   ai.pszResImage = ai.pszResText = EXPENSETRACKER_RES_FILE;
   ai.wFont = AEE_FONT_NORMAL;
   ai.dwData = 0;

   // Add New
   ai.wText = IDC_ADD_NEW;
   ai.wImage = IDB_ADD_NEW;
   ai.wItemID = IDC_ADD_NEW;

   IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

   // View
   ai.wText = IDC_VIEW;
   ai.wImage = IDB_VIEW;
   ai.wItemID = IDC_VIEW;

   IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

   // Options
   ai.wText = IDC_OPTIONS;
   ai.wImage = IDB_OPTIONS;
   ai.wItemID = IDC_OPTIONS;

   IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

   // Help
   ai.wText = IDC_HELP;
   ai.wImage = IDB_HELP;
   ai.wItemID = IDC_HELP;

   IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

   // About
   ai.wText = IDC_ABOUT;
   ai.wImage = IDB_ABOUT;
   ai.wItemID = IDC_ABOUT;

   IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

   IMENUCTL_SetRect( pApp->m_pMenu, &pApp->m_rScreenRect );
   IMENUCTL_SetActive( pApp->m_pMenu, TRUE );
   pApp->m_eAppState = APP_STATE_MAIN;
}

/*===========================================================================

FUNCTION: ET_DisplayAddScreen

DESCRIPTION:
	This function displays the Add/Edit screen used to add new expenses to the 
  database or edit existing expenses.

  The application state must be set to APP_STATE_ADD or APP_STATE_EDIT prior
  to the call since this screen can be used for both adding and 
  editing functions.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

static void ET_DisplayAddScreen(CExpenseTrackerApp* pApp)
{
   uint16 nControlYLoc = 0;
   JulianType rJulianDate;

   ET_Reset(pApp, FALSE);

   if( pApp->m_eAppState == APP_STATE_ADD )
     ET_DisplayControl( pApp, IDC_ADD_NEW, NULL, nControlYLoc );
   else
     ET_DisplayControl( pApp, IDS_EDIT_EXPENSE, NULL, nControlYLoc );

   // Display Date Control with current date
   GETJULIANDATE(0, &rJulianDate);
   rJulianDate.wHour = 0;
   rJulianDate.wMinute = 0;
   rJulianDate.wSecond = 0;
   IDATECTL_SetDate( pApp->m_pDate, rJulianDate.wYear, rJulianDate.wMonth, rJulianDate.wDay );
   nControlYLoc += pApp->m_nFontHeight + 3;
   ET_DisplayControl( pApp, IDS_DATE, (IControl*) pApp->m_pDate, nControlYLoc );

   // Display List of Transactions Types
   IMENUCTL_AddItem( pApp->m_pList, EXPENSETRACKER_RES_FILE, IDS_CASH, IDLI_TRANS_TYPE_CASH, NULL, 0 );
   IMENUCTL_AddItem( pApp->m_pList, EXPENSETRACKER_RES_FILE, IDS_CHECK, IDLI_TRANS_TYPE_CHECK, NULL, 0 );
   IMENUCTL_AddItem( pApp->m_pList, EXPENSETRACKER_RES_FILE, IDS_CREDIT, IDLI_TRANS_TYPE_CREDIT, NULL, 0 );
   IMENUCTL_AddItem( pApp->m_pList, EXPENSETRACKER_RES_FILE, IDS_DEBIT, IDLI_TRANS_TYPE_DEBIT, NULL, 0 );
   IMENUCTL_EnableCommand( pApp->m_pList, FALSE );
   nControlYLoc += pApp->m_nFontHeight + 2;
   ET_DisplayControl( pApp, IDS_TYPE, (IControl*) pApp->m_pList, nControlYLoc );

   // Display Amount
   CAMOUNTCTL_SetValue( pApp->m_pAmount, 0 );
   nControlYLoc += pApp->m_nFontHeight + 2;
   ET_DisplayControl( pApp, IDS_AMOUNT, (IControl*) pApp->m_pAmount, nControlYLoc );

   // Display Description Control
   ITEXTCTL_Reset( pApp->m_pText );
   ITEXTCTL_SetProperties( pApp->m_pText, TP_FRAME );
   ITEXTCTL_SetInputMode( pApp->m_pText, AEE_TM_LETTERS );
   ITEXTCTL_SetMaxSize( pApp->m_pText, MAX_DESC_SIZE );
   nControlYLoc += pApp->m_nFontHeight + 2;
   ET_DisplayControl( pApp, IDS_DESC, (IControl*) pApp->m_pText, nControlYLoc );

   // Display Soft Key
   IMENUCTL_AddItem( pApp->m_pSK, EXPENSETRACKER_RES_FILE, IDC_DONE, IDC_DONE, NULL, 0 );
   if( pApp->m_eAppState == APP_STATE_EDIT )
   {
     IMENUCTL_AddItem( pApp->m_pSK, EXPENSETRACKER_RES_FILE, IDC_ERASE, IDC_ERASE, NULL, 0 );
   }
   IMENUCTL_Redraw( pApp->m_pSK);

   // Activate date control
   IDATECTL_SetActive(pApp->m_pDate, TRUE);
}

/*===========================================================================

FUNCTION: ET_DisplayViewScreen

DESCRIPTION:
	This function displays the View screen which allows the user to specify
  the search parameters used to display expense records.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Sets the application state to APP_STATE_VIEW.
===========================================================================*/

static void ET_DisplayViewScreen( CExpenseTrackerApp* pApp )
{
   uint16 nControlYLoc;
   JulianType rJulianDate;
   IDialog  * pDlg = NULL;
   IControl * pCtl = NULL; 
 
   ET_Reset(pApp, TRUE);
 
   if( ISHELL_CreateDialog( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDDG_VIEW, NULL ) != SUCCESS )
      return;

   // Draw Banner
   IIMAGE_Draw(pApp->m_pTitleBarImg, 0, 0);

   // Display Title
   nControlYLoc = pApp->m_rScreenRect.y;
   ET_DisplayControl( pApp, IDS_VIEW_PARAMETERS, NULL, nControlYLoc );

   pDlg = ISHELL_GetActiveDialog( pApp->a.m_pIShell );

   // Display Type
   pCtl = IDIALOG_GetControl( pDlg, IDLC_VIEW_TYPE );
   IMENUCTL_EnableCommand( (IMenuCtl*) pCtl, FALSE );
   nControlYLoc += pApp->m_nFontHeight + 3;
   ET_DisplayControl( pApp, IDS_TYPE, (IControl*) pCtl, nControlYLoc );

   // Reset From and To dates
   pApp->m_nFromDate = pApp->m_nToDate = 0;

   // Display From
   pCtl = IDIALOG_GetControl( pDlg, IDDC_VIEW_FROM );
   GETJULIANDATE( pApp->m_nFromDate, &rJulianDate );
   IDATECTL_SetDate((IDateCtl*) pCtl, rJulianDate.wYear, rJulianDate.wMonth, rJulianDate.wDay );
   nControlYLoc += pApp->m_nFontHeight + 3;
   ET_DisplayControl( pApp, IDS_FROM, pCtl, nControlYLoc );

   // Display To
   pCtl = IDIALOG_GetControl( pDlg, IDDC_VIEW_TO );
   GETJULIANDATE( pApp->m_nToDate, &rJulianDate );
   IDATECTL_SetDate((IDateCtl*) pCtl, rJulianDate.wYear, rJulianDate.wMonth, rJulianDate.wDay );
   nControlYLoc += pApp->m_nFontHeight + 3;
   ET_DisplayControl( pApp, IDS_TO, pCtl, nControlYLoc );

   pApp->m_eAppState = APP_STATE_VIEW;
}

/*===========================================================================

FUNCTION: ET_DisplayExpenseScreen

DESCRIPTION:
	This function displays the list of expenses based on the parameters 
  set by the user in the View screen.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Sets the application state to APP_STATE_VIEW_LIST.
===========================================================================*/

static void ET_DisplayExpenseScreen( CExpenseTrackerApp* pApp )
{
   AEERect rRect;
   uint32 nTotal = 0;
   AECHAR* psTextBuf;

   ET_Reset(pApp, TRUE);

   // Display Expenses
   ET_DisplayControl( pApp, IDS_EXPENSES, NULL, pApp->m_rScreenRect.y);

   SETAEERECT( &rRect, 0, pApp->m_rScreenRect.y + pApp->m_nFontHeight, pApp->m_rScreenRect.dx, pApp->m_rScreenRect.dy - ( 3 * pApp->m_nFontHeight ) );
   IMENUCTL_SetRect( pApp->m_pMenu, &rRect );

   // Get Expense List
   ET_GetExpenseList( pApp, pApp->m_pMenu, &nTotal, pApp->m_nFromDate, pApp->m_nToDate, (unsigned char) pApp->m_nTransType );

   // Set Appropriate Title
   if( IDATABASE_GetRecordCount( pApp->m_pDatabase ) == 0 )
      IMENUCTL_SetTitle(pApp->m_pMenu, EXPENSETRACKER_RES_FILE, IDS_DATABASE_EMPTY, NULL);
   else
   {
      if( IMENUCTL_GetItemCount( pApp->m_pMenu ) == 0 )         
         IMENUCTL_SetTitle(pApp->m_pMenu, EXPENSETRACKER_RES_FILE, IDS_NO_MATCHES, NULL);
      else
      {         
         AECHAR psTitle[ MAX_DESC_SIZE + 1 ];
         uint16 nRecordID = IMENUCTL_GetSel( pApp->m_pMenu ) - EXPENSE_LIST_ID;
         ET_GetExpenseItem( pApp, nRecordID, NULL, psTitle, NULL, NULL );         
         IMENUCTL_SetTitle(pApp->m_pMenu, NULL, NULL, psTitle);
      }
   }

   // Active Menu
   IMENUCTL_SetActive( pApp->m_pMenu, TRUE);

   // Display Total String
   SETAEERECT( &rRect, 0, ( pApp->m_rScreenRect.y + pApp->m_rScreenRect.dy ) - pApp->m_nFontHeight, pApp->m_rScreenRect.dx, pApp->m_nFontHeight );
   psTextBuf = (AECHAR*) MALLOC( MAX_RES_STRING_BUF_SIZE * sizeof( AECHAR ) );
   if( psTextBuf )
   {
      ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDS_TOTAL_STRING, psTextBuf, MAX_RES_STRING_BUF_SIZE * sizeof( AECHAR ) );
      CAMOUNTCTL_ConvertValueToString( nTotal, &( psTextBuf[ WSTRLEN( psTextBuf ) ] ), ( MAX_RES_STRING_BUF_SIZE - WSTRLEN( psTextBuf ) ) * sizeof( AECHAR ) );
      IDISPLAY_DrawText( pApp->a.m_pIDisplay, AEE_FONT_NORMAL, psTextBuf, -1, rRect.x, rRect.y, &rRect, IDF_ALIGN_CENTER | IDF_ALIGN_MIDDLE );
      IDISPLAY_Update( pApp->a.m_pIDisplay );
      FREEIF( psTextBuf );
   }

   pApp->m_eAppState = APP_STATE_VIEW_LIST;
}

/*===========================================================================

FUNCTION: ET_DisplayOptionsScreen

DESCRIPTION:
	this function displays the options menu.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Sets application state to APP_STATE_OPTIONS.
===========================================================================*/
static void ET_DisplayOptionsScreen( CExpenseTrackerApp* pApp )
{
   CtlAddItem ai;

   ET_Reset(pApp, TRUE);

   // Set Title
   IMENUCTL_SetTitle( pApp->m_pMenu, EXPENSETRACKER_RES_FILE, IDC_OPTIONS, NULL);

   // Add Items in the Menu
   ai.pText = NULL;
   ai.pImage = NULL;
   ai.pszResImage = ai.pszResText = EXPENSETRACKER_RES_FILE;
   ai.wFont = AEE_FONT_NORMAL;
   ai.dwData = 0;

   // Load Report
   ai.wText = IDC_LOAD_REPORT;
   ai.wImage = IDB_LOAD;
   ai.wItemID = IDC_LOAD_REPORT;

   IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

   // Only display the 'Save Report' menu option if there is at least one expense
   // item entry in the database.
   if(IDATABASE_GetRecordCount(pApp->m_pDatabase) > 0)
   {
      // Save Report
      ai.wText = IDC_SAVE_REPORT;
      ai.wImage = IDB_SAVE;
      ai.wItemID = IDC_SAVE_REPORT;

      IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);
   }

   IMENUCTL_SetRect( pApp->m_pMenu, &pApp->m_rScreenRect );
   IMENUCTL_SetActive( pApp->m_pMenu, TRUE );

   pApp->m_eAppState = APP_STATE_OPTIONS;
}

/*===========================================================================

FUNCTION: ET_DisplayReportScreen

DESCRIPTION:
	This function displays a list of all the reports stored in the phone's
  file system.  If no reports exist, a prompt screen is displayed indicating
  that no reports were found.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Sets the application state to APP_STATE_LOAD_LIST.
===========================================================================*/
static void ET_DisplayReportScreen( CExpenseTrackerApp* pApp )
{
   ET_Reset(pApp, TRUE);

   // Fill the menu with all the reports stroed in the phones file system
   ET_GetReportList( pApp, pApp->m_pMenu );

   if( IMENUCTL_GetItemCount( pApp->m_pMenu ) == 0 )
   {
      // No reports on the phone so display a message indicating this.
      uint16 wButtons[2];

      // Display Prompt
      MEMSET(wButtons, 0, sizeof(wButtons));
      wButtons[0] = IDC_OK;
      ET_Prompt(pApp, NULL, IDC_LOAD_REPORT, NULL, IDS_NO_REPORT_STRING, NULL, (unsigned short*)&wButtons, wButtons[0], 0);
   }
   else
   {
      // At least on report found so display the report list screen
      IMENUCTL_SetRect( pApp->m_pMenu, &pApp->m_rScreenRect );
      // Set Title
      IMENUCTL_SetTitle( pApp->m_pMenu, EXPENSETRACKER_RES_FILE, IDC_LOAD_REPORT, NULL);
      // Activate
      IMENUCTL_SetActive( pApp->m_pMenu, TRUE);
   }
   pApp->m_eAppState = APP_STATE_LOAD_LIST;
}

/*===========================================================================

FUNCTION: ET_DisplayHelpScreen

DESCRIPTION:
	This function displays the application's help screen.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Sets the application state to APP_STATE_HELP.
===========================================================================*/

static void ET_DisplayHelpScreen(CExpenseTrackerApp * pApp)
{
   uint16 wButtons[2];

   // Display the prompt screen.

   MEMSET(wButtons, 0, sizeof(wButtons));
   wButtons[0] = IDC_OK;
   ET_Prompt(pApp, NULL, IDC_HELP, NULL, 0, EXPENSETRACKER_HELP_FILE, wButtons, wButtons[0], ST_ASCII|ST_NOSCROLL);

   pApp->m_eAppState = APP_STATE_HELP;
}

/*===========================================================================

FUNCTION: ET_DisplayAboutScreen

DESCRIPTION:
	This function displays the application's about screen.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
  Sets the application state to APP_STATE_ABOUT.
===========================================================================*/

static void ET_DisplayAboutScreen(CExpenseTrackerApp * pApp)
{
  ET_Reset( pApp, TRUE);
  IDISPLAY_ClearScreen( pApp->a.m_pIDisplay );
  ISHELL_ShowCopyright( pApp->a.m_pIShell );
  pApp->m_eAppState = APP_STATE_ABOUT;
}

/*****************************************************************************
  Database Related Functions
*****************************************************************************/

/*===========================================================================

FUNCTION: ET_ReadViewSelections

DESCRIPTION:
	Reads selections specified in each control of the view screen.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
   None
===========================================================================*/

static void ET_ReadViewSelections( CExpenseTrackerApp* pApp )
{
   JulianType rJulianDate;
   IDialog* pDlg = ISHELL_GetActiveDialog( pApp->a.m_pIShell );

   MEMSET(&rJulianDate, 0, sizeof(rJulianDate));

   // Read Transaction Type
   pApp->m_nTransType = IMENUCTL_GetSel( (IMenuCtl*) IDIALOG_GetControl( pDlg, IDLC_VIEW_TYPE ) );

   // Read To Date
   IDATECTL_GetDate( (IDateCtl*) IDIALOG_GetControl( pDlg, IDDC_VIEW_FROM ), (int*) &rJulianDate.wYear, (int*) &rJulianDate.wMonth, (int*) &rJulianDate.wDay );
   pApp->m_nFromDate = JULIANTOSECONDS( &rJulianDate );

   // Read From Date
   IDATECTL_GetDate( (IDateCtl*) IDIALOG_GetControl( pDlg, IDDC_VIEW_TO ), (int*) &rJulianDate.wYear, (int*) &rJulianDate.wMonth, (int*) &rJulianDate.wDay );
   pApp->m_nToDate = JULIANTOSECONDS( &rJulianDate );

   // End Dialog
   ISHELL_EndDialog( pApp->a.m_pIShell);
}

/*===========================================================================

FUNCTION: ET_SetAddScreenSelections

DESCRIPTION:
	Reads record corresponding to the specified record ID and assigns controls
  in the edit screen with the contents of the record.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

static void ET_SetAddScreenSelections( CExpenseTrackerApp* pApp, uint16 nRecordID )
{
   dword nDate, nAmount;
   unsigned char nType;
   AECHAR szDesc[MAX_DESC_SIZE + 1];
   JulianType rJulianDate;

   // Read the record specified in  nRecordID from the database
   ET_GetExpenseItem(pApp, nRecordID, &nDate, szDesc, &nType, &nAmount );

   // Set the record values in the controls of the Edit screen
   // Set the transaction type
   IMENUCTL_SetSel( pApp->m_pList, nType );
   IMENUCTL_Redraw( pApp->m_pList);

   // Set the amount
   CAMOUNTCTL_SetValue( pApp->m_pAmount, nAmount );
   CAMOUNTCTL_Redraw( pApp->m_pAmount);

   // Set the description
   ITEXTCTL_SetText( pApp->m_pText, szDesc, -1 );
   ITEXTCTL_Redraw( pApp->m_pText);

   // Set the date
   GETJULIANDATE( nDate, &rJulianDate );  
   IDATECTL_SetDate( pApp->m_pDate, rJulianDate.wYear, rJulianDate.wMonth, rJulianDate.wDay );
   IDATECTL_Redraw( pApp->m_pDate);

   pApp->m_nRecordEditNum = nRecordID;
}

/*===========================================================================

FUNCTION: ET_SaveReportStartCB, ET_SaveReportEndCB 

DESCRIPTION:
  These functions save all database entries to a formatted text file.  Once
  the database is saved to a report, the database is cleared of all entries.

  When ExpenseTracker saves the database, it first draws a dialog to the 
  device screen indicating that the database is being saved.  It then sets
  up a callback to ET_SaveReportStartCB to perform the actual saving of
  the data.  The callback is required because in order to render the dialog
  message to the screen, control must be returned to BREW's event loop.  This
  causes any pending screen update operations to be performed.  BREW then
  invokes the pending ET_SaveReportStartCB callback.

  Once the report has been generated and the database cleared, a timer is
  set which calls ET_SaveReportEndCB.  The dialog message is then changed
  to indicated that the report generation has completed.  When the 
  ET_SaveReportStartCB function returns, control reverts back to BREW's
  event loop which updates the screen to display the new message.

  Finally, when the timer fires, the ET_SaveReportEndCB function is called
  which clears the screen and displays the application's Main Menu screen.

PARAMETERS:
	pData [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

void ET_SaveReportStartCB( void* pData )
{
  CExpenseTrackerApp* pApp = (CExpenseTrackerApp*) pData;

  // Save the contents of the database to a formatted text file

  ET_SaveReport( pApp );

  // Remove all entries from the database

  ET_EmptyExpenseDatabase( pApp );

  // Set a callbasck timer to the ET_SaveReportEndCB callback function

  ISHELL_SetTimer( pApp->a.m_pIShell, BANNER_DISPLAY_TIMER, (PFNNOTIFY) ET_SaveReportEndCB, (void*) pApp );

  // Display a banner indicating that the save operation is complete

  ET_DisplayBanner( pApp, IDS_SAVE_COMPLETE );
}

static void ET_SaveReportEndCB( void* pData )
{
  CExpenseTrackerApp* pApp = (CExpenseTrackerApp*) pData;

  // Transition the app to the APP_STATE_MAIN state

  ET_DisplayMainMenu( pApp );
}

/*****************************************************************************
  General Purpose Routines
*****************************************************************************/

/*===========================================================================

FUNCTION: ET_DisplayBanner

DESCRIPTION:
	General purpose routine to display a banner corresponding to the specified
  resource string.  This routine is used to display messages while the database
  is being saved as a report.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

  nResStringID [in] - The ID of the string resource to be displayed in the 
    banner.

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

static void ET_DisplayBanner( CExpenseTrackerApp* pApp, uint16 nResStringID )
{
  AEERect rRect;
  AECHAR psTextBuf[ MAX_RES_STRING_BUF_SIZE ];

  // Draw the text frame in the center of the screen

  SETAEERECT( &rRect, 5, ( pApp->m_rScreenRect.dy / 2 ) - pApp->m_nFontHeight, pApp->m_rScreenRect.dx - 10, pApp->m_nFontHeight * 2 );
  IDISPLAY_DrawRect( pApp->a.m_pIDisplay, &rRect, RGB_BLACK, RGB_WHITE, IDF_RECT_FRAME | IDF_RECT_FILL );

  // Load the resource string

  ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, nResStringID, psTextBuf, MAX_RES_STRING_BUF_SIZE );

  // Draw the resource string in the center of the box

  rRect.x++;
  rRect.dx -= 2;
  IDISPLAY_DrawText( pApp->a.m_pIDisplay, AEE_FONT_BOLD, psTextBuf, -1, 0, 0, &rRect, IDF_ALIGN_CENTER | IDF_ALIGN_MIDDLE );
  IDISPLAY_Update( pApp->a.m_pIDisplay );
}

/*===========================================================================

FUNCTION: ET_DisplayControl

DESCRIPTION:
	This a general purpose function to position a control and a corresponding 
  text label on the phone screen.  The label is displayed to the left on the
  same line as the control.

  The function measures the number of pixels required to display the label.
  The label is then drawn to the screen.  The width of the corresponding
  control rectangle is set to the width of the device screen minus the 
  width of the label string.  The contro is then displayed to the right
  of the label.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

  nTitleID [in] - The ID of the string resource to be used as the label for
    the control.

  pCtl [in] - A pointer to the control to be displayed.

  yPos [in] - The starting Y coordinate where the control and its label should
    be displayed on the screen.

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

static void ET_DisplayControl( CExpenseTrackerApp* pApp, uint16 nTitleID, IControl* pCtl, int16 yPos )
{
  AECHAR* psTextBuf;
  AEERect rRect;

  psTextBuf = (AECHAR*) MALLOC( MAX_RES_STRING_BUF_SIZE * sizeof( AECHAR ) );

  // Load the string resource that represents the text lable of the control
  if( psTextBuf )
  {
     ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, nTitleID, psTextBuf, MAX_RES_STRING_BUF_SIZE * sizeof( AECHAR ) );

     // Set the position of the label's daring rectangle
     SETAEERECT( &rRect, 2, yPos, IDISPLAY_MeasureText( pApp->a.m_pIDisplay, AEE_FONT_BOLD, psTextBuf ), pApp->m_nFontHeight );
     IDISPLAY_DrawText( pApp->a.m_pIDisplay, AEE_FONT_BOLD, psTextBuf, -1, 0, yPos, &rRect, IDF_ALIGN_BOTTOM | IDF_ALIGN_LEFT );
     IDISPLAY_Update( pApp->a.m_pIDisplay);
     FREEIF( psTextBuf );
  }

  if( !pCtl )
    return;

  // Set the starting X coordinate position of the control and its width (screen width
  // minus the width of the label string).
  rRect.x = rRect.dx;
  rRect.dx = pApp->m_rScreenRect.dx - rRect.x;

  // The CAmountCtl object is not a true BREW control.  Therefore it is not derived
  // from IControl.  So it must be handled seperately from the other true brew
  // controls by checking its pointer value.
  if( pCtl == (IControl*) pApp->m_pAmount )
  {
    CAMOUNTCTL_SetRect( (CAmountCtl*) pCtl, &rRect );
    CAMOUNTCTL_Redraw( (CAmountCtl*) pCtl );
  }
  else
  {
    ICONTROL_SetRect( pCtl, &rRect );
    ICONTROL_Redraw( pCtl );
  }
}

/*===========================================================================

FUNCTION: ET_Reset

DESCRIPTION:
	This is a generic function which is called each time a new screen is
  displayed.  The function resets key controls, sets their active status
  to FALSE, clears the screen and draws the application title image 
  at the top of the screen.  This allows us to reduce the size of the app's
  code base.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

  bShowTitleBar [in] - A boolean value indicating if the application's title bar
    image should be drawn at the top of the screen.  Setting this value to FALSE
    skips drawind the image.  This gives us additional screen space for screens
    (like the Add/Edit screen which have alot of controls.

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

static void ET_Reset(CExpenseTrackerApp * pApp, boolean bShowTitleBar )
{
   // Reset Menu Controls
   IMENUCTL_Reset(pApp->m_pMenu);
   IMENUCTL_Reset( pApp->m_pList);
   IMENUCTL_Reset( pApp->m_pSK);
   
   // End Any Active Dialog
   ISHELL_EndDialog( pApp->a.m_pIShell);

   // Disable Other Controls
   IDATECTL_SetActive( pApp->m_pDate, FALSE );
   CAMOUNTCTL_SetActive( pApp->m_pAmount, FALSE );
   ITEXTCTL_SetActive( pApp->m_pText, FALSE );
   IMENUCTL_SetActive( pApp->m_pMenu, FALSE );

   // Release Static Control
   ReleaseObj((void**)&pApp->m_pIStatic);

   // Clear Screen
   IDISPLAY_ClearScreen(pApp->a.m_pIDisplay);

   // Draw Banner
   if( bShowTitleBar )
      IIMAGE_Draw(pApp->m_pTitleBarImg, 0, 0);
}

/*===========================================================================

FUNCTION: ET_Prompt

DESCRIPTION:
	This function displays a prompt on the screen consisting of a static
  control to display text and on or more buttons at the bottom of the 
  screen.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 

	pApp [in] -	The CExpenseTrackerApp

  szTitle [in] - Title string.

  wIDTitle [in] - Title string resource ID.

  szText [in] - Text string.

  wIDText [in] - Text string resource ID.

  pFileName [in] - If valid, text is streamed from a file.

  wButtons [in] - Array of button resource IDs.

  wIDDef [in] - Resource ID of default button.

  dwProps [in] - Static control properties.

DEPENDENCIES:
   None

RETURN VALUE:
   None

SIDE EFFECTS:
  Causes the phone display to be updated.
===========================================================================*/

static void ET_Prompt(CExpenseTrackerApp * pApp, const AECHAR* szTitle, uint16 wIDTitle, const AECHAR* szText, uint16 wIDText, const char* pFileName, uint16* wButtons, uint16 wDefID, uint32 dwProps)
{
	AEERect rc;
	AECHAR * szTitleBuf = NULL;
	AECHAR * szTextBuf = NULL;
  IFile * pIFile = NULL;
  IFileMgr* pIFileMgr = NULL;

  ET_Reset( pApp, TRUE );

   // Create Static control for prompt
	if (ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_STATIC, (void**)&pApp->m_pIStatic) != AEE_SUCCESS)
      return;

  if (dwProps)
      ISTATIC_SetProperties(pApp->m_pIStatic, dwProps);

	if (!szTitle)
		szTitleBuf = (AECHAR *)MALLOC(MAX_RES_STRING_BUF_SIZE);
	else
		szTitleBuf = (AECHAR *)szTitle;


   if (pFileName) 
   {
      // Create an instance of IFileMgr used to open the file.
      if ( ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_FILEMGR, (void**)(&pIFileMgr)) != SUCCESS )
        return;

      // Open the file.

      pIFile = IFILEMGR_OpenFile(pIFileMgr, pFileName, _OFM_READ);

      // Delete the file manager as we no longer need it.

      IFILEMGR_Release( pIFileMgr );

      // If the file could not open then return.

      if( !pIFile )
         return;
   }
	else if (!szText)
		szTextBuf = (AECHAR *)MALLOC(MAX_RES_STRING_BUF_SIZE);
	else
		szTextBuf = (AECHAR *)szText;


   if (wButtons)
   {
      AEERect rcm;

      while (*wButtons)
	   {
		   IMENUCTL_AddItem(pApp->m_pSK, EXPENSETRACKER_RES_FILE, *wButtons, *wButtons, NULL, 0);
         wButtons++;
	   }

      IMENUCTL_SetSel(pApp->m_pSK, wDefID);
	   IMENUCTL_SetActive(pApp->m_pSK, TRUE);

      IMENUCTL_GetRect(pApp->m_pSK, &rcm);

      SETAEERECT(&rc, 0, pApp->m_rScreenRect.y, pApp->m_rScreenRect.dx, rcm.y - pApp->m_rScreenRect.y);
   }
   else
      SETAEERECT(&rc, 0, pApp->m_rScreenRect.y, pApp->m_rScreenRect.dx, pApp->m_rScreenRect.dy);
	
   ISTATIC_SetRect(pApp->m_pIStatic, &rc);

   if (!szTitle)			
	    ISHELL_LoadResString(pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, wIDTitle, szTitleBuf, MAX_RES_STRING_BUF_SIZE);

   if (pIFile)
   {
	   ISTATIC_SetText(pApp->m_pIStatic, szTitleBuf, NULL, AEE_FONT_BOLD, AEE_FONT_NORMAL);
     ISTATIC_SetTextEx(pApp->m_pIStatic, NULL, (IAStream*)pIFile, FALSE);
     ReleaseObj((void**)&pIFile);
   }
   else if (!szText)
   {
		ISHELL_LoadResString(pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, wIDText, szTextBuf, MAX_RES_STRING_BUF_SIZE);
	  ISTATIC_SetText(pApp->m_pIStatic, szTitleBuf, szTextBuf, AEE_FONT_BOLD, AEE_FONT_NORMAL);
		FREEIF(szTextBuf);
   }
   else
	   ISTATIC_SetText(pApp->m_pIStatic, szTitleBuf, szTextBuf, AEE_FONT_BOLD, AEE_FONT_NORMAL);

	ISTATIC_SetActive(pApp->m_pIStatic, TRUE);
	ISTATIC_Redraw(pApp->m_pIStatic);

	if (!szTitle)
		FREEIF(szTitleBuf);

	IDISPLAY_Update(pApp->a.m_pIDisplay);
}
