/******************************************************************************
FILE:  ET_DBFunctions.c

SERVICES:  Implements backend of Expense Tracker that interacts with the expense
   tracker database.

GENERAL DESCRIPTION:

PUBLIC CLASSES AND STATIC FUNCTIONS:
	List the class(es) and static functions included in this file

INITIALIZATION & SEQUENCING REQUIREMENTS:

	See Exported Routines

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

static void    ET_ConvertSecondsToDateString( uint32 nSeconds, AECHAR* psDateString, uint16 nMaxBufferSize );
static boolean ET_ParseExpenseRecord( IDBRecord* pRecord, dword* pnDateTime, unsigned char* pcType, AECHAR* psDesc, dword* pnAmount );

//*****************************************************************************
// DATABASE FUNCTIONS
//*****************************************************************************

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

FUNCTION: ET_ParseExpenseRecord

DESCRIPTION:
  This function extracts each of the values from an expense record in the 
  database and returns the values.  If any of the output argument's pointer values
  is NULL, the datum for that argument is not returned.

PARAMETERS:
	pRecord [in] - Pointer to a valid database record.
  
  pnDateTime [out] - Pointer to a dword that will be assigned the number of 
    seconds since 00:00:00.  NULL value is ok.

  pcType [out] - Pointer to a char that will be assigned the transaction type
    of the expense record entry.  NULL value is ok.

  psDesc [out] - Pointer to a wide-string character buffer that will be assigned
    the description of the tracsaction.  NULL value is ok.

  pnAmount [out] - Pointer to a dword that will be assigned the amount of the
    transaction.  NULL value is ok.

DEPENDENCIES:
  Assumes pRecord argument is valid.

RETURN VALUE:
  None

SIDE EFFECTS:
  Resets the Record index.

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

static boolean ET_ParseExpenseRecord( IDBRecord* pRecord, dword* pnDateTime, unsigned char* pcType, AECHAR* psDesc, dword* pnAmount )
{
  uint16 nFieldLen;
  AEEDBFieldName rFieldName;
  AEEDBFieldType rFieldType;
  AECHAR* psStringPtr;

  IDBRECORD_Reset( pRecord );  // Set the record index to -1
  
  // Get the first field

  rFieldType = IDBRECORD_NextField( pRecord, &rFieldName, &nFieldLen );

  // Set the DateTime if pnDateTime is a valid pointer

  if( pnDateTime )
    IDBRECORD_GetFieldDWord( pRecord, pnDateTime );
  
  // Get next field

  rFieldType = IDBRECORD_NextField( pRecord, &rFieldName, &nFieldLen );

  // Set the description if psDesc is a valid pointer

  if( psDesc )
  {
    psStringPtr = IDBRECORD_GetFieldString( pRecord );
    WSTRCPY( psDesc, psStringPtr );

    // psStringPtr is not freed by us because the pointer is owned by the
    // IDBRecord (See API Reference for IDBRECORD_GetFieldString ).
  }

  // Get next field

  rFieldType = IDBRECORD_NextField( pRecord, &rFieldName, &nFieldLen );

  // Set the transaction type if pcType is a valid pointer

  if( pcType )
    *pcType = *IDBRECORD_GetField( pRecord, &rFieldName, &rFieldType, &nFieldLen );
  
  // Get next field

  rFieldType = IDBRECORD_NextField( pRecord, &rFieldName, &nFieldLen );

  // Set the amount if pnAmount is a valid pointer

  if( pnAmount )
    IDBRECORD_GetFieldDWord( pRecord, pnAmount );
  
  return TRUE;
}

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

FUNCTION: ET_InitExpenseFieldStruct

DESCRIPTION:
  This function fills in the values of a AEEDBField structure array.  Once
  filled in, the array can be used later to write an entry to the database.

PARAMETERS:
	pFieldArray [out] - Pointer to a valid database record.
  
  pnDateTime [in] - Pointer to a dword that contains the number of seconds
    since 00:00:00.

  pcType [in] - Pointer to a char that contains the trasaction type.

  psDesc [in] - Pointer to a wide-string character buffer that contains
    the description of the tracsaction.

  pnAmount [in] - Pointer to a dword that contains the amount of the
    transaction.

DEPENDENCIES:
  Assumes all pointer values in the arguments to be valid.

RETURN VALUE:
  None

SIDE EFFECTS:
  None

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

static void ET_InitExpenseFieldStruct( AEEDBField* pFieldArray, dword* pnDateTime, unsigned char* pcType, AECHAR* psDesc, dword* pnAmount )
{
  // Fill in the date/time field

  pFieldArray[ DB_RECORD_FIELD_DATETIME ].fType = AEEDB_FT_DWORD;
  pFieldArray[ DB_RECORD_FIELD_DATETIME ].fName = AEEDBFIELD_DATE_TIME;
  pFieldArray[ DB_RECORD_FIELD_DATETIME ].wDataLen = sizeof( *pnDateTime );
  pFieldArray[ DB_RECORD_FIELD_DATETIME ].pBuffer = pnDateTime;

  // Fill in the description field

  pFieldArray[ DB_RECORD_FIELD_DESC ].fType = AEEDB_FT_STRING;
  pFieldArray[ DB_RECORD_FIELD_DESC ].fName = AEEDBFIELD_TEXT;
  pFieldArray[ DB_RECORD_FIELD_DESC ].wDataLen = WSTRSIZE( psDesc );
  pFieldArray[ DB_RECORD_FIELD_DESC ].pBuffer = psDesc;

  // Fill in the transaction type field
  
  pFieldArray[ DB_RECORD_FIELD_TYPE ].fType = AEEDB_FT_BYTE;
  pFieldArray[ DB_RECORD_FIELD_TYPE ].fName = AEEDBFIELD_NONE;
  pFieldArray[ DB_RECORD_FIELD_TYPE ].wDataLen = sizeof( *pcType );
  pFieldArray[ DB_RECORD_FIELD_TYPE ].pBuffer = pcType;

  // Fill in the amount field

  pFieldArray[ DB_RECORD_FIELD_AMOUNT ].fType = AEEDB_FT_DWORD;
  pFieldArray[ DB_RECORD_FIELD_AMOUNT ].fName = AEEDBFIELD_NONE;
  pFieldArray[ DB_RECORD_FIELD_AMOUNT ].wDataLen = sizeof( *pnAmount );
  pFieldArray[ DB_RECORD_FIELD_AMOUNT ].pBuffer = pnAmount;
}

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

FUNCTION: ET_AddExpenseItem

DESCRIPTION:
  This function adds a single expense transaction to the database.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 
  
  nDateTime [in] - A dword that contains the number of seconds
    since 00:00:00.

  cType [in] - A char that contains the transaction type.

  psDesc [in] - Pointer to a wide-string character buffer that contains
    the description of the tracsaction.

  nAmount [in] - Pointer to a dword that contains the amount of the
    transaction.

DEPENDENCIES:
  Assumes database has been successfully opened or created.

RETURN VALUE:
  TRUE - If record successfully added to the database.
  FALSE - If record could not be added.

SIDE EFFECTS:
  None

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

boolean ET_AddExpenseItem( CExpenseTrackerApp* pApp, dword nDateTime, unsigned char cType, AECHAR* psDesc, dword nAmount )
{
  IDBRecord* pRecord;
  AEEDBField pFieldArray[ NUM_DB_RECORD_FIELDS ];
  
  // Fill-in the AEEDBField field array

  ET_InitExpenseFieldStruct( pFieldArray, &nDateTime, &cType, psDesc, &nAmount );

  // Create a new record based on the AEEDBField field array values

  pRecord = IDATABASE_CreateRecord( pApp->m_pDatabase, pFieldArray, NUM_DB_RECORD_FIELDS );

  // Return false if the record could not be created

  if( !pRecord )
    return FALSE;

  // Release the record

  IDBRECORD_Release( pRecord );

  return TRUE;
}

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

FUNCTION: ET_UpdateExpenseItem

DESCRIPTION:
  This function updates the data in a single existing expense transaction in
  the database.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 
  
  nRecordID [in] - ID of the database record to be updated.

  nDateTime [in] - A dword that contains the number of seconds
    since 00:00:00.

  cType [in] - A char that contains the transaction type.

  psDesc [in] - Pointer to a wide-string character buffer that contains
    the description of the tracsaction.

  nAmount [in] - Pointer to a dword that contains the amount of the
    transaction.

DEPENDENCIES:
  Assumes database has been successfully opened or created.
  Assumes nRecordID is valid.

RETURN VALUE:
  TRUE - If record successfully updated.
  FALSE - If record could not be updated.

SIDE EFFECTS:
  None

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

boolean ET_UpdateExpenseItem( CExpenseTrackerApp* pApp, uint16 nRecordID, dword nDateTime, unsigned char cType, AECHAR* psDesc, dword nAmount )
{
  IDBRecord* pRecord;
  AEEDBField pFieldArray[ NUM_DB_RECORD_FIELDS ];

  // Get the record using the ID

  if(( pRecord = IDATABASE_GetRecordByID( pApp->m_pDatabase, nRecordID )) == NULL)
    return FALSE;

  // Update the fields in the record's AEEDBField structure array

  ET_InitExpenseFieldStruct( pFieldArray, &nDateTime, &cType, psDesc, &nAmount );

  // Update the record

  IDBRECORD_Update( pRecord, (AEEDBField*) pFieldArray, NUM_DB_RECORD_FIELDS );

  // Release the record

  IDBRECORD_Release( pRecord );

  return TRUE;
}

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

FUNCTION: ET_DeleteExpenseItem

DESCRIPTION:
  This function deletes a database record based on the ID passed in the
  second argument.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 
  
  nRecordID [in] - ID of the database record to be deleted.

DEPENDENCIES:
  Assumes database has been successfully opened or created.
  Assumes nRecordID is valid.

RETURN VALUE:
  TRUE - If record successfully deleted.
  FALSE - If record could not be deleted.

SIDE EFFECTS:
  None

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

boolean ET_DeleteExpenseItem( CExpenseTrackerApp* pApp, uint16 nRecordID )
{
  IDBRecord* pRecord;

  // Get the record using the ID

  if(( pRecord = IDATABASE_GetRecordByID( pApp->m_pDatabase, nRecordID )) == NULL)
    return FALSE;
  
  // Remove the record

  if( IDBRECORD_Remove( pRecord ) != SUCCESS )
  {
    // The record could not be removed so release the record and return FALSE

    IDBRECORD_Release( pRecord );
    return FALSE;
  }

  // Record removed (and released) successfully

  return TRUE;
}

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

FUNCTION: ET_GetExpenseItem

DESCRIPTION:
  This function gets a single record based on it's ID and returns the individual
  record values.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 
  
  nRecordID [in] - ID of the database record to be accessed.

  nDateTime [out] - Pointer to a dword that is assigned the number of 
    seconds since 00:00:00.  NULL value is ok.

  psDesc [out] - Pointer to a wide-string character buffer that is assigned
    the description of the tracsaction.  NULL value is ok.

  cType [out] - Pointer to a char that is assigend the transaction type.
    NULL value is ok.

  nAmount [out] - Pointer to a dword that is assigned the amount of the
    transaction.  NULL value is ok.

DEPENDENCIES:
  Assumes database has been successfully opened or created.


RETURN VALUE:
  TRUE - If record successfully accessed.
  FALSE - If record could not be accessed.

SIDE EFFECTS:
  None

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

boolean ET_GetExpenseItem( CExpenseTrackerApp* pApp, uint16 nRecordID, dword* pnDateTime, AECHAR* psDesc, unsigned char* pcType, dword* pnAmount )
{
  IDBRecord* pRecord;
  
  // Get the record using the ID

  if(( pRecord = IDATABASE_GetRecordByID( pApp->m_pDatabase, nRecordID )) == NULL)
    return FALSE;

  // Extract each of the data values from the record and assogn to the output 
  // arguments

  ET_ParseExpenseRecord( pRecord, pnDateTime, pcType, psDesc, pnAmount );

  // Release the record

  IDBRECORD_Release( pRecord );

  return TRUE;
}

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

FUNCTION: ET_GetExpenseList

DESCRIPTION:
  This function searches the database for all entries which match the 
  transaction type, start and end date argument values and creates 
  a menu item entry in the pMenu argument containing the transaction
  type icon, formated amount string and date/time (in seconds) in the
  menu item's user data.

  The value of each menu item is added to generate the total amount 
  of all the transactions in the menu object.

  The ID of each menu item is set to the ID of the record in the database
  and is therefore guaranteed to be unique.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 
  
  pMenu [out] - Pointer to the IMenuCtl to which menu items are added.

  pnTotal [out] - Pointer to a four byte integer to which the total is written.

  nStartDate [in] - The earliest date, in seconds, of a listed transaction.

  nEndDate [in] - The latest date, in seconds, of a listed transaction.

  cType [in] - The type of transaction to be listed.

DEPENDENCIES:
  Assumes database has been successfully opened or created.
  Assumes the pMenu argument is a valid IMenuCtl pointer.
  Assumes the pnTotal arument is a valid pointer.

RETURN VALUE:
  TRUE - If record successfully accessed.
  FALSE - If record could not be accessed.

SIDE EFFECTS:
  None

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

boolean ET_GetExpenseList( CExpenseTrackerApp * pApp, IMenuCtl* pMenu, uint32* pnTotal, uint32 nStartDate, uint32 nEndDate, unsigned char cType )
{
   IDBRecord* pRecord;
   dword nDateTime;
   unsigned char pcTransType[1];
   dword nAmount;
   AECHAR psAmountTextBuf[ MAX_AMOUNT_DIGITS + 2 ];
   AECHAR psAlignedAmountBuf[ MAX_RES_STRING_BUF_SIZE ];
   uint16 nTransIcon = 0;
   uint16 nAmountWidth;
   AECHAR psSpaceChar[] = { ' ','\0' };
   uint16 nSpaceWidth;
   uint16 nNumSpaces;
   AEERect rRect;
   uint16 i;
   CtlAddItem ai;

   // Initialize
   ai.wText = 0;
   ai.pImage = NULL;
   ai.pszResImage = ai.pszResText = EXPENSETRACKER_RES_FILE;
   ai.wFont = AEE_FONT_NORMAL;
   ai.dwData = 0;

  // Reset the database's record index

  IDATABASE_Reset( pApp->m_pDatabase );

  // Clear any items from the IMenuCtl

  IMENUCTL_Reset( pMenu );

  // Initialize the total to zero

  *pnTotal = 0;

  // Get each record in the database, one at a time

  while( (pRecord = IDATABASE_GetNextRecord( pApp->m_pDatabase )) != NULL )
  {
    // Parse the date/time, transaction type and amount from the current record

    ET_ParseExpenseRecord( pRecord, &nDateTime, pcTransType, NULL, &nAmount );

    // Check if the record matches the input criteria.  If cType equals TRANS_ALL then
    // allow all transaction types.  Also check that the record's transaction date
    // falls between nStartDate and nEndDate.  If it matches all criteria then 
    // create a menu item for the transaction, otherwise, skip it.

    if( ( cType == pcTransType[0] || cType == IDLI_TRANS_TYPE_ALL ) &&
        ( nDateTime >= nStartDate && nDateTime <= nEndDate ) )
    {

      // The transaction matches all criteria so format the amount value into a string

      CAMOUNTCTL_ConvertValueToString( nAmount, psAmountTextBuf, ( MAX_AMOUNT_DIGITS + 2 ) * sizeof( AECHAR ) );

      // Right align the item by inserting spaces based on the pixel width of the string.

      nAmountWidth = IDISPLAY_MeasureText( pApp->a.m_pIDisplay, AEE_FONT_NORMAL, psAmountTextBuf );
      nSpaceWidth = IDISPLAY_MeasureText( pApp->a.m_pIDisplay, AEE_FONT_NORMAL, psSpaceChar ) + 1;
      IMENUCTL_GetRect( pMenu, &rRect );
      nNumSpaces = ( ( rRect.dx - ( nAmountWidth + 10 ) ) / nSpaceWidth ) - 2;

      for( i = 0; i < nNumSpaces && nNumSpaces > 0; i++ )
      {
        psAlignedAmountBuf[i] = ' ';
      }
      psAlignedAmountBuf[i] = '\0';
      WSTRCAT( psAlignedAmountBuf, psAmountTextBuf );
    
      // Determine the appropriate icon to use based on the transaction type.

      switch( pcTransType[0] )
      {
      case IDLI_TRANS_TYPE_CASH:
        nTransIcon = IDB_CASH;
        break;
      case IDLI_TRANS_TYPE_CHECK:
        nTransIcon = IDB_CHECK;
        break;
      case IDLI_TRANS_TYPE_CREDIT:
        nTransIcon = IDB_CREDIT;
        break;
      case IDLI_TRANS_TYPE_DEBIT:
        nTransIcon = IDB_DEBIT;
        break;
      }

		 // Create the menu entry.
      ai.pText = psAlignedAmountBuf;
      ai.wImage = nTransIcon;
      ai.wItemID = EXPENSE_LIST_ID + IDBRECORD_GetID(pRecord);
      IMENUCTL_AddItemEx(pApp->m_pMenu, &ai);

      // Add the entry amount to the total

      *pnTotal += nAmount;
    }
    // Release the current record

    IDBRECORD_Release( pRecord );
  }
  return TRUE;
}

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

FUNCTION: ET_EmptyExpenseDatabase

DESCRIPTION:
  This function removes all the record from the database.  The database remains
  open.

PARAMETERS:
	pApp [in] - Pointer to the CExpenseTrackerApp structure. This structure contains 
    information specific to this applet. 
  
DEPENDENCIES:
  Assumes database has been successfully opened or created.

RETURN VALUE:
  None

SIDE EFFECTS:
  None

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

void ET_EmptyExpenseDatabase( CExpenseTrackerApp* pApp )
{
  IDBRecord* pRecord;

  // Reset the database record index

  IDATABASE_Reset( pApp->m_pDatabase );

  // Get each record from the database and remove it

  while((pRecord = IDATABASE_GetNextRecord( pApp->m_pDatabase )) != NULL)
  {
    IDBRECORD_Remove( pRecord );
  }
}

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

FUNCTION: ET_GetReportList

DESCRIPTION:
  This function searches the application's root directory in the phones 
  file system for all files containing the file name extension defined
  in REPORT_FILE_EXTENSION.  For each matching file found, the file name
  is copied to a buffer, the file extension is removed and a menu item
  is created with the root file name.

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

  pMenu [out] - Pointer to a IMenuCtl in which a menu item will be created
    for each matching file name.
  
DEPENDENCIES:
  Assumes the pMenu argument is a pointer to a valid IMenuCtl.

RETURN VALUE:
  None

SIDE EFFECTS:
  None

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

extern void ET_GetReportList( CExpenseTrackerApp * pApp, IMenuCtl* pMenu )
{
  FileInfo* pFileInfo = NULL;
  IFileMgr* pFileMgr = NULL;
  char* pzFileName = NULL;
  AECHAR* psFileName = NULL;
  uint16 nMenuItemID = REPORT_LIST_ID;

  // Create the text buffers on the heap.

  pzFileName = (char*) MALLOC( MAX_FILE_NAME * sizeof( char ) );
  psFileName = (AECHAR*) MALLOC( MAX_FILE_NAME * sizeof( AECHAR ) );

  if( !pzFileName || !psFileName )
  {
    FREEIF( pzFileName );
    FREEIF( psFileName );
    return;
  }

  // Create an IFileMgr object.

  if ( ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_FILEMGR, (void**)(&pFileMgr)) != SUCCESS )
  {
    FREEIF( pzFileName );
    FREEIF( psFileName );
    return;
  }

  // Initialize the file manager's file index in the application's root directory

  IFILEMGR_EnumInit( pFileMgr, "", FALSE );

  // Remove all items from the menu object

  IMENUCTL_Reset( pMenu );

  // Get each file name in the aplication's root directory.

  pFileInfo = (FileInfo*) MALLOC( sizeof( FileInfo ) );
  
  if( pFileInfo )
  {
    while( IFILEMGR_EnumNext( pFileMgr, pFileInfo ) )
    {
      // If the file name ends with the REPORT_FILE_EXTENSION string then copy the file name
      // to a single-byte string buffer, strip off the extension, convert the string to
      // wide-string and create a menu item entry in the IMenuCtl containing the root
      // file name.

      if( STRENDS( REPORT_FILE_EXTENSION, pFileInfo->szName ) )
      {
        STRCPY( pzFileName, pFileInfo->szName );
        ( STRRCHR( pzFileName, '.' ) )[ 0 ] = '\0';
        STRTOWSTR( pzFileName, psFileName, MAX_FILE_NAME );
        WSTRUPPER( psFileName );
        IMENUCTL_AddItem( pMenu, EXPENSETRACKER_RES_FILE, 0, nMenuItemID++, psFileName, 0);
      }
    }
  }
  IFILEMGR_Release( pFileMgr );
  FREEIF( pFileInfo );
  FREEIF( pzFileName );
  FREEIF( psFileName );
}

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

FUNCTION: ET_SaveReport

DESCRIPTION:
  This function opens a text file, reads each record from the database, 
  converts the record data to a formatted string and writes the string
  to the text file.  The text file is closed upon completion.

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

DEPENDENCIES:
  Assumes database has been successfully opened or created.

RETURN VALUE:
  TRUE - If database saved successfully.
  FALSE - If save fails.

SIDE EFFECTS:
  None

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

boolean ET_SaveReport( CExpenseTrackerApp* pApp )
{
  IFileMgr* pFileMgr = NULL;
  IFile* pFile = NULL;
  IDBRecord* pRecord = NULL;
  uint32 nDateTime;
  unsigned char cType;
  uint32 nAmount;
  uint32 nStartDate = 0;
  uint32 nEndDate = 0;
  int i = 0;
  AECHAR* psDescTextBuf = NULL;
  char* pzFileNameBuf = NULL;
  AECHAR psTextBuf[ MAX_RES_STRING_BUF_SIZE ];

  AECHAR psDashString[] = { ' ','-',' ','\0' };
  AECHAR psDashChar[] = { '-','\0' };
  AECHAR psNewlineString[] = { '\n', '\0' };
  AECHAR psSeparatorString[] = { ',',' ','\0' };
  AECHAR* psMonetarySymbol = NULL;

  // Create the text buffers on the heap.

  psDescTextBuf = (AECHAR*) MALLOC( ( MAX_DESC_SIZE + 1 ) * sizeof( AECHAR ) );
  pzFileNameBuf = (char*) MALLOC( MAX_FILE_NAME * sizeof( char ) );

  if( !psDescTextBuf || !pzFileNameBuf )
  {
    FREEIF( psDescTextBuf );
    FREEIF( pzFileNameBuf );
    return FALSE;
  }

  // Set the database's record index to the first record

  IDATABASE_Reset( pApp->m_pDatabase );

  // Scan each record to find the earliest and latest dates contained in the database.
  // These dates will be used to create the file name.

  while((pRecord = IDATABASE_GetNextRecord( pApp->m_pDatabase )) != NULL )
  {
    // Get the Date/time (in seconds) of the current record

    ET_ParseExpenseRecord( pRecord, &nDateTime, NULL, NULL, NULL );

    // Set the earliest and latest dates as we go

    if( nStartDate == 0 || nStartDate > nDateTime )
      nStartDate = nDateTime;

    if( nEndDate < nDateTime )
      nEndDate = nDateTime;
    IDBRECORD_Release( pRecord );
  }

  ET_ConvertSecondsToDateString( nStartDate, psTextBuf, MAX_FILE_NAME );

  WSTRCAT( psTextBuf, psDashString );

  ET_ConvertSecondsToDateString( nEndDate, &( psTextBuf[ WSTRLEN( psTextBuf ) ] ), MAX_FILE_NAME * sizeof( AECHAR ) );

  // Append the ending date to the end of the file name.

  WSTRTOSTR( psTextBuf, pzFileNameBuf, MAX_FILE_NAME );

  // Tack on the file extension

  STRCAT( pzFileNameBuf, REPORT_FILE_EXTENSION );

  // Create an IFileMgr object.

  if ( ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_FILEMGR, (void**)(&pFileMgr)) != SUCCESS )
  {
    FREEIF( psDescTextBuf );
    FREEIF( pzFileNameBuf );
    return FALSE;
  }

  // Open the file for writing using the generated file name

  pFile = IFILEMGR_OpenFile( pFileMgr, pzFileNameBuf, _OFM_CREATE );

  IFILEMGR_Release( pFileMgr );

  if( !pFile )
  {
    FREEIF( psDescTextBuf );
    FREEIF( pzFileNameBuf );
    return FALSE;
  }

  // Load the monetary symbol (i.e. US=$, etc.)

  ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDS_MONETARY_SYMBOL, psTextBuf, MAX_RES_STRING_BUF_SIZE );
  psMonetarySymbol = WSTRDUP( psTextBuf );

  // Reset the database's record index to the first record

  IDATABASE_Reset( pApp->m_pDatabase );
  
  // Get each record, convert its elements to string values and write then to the
  // text file.

  while((pRecord = IDATABASE_GetNextRecord( pApp->m_pDatabase )) != NULL )
  {
    // Get the data values for the current record

    if( !ET_ParseExpenseRecord( pRecord, &nDateTime, &cType, psDescTextBuf, &nAmount ) )
    {
      IDBRECORD_Release( pRecord );
      break;
    }

    // Convert the transaction date and time to a string and write them to the text file

    ET_ConvertSecondsToDateString( nDateTime, psTextBuf, MAX_RES_STRING_BUF_SIZE );
    WSTRUPPER( psTextBuf );
    IFILE_Write( pFile, psTextBuf, WSTRSIZE( psTextBuf ) - sizeof( AECHAR ) );

    // Write a newline sequence to the text file

    IFILE_Write( pFile, &psNewlineString, WSTRSIZE( psNewlineString ) - sizeof( AECHAR ) );

    // Write the transaction description string to the text file
    // Ensure that the Description text is not empty
    if (psDescTextBuf && (WSTRSIZE( psDescTextBuf ) == 0))
        IFILE_Write( pFile, psDescTextBuf, 0 );
    else
        IFILE_Write( pFile, psDescTextBuf, WSTRSIZE( psDescTextBuf ) - sizeof( AECHAR ) );

    // Write a newline sequence to the text file

    IFILE_Write( pFile, &psNewlineString, WSTRSIZE( psNewlineString ) - sizeof( AECHAR ) );

    // Load the correct transaction string based on the transaction type of the current record

    switch( cType )
    {
    case IDLI_TRANS_TYPE_CASH:
      ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDS_CASH, psTextBuf, MAX_RES_STRING_BUF_SIZE );
      break;
    case IDLI_TRANS_TYPE_CHECK:
      ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDS_CHECK, psTextBuf, MAX_RES_STRING_BUF_SIZE );
      break;
    case IDLI_TRANS_TYPE_CREDIT:
      ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDS_CREDIT, psTextBuf, MAX_RES_STRING_BUF_SIZE );
      break;
    case IDLI_TRANS_TYPE_DEBIT:
      ISHELL_LoadResString( pApp->a.m_pIShell, EXPENSETRACKER_RES_FILE, IDS_DEBIT, psTextBuf, MAX_RES_STRING_BUF_SIZE );
      break;
    default:
      psTextBuf[0] = '\0';
      break;
    }

    // Write the transaction type string to the text file

    IFILE_Write( pFile, psTextBuf, WSTRSIZE( psTextBuf ) - sizeof( AECHAR ) );

    // Write a 'comma/space' character combination to the text file

    IFILE_Write( pFile, &psSeparatorString, WSTRSIZE( psSeparatorString ) - sizeof( AECHAR ) );

    // Write the monetary symbol to the text file

    IFILE_Write( pFile, psMonetarySymbol, WSTRLEN( psMonetarySymbol ) * sizeof( AECHAR ) );

    // Format the amount value to a decimal string

    CAMOUNTCTL_ConvertValueToString( nAmount, psTextBuf, AMOUNT_BUFFER_SIZE * sizeof( AECHAR ) );

    // Write the amount string to the text file

    IFILE_Write( pFile, psTextBuf, WSTRSIZE( psTextBuf ) - sizeof( AECHAR ) );

    // Write a newline sequence to the text file

    IFILE_Write( pFile, &psNewlineString, WSTRSIZE( psNewlineString ) - sizeof( AECHAR ) );

    // Write a series of dashes to the text file.  Use the IDISPLAY_MeasureText API to determine
    // the maximum number of dashes we can write based on the screen width of the phone.
    // Write each dash to the text file.
    for( i = pApp->m_rScreenRect.dx / IDISPLAY_MeasureText( pApp->a.m_pIDisplay, AEE_FONT_NORMAL, psDashChar ); i > 1; i-- )
    {
      IFILE_Write( pFile, psDashChar, WSTRSIZE( psDashChar ) - sizeof( AECHAR ) );
    }

    // Release the current record

    IDBRECORD_Release( pRecord );
  }
  // All records have been written so release the text file

  IFILE_Release( pFile );

  // Free the monetary symbol string we obtained at the start of the function

  FREEIF( psMonetarySymbol );
  FREEIF( psDescTextBuf );
  FREEIF( pzFileNameBuf );

  return TRUE;
}

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

FUNCTION: ET_ConvertSecondsToDateString

DESCRIPTION:
  This function calculates the date and time from the nSeconds argument and
  creates a formatted date/time string.

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

  nSeconds [in] - The number of seconds since 00:00:00.

  psDateString [out] - Pointer to the wide-string buffer to which the formatted 
    date string will be written.

  nMaxBufferSize [in] - The maximum length of the wide-string buffer pointed
    to by psDateTimeString.

DEPENDENCIES:
  None

RETURN VALUE:
  None

SIDE EFFECTS:
  None

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

static void ET_ConvertSecondsToDateString( uint32 nSeconds, AECHAR* psDateString, uint16 nMaxBufferSize )
{
  AEEApplet* pApp = (AEEApplet*) GETAPPINSTANCE();
  JulianType rJulianDate;
  AECHAR psFormatTextBuf[] = { '%','i',' ','%','s',' ','%','i','\0' };
  AECHAR psTextBuf[ MAX_RES_STRING_BUF_SIZE ];
  
  // Fill in the JulianType data structure based on the value of the nSeconds argument

  GETJULIANDATE( nSeconds, &rJulianDate );

  // Get the month string associated with the wMonth value in the rJulianDate structure

  ISHELL_LoadResString( pApp->m_pIShell, EXPENSETRACKER_RES_FILE, (int16) ( rJulianDate.wMonth + ( IDS_MONTH_JAN - 1 ) ), psTextBuf, MAX_RES_STRING_BUF_SIZE );

  // Generate the completed date string

  WSPRINTF( psDateString, nMaxBufferSize * sizeof( AECHAR ), psFormatTextBuf, rJulianDate.wDay, psTextBuf, rJulianDate.wYear );
}

