/*
================================ COPYRIGHT ================================
The contents of this file are subject to the VTech Informations Ltd. License
of VT-OS Ver. 1.1 operating system (the "License"); you may not use this 
file except in compliance with the License.  

Software distributed under the License is distributed on an "AS IS" basis, 
WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License 
for the specific language governing rights and limitations under the License.
  
The Original Code is VT-OS Ver. 1.1 Operating System, released 
on October 1st, 1999
	
The Initial Developer of the Original Code is VTech Informations Ltd.  All 
codes are Copyright (C) VTech Informations Ltd. 1999.  All Rights Reserved.
===========================================================================
*/

/*
===========================================================================
File        :   expmdb.c
Author(s)   :   Jason Ngan
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   application c file
Revision    :   1.1
Note        :   None
===========================================================================
*/


#include "stdafx.h"
#include "expdef.h"
#include "expense.h"
#include "atod.h"
#include "sysetup.h"

#define		EXPENSE_NUM_FIELD	3
#define		F_DATE				0
#define		F_TYPE				1
#define		F_AMT				2

//#define DEBUG

/*****************************************************************
********************** Global Variables **************************
*****************************************************************/
BYTE			ListHighlightStatus, SetRtcDate;
UBYTE			CatNum;
SHORT			HighlightRecNumInList;
USHORT			TotalRecordInCat;
UWORD			*RecInCat;
WORD			NewItemNum, RecIDInList[11];
RecordID		NewExpense_rec_id, Highlighted_rec_id, UnDelete_rec_id;
EXPENSE_DATE	GExpenseDate;

extern SHORT		CatHighlightInList;
extern BYTE			CatText[20];
extern USHORT		DelItemNum;
extern ObjectID		G_active_form_id;
extern BYTE			LargeFontInEdcat;

//t==============================================================
extern UWORD		G_del_expense_type;
extern UWORD		G_rename_expense_type;
//t==============================================================

/*****************************************************************
* Function:	ExpenseCatNameToNum
* Purpose: 	This function is used to convert a category name to the 
number of this name in category list
* Scope:		application
* Input:		in_cat_string		Input category name
* Output:		None
* Return:		The related category number
*				0					if the category is not found
* Comment: 	None
*****************************************************************/
UBYTE ExpenseCatSelectedNameToNum(BYTE *in_cat_string)
{
	UBYTE		cat[NUM_FLODERS], num_valid_cat;
	BYTE		cat_name[30];
	WORD		i;
	DatabaseID	Expense_dbid;
	
	DataFindDB(EXPDB, &Expense_dbid);
	
	num_valid_cat = DataCategorySort(Expense_dbid, cat);
	if (num_valid_cat > 0)
	{
		for(i=0; i<num_valid_cat; i++)
		{
			DataCategoryName(Expense_dbid, cat[i], cat_name);
			if (!strcmp(cat_name, in_cat_string))
			{
				CatNum = cat[i];
				return i;
			}
		}
	}
	
	// ====================================================================
	// add at 13062000
	strcpy(cat_name, EXPUNFILED);
	if (!strcmp(cat_name, in_cat_string))
	{
		CatNum = 0;
		return 1;
	}
	// ====================================================================
	return 0;
}


/*****************************************************************
* Function:	ExpenseCatSetScrollbar
* Purpose: 	This function is called in order to set the values for a scrollbar		
* Scope:		application
* Input:		new_cat_num			the last category number in the category list
* Output:		None
* Return:		TRUE				scrollbar is erased
*				FALSE				scrollbar is drawn
* Comment: 	If a scrollbar is not required, then the scrollbar will be erased 
If a scrollbar is required, the scrollbar will be displayed accordingly 
*****************************************************************/
BOOLEAN ExpenseCatSetScrollbar(SHORT new_cat_num)
{
	UBYTE		cat[NUM_FLODERS];
	SHORT		total_cat;
	WORD		max_value, min_value, scrollbar_pagesize;
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	total_cat = DataCategorySort(Expense_dbid, cat);
	
	if (LargeFontInEdcat)
		scrollbar_pagesize = 9;
	else
		scrollbar_pagesize = 11;
	
	min_value = 0;
	max_value = total_cat - scrollbar_pagesize;	
	
	if (total_cat > scrollbar_pagesize)
		ScrollbarSetScrollbarVisible(SCROLLBAR_EXPENSE_EDCAT, TRUE);
	else
	{
		ScrollbarSetScrollbarVisible(SCROLLBAR_EXPENSE_EDCAT, FALSE);
		ScrollbarEraseScrollbar(SCROLLBAR_EXPENSE_EDCAT);
		return FALSE;
	}
	
	if (total_cat < scrollbar_pagesize)
		ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_EDCAT, max_value, max_value, min_value, scrollbar_pagesize-1, total_cat);
	else
	{
		if (new_cat_num < scrollbar_pagesize)
			ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_EDCAT, 0, max_value, min_value, scrollbar_pagesize-1, total_cat);
		else
			ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_EDCAT, (WORD)(new_cat_num -scrollbar_pagesize+1), max_value, min_value, scrollbar_pagesize-1, total_cat);
	}
	
	ScrollbarSetScrollbarDrawPagesize(SCROLLBAR_EXPENSE_EDCAT, scrollbar_pagesize);
	return TRUE;
	
}

/*****************************************************************
* Function:	ExpenseCatToList
* Purpose: 	This function is used to show the correct category to 
*				the category page
* Scope:		application
* Input:		new_cat_string		Category name being edit
add_new_cat			Add new category flag
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseCatToList(BYTE *new_cat_string, BOOLEAN add_new_cat)
{
	BYTE			cat_name[30] = {0}, null_buf[1]={0}, list_highlight_text[20], *slist_highlight_text;
	UBYTE			cat[NUM_FLODERS];
	SHORT			num_valid_cat, new_cat_num=-1, list_highlight_num, old_cat_num = -1, temp = -1;
	WORD			i, j, k = 0, scrollbar_pagesize, temp_cat_num; 
	USHORT			rec_display = 0, rec_page_count = 0, num_items;
	static SHORT	CatHighlightNotInList = 0;
	DatabaseID		Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	ListGetNumOfItems(LIST_EXPENSE_EDCAT, &num_items);
	num_valid_cat = DataCategorySort(Expense_dbid, cat);
	
	if ((num_valid_cat == 0)&&(num_items == 0))
	{
		CatHighlightInList = -1;
		CatNum = 0;
		return TRUE;
	}
	
	if (LargeFontInEdcat)
		scrollbar_pagesize = 9;
	else
		scrollbar_pagesize = 11;
	
	ListGetSelectedItem(LIST_EXPENSE_EDCAT, &list_highlight_num);
	if (list_highlight_num < 0 || list_highlight_num > scrollbar_pagesize-1)
		strcpy(list_highlight_text, "");
	else
	{
		ListGetListItem(LIST_EXPENSE_EDCAT, (SHORT)list_highlight_num, &slist_highlight_text);
		strcpy(list_highlight_text, slist_highlight_text);
	}
	
	ControlPopupDeleteAllItems(POPUP_EXPENSE_LIST);
	strcpy(cat_name, EXPEFOLD);
	ControlPopupInsertItem(POPUP_EXPENSE_LIST, 0, cat_name);
	
	strcpy(cat_name, EXPUNFILED);
	ControlPopupInsertItem(POPUP_EXPENSE_LIST, 1, cat_name);
	ListDeleteAllItems(LIST_EXPENSE_EDCAT);
	
	for(i=0; i<num_valid_cat; i++)
	{
		DataCategoryName(Expense_dbid, cat[i], cat_name);
		ControlPopupInsertItem(POPUP_EXPENSE_LIST, i+2, cat_name);
		
		if (!strcmp(cat_name, new_cat_string))
		{
			new_cat_num = i;
		}
		
		if (!strcmp(cat_name, list_highlight_text))
		{
			old_cat_num = i;
		}
	}
	if (old_cat_num < 0)
		old_cat_num = CatHighlightNotInList;
	
	if (num_valid_cat < 1)
	{
		CatNum = 0;
		CatHighlightInList = -1;
		ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
	}
	else if (num_valid_cat < scrollbar_pagesize)
	{
		for(i=0; i<num_valid_cat; i++)
		{
			DataCategoryName(Expense_dbid, cat[i], cat_name);
			ListInsertItem(LIST_EXPENSE_EDCAT, i, cat_name);
		}
		if (add_new_cat)
		{
			CatHighlightInList = new_cat_num;
			ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
		}
		else
		{
			CatHighlightInList = old_cat_num;
			ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
		}
		CatNum = cat[CatHighlightInList];
	}
	else
	{
		if (new_cat_num < scrollbar_pagesize)
		{
			for(i=0; i<scrollbar_pagesize; i++)
			{
				DataCategoryName(Expense_dbid, cat[i], cat_name);
				ListInsertItem(LIST_EXPENSE_EDCAT, i, cat_name);
			}
			if (add_new_cat)
			{
				CatHighlightInList = new_cat_num;
				ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
			}
			else
			{
				if ((new_cat_num == old_cat_num) && (new_cat_num < scrollbar_pagesize))
				{
					CatHighlightInList = old_cat_num;
					ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
				}
				else
				{
					j = new_cat_num - old_cat_num;
					if (j < scrollbar_pagesize && j > -1)
					{
						CatHighlightInList = scrollbar_pagesize-1 - j;
						ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
					}
					else if( j < 0 && j < -scrollbar_pagesize)
					{
						CatHighlightNotInList = old_cat_num;
						CatHighlightInList = old_cat_num;
						
						ListSetHighlightedItem(LIST_EXPENSE_EDCAT, -1);
					}
					else
					{
						CatHighlightInList = old_cat_num;
						ListSetHighlightedItem(LIST_EXPENSE_EDCAT, CatHighlightInList);
					}
				}
			}
			CatNum = cat[CatHighlightInList];
		}
		else
		{
			j = new_cat_num + 1;
			for(i=new_cat_num-scrollbar_pagesize+1; i<j; i++)
			{
				DataCategoryName(Expense_dbid, cat[i], cat_name);
				ListInsertItem(LIST_EXPENSE_EDCAT, k++, cat_name);
			}
			if (add_new_cat)
			{
				CatHighlightInList = new_cat_num;
				ListSetHighlightedItem(LIST_EXPENSE_EDCAT, scrollbar_pagesize-1);
				CatNum = cat[10];
			}
			else
			{
				j = new_cat_num - old_cat_num;
				if (j < scrollbar_pagesize && j > -1)
				{
					ListSetHighlightedItem(LIST_EXPENSE_EDCAT, scrollbar_pagesize-1-j);
					CatNum = cat[scrollbar_pagesize-1 - j];
				}
				else
				{
					CatHighlightNotInList = old_cat_num;
					ListSetHighlightedItem(LIST_EXPENSE_EDCAT, -1);
					CatNum = cat[old_cat_num];
				}
			}
			
		}
		//ExpenseCatSetScrollbar(new_cat_num);
	}
	
	ExpenseCatSetScrollbar(new_cat_num);
	
	return TRUE;
}

/*****************************************************************
* Function:	ExpenseDatabaseClose
* Purpose: 	This function is used to close all opened 
*				record and database before leaving the application
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE if success
*				FALSE if the database not found
* Comment: 	This function should be called in the StopApplication
*****************************************************************/
BOOLEAN ExpenseDatabaseClose(void)
{
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	if (DataCloseDB(Expense_dbid) != TRUE)
		return FALSE;
	
	return TRUE;
}

/*****************************************************************
* Function:	ExpenseDatabaseInit
* Purpose: 	This function is used to simulate and initialse the 
*				the datebase in the PDA. Try to preset some records in 
*				the database
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE if success
*				FALSE if no memory
* Comment: 	This function should be called in the StartApplication() function.
*****************************************************************/
BOOLEAN ExpenseDatabaseInit(BOOLEAN is_restart)
{
	WORD			i = 0;
	UWORD			type_id;
	BYTE			textbox_string[15] = {0}, bchar_pos = 0;
	DatabaseID		Expense_dbid, Expense_type_dbid;
	RecordID		Expense_type_rec_id;
	BYTE			curr_to_cat;
	
	
	/* New Database */
	if (!DataFindDB(EXPDB, &Expense_dbid))
		if (DataNewDB(EXPDB, F_DATE, EXPAPP, &Expense_dbid) == ERR_DATA_NO_SPACE)
			return FALSE;
		if (DataOpenDB(Expense_dbid, F_DATE, OPEN_RW) != TRUE)
			return FALSE;
		
		//t==============================================================
		if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
			if (DataNewDB(EXPTYPEDB, F_DATE, EXPTYPEDB1, &Expense_type_dbid) == ERR_DATA_NO_SPACE)
				return FALSE;
			if (DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW) != TRUE)
				return FALSE;
			//t==============================================================
			
			if (is_restart)
			{
				if (DataNewRecordWithID(Expense_dbid, EXPENSE_MAIN_APP_SAVE, 0, 18) != TRUE)
					return FALSE;
				if (DataWriteField(Expense_dbid, EXPENSE_MAIN_APP_SAVE, F_ExpTextboxString, 16*sizeof(BYTE), (BYTE*)textbox_string) != TRUE)
					return FALSE;
				if (DataWriteField(Expense_dbid, EXPENSE_MAIN_APP_SAVE, F_ExpTextboxCharPos, sizeof(BYTE), (BYTE*)&bchar_pos) != TRUE)
					return FALSE;
				
				if (DataNewRecordWithID(Expense_dbid, EXPENSE_MDB_APP_SAVE, 0, 18) != TRUE)
					return FALSE;
			}
			return TRUE;
}


/*****************************************************************
* Function:	ExpenseInitMDBGlobal
* Purpose: 	This function is used to initialize the global variables
* Scope:		application/internal
* Input:		None
* Output:		None
* Return:		None
* Comment: 	None
******************************************************************/
void ExpenseInitMDBGlobal(BOOLEAN is_restart)
{
	BYTE	*buffer;
	UWORD	byte_read;
	DatabaseID	Expense_dbid;
	
	RecInCat = (UWORD*)qmalloc(sizeof(UWORD));
	SetRtcDate = 1;
	if (is_restart)
	{
		TotalRecordInCat = 0;
		ListHighlightStatus = EXPENSE_NO_HIGHLIGHT;
		NewItemNum = 10;
		CatHighlightInList = -1;
		RecIDInList[0] = -1;
		RecIDInList[1] = -1;
		RecIDInList[2] = -1;
		RecIDInList[3] = -1;
		RecIDInList[4] = -1;
		RecIDInList[5] = -1;
		RecIDInList[6] = -1;
		RecIDInList[7] = -1;
		RecIDInList[8] = -1;
		RecIDInList[9] = -1;
		RecIDInList[10] = -1;
		NewExpense_rec_id = 0x80001000;
		Highlighted_rec_id = 0x80001100;
		UnDelete_rec_id = 0x80001200;
		HighlightRecNumInList = EXPENSE_INVALID_REC_NUM;
	}
	else
	{
		DataFindDB(EXPDB, &Expense_dbid);
		
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_ListHighlightStatus, &buffer, &byte_read);
		ListHighlightStatus = *(BYTE*)buffer;
		qfree(buffer);
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_CatNum, &buffer, &byte_read);
		CatNum = *(UBYTE*)buffer;
		qfree(buffer);
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_HighlightRecNumInList, &buffer, &byte_read);
		HighlightRecNumInList = *(SHORT*)buffer;
		
		qfree(buffer);
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_TotalRecordInCat, &buffer, &byte_read);
		TotalRecordInCat = *(USHORT*)buffer;
		qfree(buffer);
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_NewItemNum, &buffer, &byte_read);
		NewItemNum = *(WORD*)buffer;
		qfree(buffer);
		
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_RecIDInList_0, &buffer, &byte_read);
		RecIDInList[0] = *((WORD*)buffer);
		RecIDInList[1] = *((WORD*)buffer+1);
		RecIDInList[2] = *((WORD*)buffer+2);
		RecIDInList[3] = *((WORD*)buffer+3);
		RecIDInList[4] = *((WORD*)buffer+4);
		RecIDInList[5] = *((WORD*)buffer+5);
		RecIDInList[6] = *((WORD*)buffer+6);
		RecIDInList[7] = *((WORD*)buffer+7);
		RecIDInList[8] = *((WORD*)buffer+8);
		RecIDInList[9] = *((WORD*)buffer+9);
		RecIDInList[10] = *((WORD*)buffer+10);
		qfree(buffer);
		
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_NewExpense_rec_id, &buffer, &byte_read);
		NewExpense_rec_id = *(RecordID*)buffer;
		qfree(buffer);
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_Highlighted_rec_id, &buffer, &byte_read);
		Highlighted_rec_id = *(RecordID*)buffer;
		qfree(buffer);
		DataGetField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_UnDelete_rec_id, &buffer, &byte_read);
		UnDelete_rec_id = *(RecordID*)buffer;
		qfree(buffer);
		
	}
	
	return;
}

/*****************************************************************
* Function:	ExpenseMDBAppSave
* Purpose: 	This function is called to save the data in 
the expense database when it is called to stopped
* Scope:		application/internal
* Input:		None
* Output:		None
* Return:		None
* Comment: 	None
******************************************************************/
BOOLEAN ExpenseMDBAppSave(void)
{
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_ListHighlightStatus, sizeof(BYTE), (BYTE*)&ListHighlightStatus) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_CatNum, sizeof(UBYTE), (BYTE*)&CatNum) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_HighlightRecNumInList, sizeof(SHORT), (BYTE*)&HighlightRecNumInList) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_TotalRecordInCat, sizeof(USHORT), (BYTE*)&TotalRecordInCat) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_NewItemNum, sizeof(WORD), (BYTE*)&NewItemNum) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_RecIDInList_0, 11*sizeof(WORD), (BYTE*)&RecIDInList) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_NewExpense_rec_id, sizeof(RecordID), (BYTE*)&NewExpense_rec_id) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_Highlighted_rec_id, sizeof(RecordID), (BYTE*)&Highlighted_rec_id) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, EXPENSE_MDB_APP_SAVE, F_UnDelete_rec_id, sizeof(RecordID), (BYTE*)&UnDelete_rec_id) != TRUE)
		return FALSE;
	qfree(RecInCat);
	
	return TRUE;
}

/*****************************************************************
* Function:	ExpenseLoadRecord
* Purpose: 	This function is used to load the specific records 
*				according to the input category name
* Scope:		application
* Input:		incat_name			Input category name
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseLoadRecord(BYTE *incat_name, BOOLEAN reset_undelete)
{
	BYTE		rec2cat_name[30], sbuf[20], *buffer;
	UBYTE		rec2cat_num;
	UWORD		total_num_rec, i, byte_read;
	double		total_amt = 0.0;
	RecordID	Expense_rec_id;
	DatabaseID	Expense_dbid;
	
	Err			Error;
	UWORD		UnDelete_rec_num;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	if (reset_undelete)
	{
		DataRecIDtoNum(Expense_dbid, UnDelete_rec_id, &UnDelete_rec_num);
		if (DataOpenRecord(Expense_dbid, UnDelete_rec_num, &Expense_rec_id, NULL) == TRUE)
		{
			DataCloseRecord(Expense_dbid, Expense_rec_id);
			DataDeleteRecord(Expense_dbid, Expense_rec_id, FALSE);
		}
		UnDelete_rec_id = 0x80001200;
	}
	
	TotalRecordInCat = 0;
	DataTotalRecord(Expense_dbid, &total_num_rec);
	qfree(RecInCat);
	RecInCat = (UWORD*) qmalloc((total_num_rec+1)*sizeof(UWORD));
	
	ExpenseCatSelectedNameToNum(incat_name);
	
	
	
	for (i=0; i<total_num_rec; i++)
	{
		/* Format and print various data: */
		if (DataOpenRecord(Expense_dbid, i, &Expense_rec_id, NULL) != TRUE)
			return FALSE;
		
		if (UnDelete_rec_id != Expense_rec_id)
		{
			DataRecordInfo(Expense_dbid, Expense_rec_id, NULL, &rec2cat_num, NULL, NULL, NULL);
			DataCategoryName(Expense_dbid, rec2cat_num, rec2cat_name);
			if (strcmp(rec2cat_name, incat_name) == 0)
			{
				RecInCat[TotalRecordInCat] = Expense_rec_id;
				
				if (DataGetField(Expense_dbid, Expense_rec_id, F_AMT, &buffer, &byte_read) != TRUE)
					return FALSE;
				if (Expense_rec_id == NewExpense_rec_id)
					if (TotalRecordInCat < 11)
						NewItemNum = 10;
					else
						NewItemNum = TotalRecordInCat;
					
					total_amt += (*(double*)buffer);
					TotalRecordInCat++;
					qfree(buffer);
			}
		}
		if (DataCloseRecord(Expense_dbid, Expense_rec_id) != TRUE)
			return FALSE;
	}
	
	if (TotalRecordInCat < 12)
		NewItemNum = 10;
	
	RecInCat[TotalRecordInCat] = 65534;
	
	if (TotalRecordInCat > 0)
	{
		dtoa(total_amt, (char*)sbuf, 2);
		StringSetText(STRING_EXPENSE_LIST_TOTAL_AMT, sbuf);
	}
	
	return TRUE;
}


/*****************************************************************
* Function:	ExpenseRecordToList
* Purpose: 	This function is used to show the correct records to 
*				the list objects in the expense list page
* Scope:		application
* Input:		None
* Output:		new_item_num		The last item number in the list
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseRecordToList(USHORT *new_item_num)
{
	BYTE			*buffer, sbuffer[16], sbuf[25], null_buf[1]={0}, curr[4];
	USHORT			k, rec_display = 0, rec_page_count = 0;
	UWORD			i, j, byte_read, rec_num;
	BOOLEAN			update = FALSE;
	ObjectID		textbox_id = TEXTBOX_EXPENSE_LIST_AMT1;
	EXPENSE_DATE	*date_buf;
	double			amount = 0.0;
	RecordID		dummy_rec_id, type_rec_id;
	DatabaseID		Expense_dbid, Expense_type_dbid;
	CountrySettings country;
	
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	if (DataGetField(Expense_dbid, EXPENSE_CURR_REC_ID, CatNum, &buffer, &byte_read) != TRUE)
		return FALSE;
	
	switch(*buffer)
	{
	case AUSTRALIA_CURR:
		strcpy(curr, CUR1);
		break;
	case AUSTRIA_CURR:
		strcpy(curr, CUR2);
		break;
	case BELGIUM_CURR:
		strcpy(curr, CUR3);
		break;
	case BRAZIL_CURR:
		strcpy(curr, CUR4);
		break;
	case CANADA_CURR:
		strcpy(curr, CUR5);
		break;
	case DENMARK_CURR:
		strcpy(curr, CUR6);
		break;
	case EURO_CURR:
		strcpy(curr, CUR7);
		break;
	case FINLAND_CURR:
		strcpy(curr, CUR8);
		break;
	case FRANCE_CURR:
		strcpy(curr, CUR9);
		break;
	case GERMANY_CURR:
		strcpy(curr, CUR10);
		break;
	case HONG_KONG_CURR:
		strcpy(curr, CUR11);
		break;
	case ICELAND_CURR:
		strcpy(curr, CUR12);
		break;
	case IRELAND_CURR:
		strcpy(curr, CUR13);
		break;
	case ITALY_CURR:
		strcpy(curr, CUR14);
		break;
	case JAPAN_CURR:
		strcpy(curr, CUR15);
		break;
	case LUXEMBOURG_CURR:
		strcpy(curr, CUR16);
		break;
	case MEXICO_CURR:
		strcpy(curr, CUR17);
		break;
	case NETHERLANDS_CURR:
		strcpy(curr, CUR18);
		break;
	case NEW_ZEALAND_CURR:
		strcpy(curr, CUR19);
		break;
	case NORWAY_CURR:
		strcpy(curr, CUR20);
		break;
		
	case SPAIN_CURR:
		strcpy(curr, CUR21);
		break;
	case SWEDEN_CURR:
		strcpy(curr, CUR22);
		break;
	case SWITZERLAND_CURR:
		strcpy(curr, CUR23);
		break;
	case UNITED_KINGDOM_CURR:
		strcpy(curr, CUR24);
		break;
	case UNITED_STATES_CURR:
		strcpy(curr, CUR25);
		break;
	default:
		strcpy(curr, "  $");
		break;
	}
	
	
	ListDeleteAllItems(LIST_EXPENSE_LIST_DATE);
	ListDeleteAllItems(LIST_EXPENSE_LIST_TYPE);
	ListDeleteAllItems(LIST_EXPENSE_LIST_CURR);
	
	if (HighlightRecNumInList > -1 && HighlightRecNumInList <11)
		Highlighted_rec_id = RecIDInList[HighlightRecNumInList];
	
	for(i=0; i<11; i++)
		RecIDInList[i] = -1;
	
	k = 0;
	if (NewItemNum < 11)
	{
		if (TotalRecordInCat < 11)
		{
			j = TotalRecordInCat;
			for(i=0; i<j; i++)
				RecIDInList[i] = RecInCat[i];
		}
		else
			for(i=0; i<11; i++)
				RecIDInList[i] = RecInCat[i];
	}
	else
	{
		j = NewItemNum + 1;
		for(i=NewItemNum-10; i<j; i++)
		{
			if (i >= TotalRecordInCat)
				break;
			else
			{
				RecIDInList[k] = RecInCat[i];
				k++;
			}
		}
	}
	
	i = 0;
	
	if (!SySetupGetCountrySettings(&country))
		return FALSE;
	
	while(i < 11)
	{
		
		if (RecIDInList[i] > -1)
		{
			if (DataRecIDtoNum(Expense_dbid, RecIDInList[i], &rec_num) != TRUE)
				return FALSE;
			if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
				return FALSE;
			if (DataGetField(Expense_dbid, RecIDInList[i], F_DATE, (BYTE**)&date_buf, &byte_read) != TRUE)
				return FALSE;
			
			
			if (country.date_fmt == SYSETUP_DMY)
			{
				if (date_buf->day < 10)
					j  = sprintf((char*)sbuffer, "0%d/", date_buf->day);
				else
					j  = sprintf((char*)sbuffer, "%d/", date_buf->day);
				j += sprintf((char*)sbuffer + j, "%d", date_buf->mon);
			}
			else
			{
				j  = sprintf((char*)sbuffer, "%d/", date_buf->mon);
				if (date_buf->day < 10)
					j += sprintf((char*)sbuffer + j, "0%d", date_buf->day);
				else
					j += sprintf((char*)sbuffer + j, "%d", date_buf->day);
			}
			ListInsertItem(LIST_EXPENSE_LIST_DATE, rec_display, sbuffer);
			qfree(date_buf);
			
			if (DataGetField(Expense_dbid, RecIDInList[i], F_TYPE, &buffer, &byte_read) != TRUE)
				return FALSE;
			
			if (*((UWORD*)buffer) == USER_DEFINE)
			{
				strcpy(sbuffer, EXPUDEFINE);
			}
			else if(*((UWORD*)buffer) == OTHER)
			{
				strcpy(sbuffer, EXPOTHER);
			}
			else
			{
				if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
					return FALSE;
				if (!DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW))
					return FALSE;
				
				DataRecIDtoNum(Expense_type_dbid, *((UWORD*)buffer), &rec_num);
				DataOpenRecord(Expense_type_dbid, rec_num, &type_rec_id, NULL);
				
				qfree(buffer);
				DataGetField(Expense_type_dbid, type_rec_id, 0, &buffer, &byte_read);
				strcpy(sbuffer, buffer);
				DataCloseRecord(Expense_type_dbid, type_rec_id);
				DataCloseDB(Expense_type_dbid);
				
			}
			ListInsertItem(LIST_EXPENSE_LIST_TYPE, rec_display, sbuffer);
			qfree(buffer);
			
			ListInsertItem(LIST_EXPENSE_LIST_CURR, rec_display, curr);
			
			if (DataGetField(Expense_dbid, RecIDInList[i], F_AMT, &buffer, &byte_read) != TRUE)
				return FALSE;
			
			dtoa((*(double*)buffer), (char*)sbuf, 2);
			
			if (RecIDInList[i] == (WORD)NewExpense_rec_id)
			{
				if ((*(double*)buffer) > 0.009)
				{
					TextboxSetInsertPointOn(textbox_id);
					TextboxSetText(textbox_id, sbuf);
					TextboxSetInsertPointOff(textbox_id);
				}
				else
				{
					TextboxSetInsertPointOn(textbox_id);
					TextboxSetText(textbox_id, null_buf);
					TextboxSetInsertPointPositionByCharPos(textbox_id, 0);
				}
				*new_item_num = rec_display;
			}
			else
			{
				TextboxSetInsertPointOn(textbox_id);
				TextboxSetText(textbox_id, sbuf);
				TextboxSetInsertPointOff(textbox_id);
			}
			textbox_id++;
			rec_display++;
			
			if (RecIDInList[i] == (WORD)Highlighted_rec_id)
				switch(ListHighlightStatus)
			{
					case EXPENSE_DATE_HIGHLIGHT:
						ListSetHighlightedItem(LIST_EXPENSE_LIST_DATE, (SHORT)i);
						HighlightRecNumInList = (SHORT)i;
						//						NewExpense_rec_id = RecIDInList[HighlightRecNumInList];
						DelItemNum = i;
						break;
						
					case EXPENSE_TYPE_HIGHLIGHT:
						ListSetHighlightedItem(LIST_EXPENSE_LIST_TYPE, (SHORT)i);
						break;
						
					case EXPENSE_CURR_HIGHLIGHT:
						if (!ExpenseIsKeypadVisible())
							ListSetHighlightedItem(LIST_EXPENSE_LIST_CURR, (SHORT)i);
						break;
						
					case EXPENSE_AMT_HIGHLIGHT:
						ListSetHighlightedItem(LIST_EXPENSE_LIST_DATE, (SHORT)i);
						break;
						
					default:
						break;
			}
			
			
			qfree(buffer);
			if (DataCloseRecord(Expense_dbid, RecIDInList[i]) != TRUE)
				return FALSE;
		}
		else
			ListInsertItem(LIST_EXPENSE_LIST_CURR, rec_display, null_buf);
		
		i++;
		update = TRUE;
	}
	
	
	if (rec_display == 0)
	{
		StringSetText(STRING_EXPENSE_LIST_TOTAL, null_buf);
		StringSetText(STRING_EXPENSE_LIST_TOTAL_AMT, null_buf);
	}
	else
	{
		ListInsertItem(LIST_EXPENSE_LIST_CURR, 11, curr);
		
		strcpy(sbuffer, EXPTOTAL);
		StringSetText(STRING_EXPENSE_LIST_TOTAL, sbuffer);
	}
	
	while(rec_display < 11)
	{
		TextboxSetInsertPointOn(textbox_id);
		TextboxSetText(textbox_id, null_buf);
		TextboxSetInsertPointOff(textbox_id);
		textbox_id++;
		rec_display++;
	}
	
	if (update == TRUE)
		ExpenseListSetScrollbar();
	
	
	return TRUE;
}



/*****************************************************************
* Function:	ExpenseNewExpense
* Purpose: 	This function is used to create a new expense record and
*				save into the database
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseNewExpense(void)
{
	RTM				date_source;
	double			amount;
	EXPENSE_DATE	date;
	DatabaseID		Expense_dbid;
	UWORD			type;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	if (DataNewRecord(Expense_dbid, CatNum, EXPENSE_NUM_FIELD, &NewExpense_rec_id) != TRUE)
		return FALSE;
	
	
	RtcGetTime(&date_source);
	if (SetRtcDate)
	{	
		date.year= (BYTE)(date_source.year - SYSETUP_YEAR_OFFSET);
		date.mon = (BYTE)date_source.mon+1;
		date.day = (BYTE)date_source.mday;
	}
	else
	{
		date.year= GExpenseDate.year;
		date.mon = GExpenseDate.mon;
		date.day = GExpenseDate.day;
	}
	date.hr  = (BYTE)date_source.hour;
	date.min = (BYTE)date_source.min;
	date.sec = (BYTE)date_source.sec;
	
	
	if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_DATE, sizeof(EXPENSE_DATE), (BYTE*)&date) != TRUE)
		return FALSE;
	
	type = (BYTE)EXPENSE_TYPE;
	if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_TYPE, sizeof(BYTE), (BYTE*)&type) != TRUE)
		return FALSE;
	
	type = (UWORD)OTHER;
	if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_TYPE, sizeof(UWORD), (BYTE*)&type) != TRUE)
		return FALSE;
	
	amount = 0.0;
	if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_AMT, sizeof(double), (BYTE*)&amount) != TRUE)
		return FALSE;
	
	if (DataCloseRecord(Expense_dbid, NewExpense_rec_id) != TRUE)
		return FALSE;
	
	return TRUE;
}

/*****************************************************************
* Function:	ExpenseDeleteExpense
* Purpose: 	This function is used to delete a expense record from
*				the database
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseDeleteExpense(USHORT item_num)
{
	DatabaseID		Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	if (UnDelete_rec_id != 0x80001200)
	{
		DataDeleteRecord(Expense_dbid, UnDelete_rec_id, FALSE);
		TotalRecordInCat--;
	}
	
	
	UnDelete_rec_id = RecInCat[NewItemNum + item_num - 10];
	
	if (NewItemNum  == 10)
		NewItemNum = 10;
	else
		NewItemNum--;
	
	return TRUE;
	
}

/*****************************************************************
* Function:	ExpenseDeleteAllExpense
* Purpose: 	This function is used to delete all expenses from
*				the database
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseDeleteAllExpense(void)
{
	DatabaseID		Expense_dbid;
	WORD			i;
	BYTE			curr;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	for(i=0; i<TotalRecordInCat; i++)
	{
		
        if (DataDeleteRecord(Expense_dbid, RecInCat[i], FALSE) != TRUE)
            return FALSE;
	}
	
	if (UnDelete_rec_id != 0x80001200)
	{
		if (DataDeleteRecord(Expense_dbid, UnDelete_rec_id, FALSE) != TRUE)
			return FALSE;
		UnDelete_rec_id = 0x80001200;
	}
	
	curr = (BYTE)NONE_CURR;
	if (DataWriteField(Expense_dbid, EXPENSE_CURR_REC_ID, CatNum, sizeof(BYTE), (BYTE*)&curr) != TRUE)
		return FALSE;
	
	TotalRecordInCat = 0;
	NewItemNum = 10;
	
	return TRUE;
	
}


/*****************************************************************
* Function:	ExpenseSetDate
* Purpose: 	This function is used to set date settings into the
*				expense record
* Scope:		application
* Input:		date				input date settings in expense format
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseSetDate(EXPENSE_DATE date)
{
	UWORD			rec_num;
	RecordID		dummy_rec_id;
	DatabaseID		Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	if (DataRecIDtoNum(Expense_dbid, NewExpense_rec_id, &rec_num) != TRUE)
		return FALSE;
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return FALSE;
	if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_DATE, sizeof(EXPENSE_DATE), (BYTE*)&date) != TRUE)
		return FALSE;
	if (DataCloseRecord(Expense_dbid, NewExpense_rec_id) != TRUE)
		return FALSE;
	
	ExpenseStoreDate(date);
	
	return TRUE;
}



/*****************************************************************
* Function:	ExpenseStoreDate
* Purpose: 	This function is used to store date settings into the
*				expense db
* Scope:		application
* Input:		date				input date settings in expense format
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
void ExpenseStoreDate(EXPENSE_DATE date)
{
	SetRtcDate = 0;
	
	GExpenseDate = date;
	
	return;
}


/*****************************************************************
* Function:	ExpenseNumStyleConvert
* Purpose: 	This function is used to set the number stylus according
to system setup
* Scope:		application
* Input:		sbuf				The input string (number)
* Output:		sbuf				String with style added
* Return:		buffer				Expense type
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseNumStyleConvert(BYTE *sbuf)
{
	BYTE			num_2, num_3, *outbuf;
	USHORT			len_sbuf;
	WORD			i, j;
	CountrySettings country;
	
	if (sbuf[0] == 0)
		return FALSE;
	
	if (!SySetupGetCountrySettings(&country))
		return FALSE;
	
	len_sbuf = strlen(sbuf);
	outbuf = (BYTE*)qmalloc((len_sbuf + len_sbuf/3)*sizeof(BYTE));
	
	switch(country.nums)
	{
	case SYSETUP_NUMS_F_C:
		num_3 = '.';
		num_2 = ',';
		break;
	case SYSETUP_NUMS_S_C:
		num_3 = ' ';
		num_2 = ',';
		break;
	case SYSETUP_NUMS_S_F:
		num_3 = ' ';
		num_2 = '.';
		break;
	case SYSETUP_NUMS_N_C:
		num_3 = 0;
		num_2 = ',';
		break;
	case SYSETUP_NUMS_N_F:
		num_3 = 0;
		num_2 = '.';
		break;
		//		case SYSETUP_NUMS_C_F:
	default:
		num_3 = ',';
		num_2 = '.';
		break;
	}
	
	outbuf[0] = sbuf[len_sbuf-1];
	outbuf[1] = sbuf[len_sbuf-2];
	outbuf[2] = num_2;
	outbuf[3] = sbuf[len_sbuf-4];
	
	i = 4;
	if (len_sbuf > 5)
	{
		j = 5;
		while(sbuf[len_sbuf-j] != 0)
		{
			if (i%3 == 0)
			{
				if (num_3 != 0)
					outbuf[i] = num_3;
			}
			else
			{
				outbuf[i] = sbuf[len_sbuf-j];
				j++;
			}
			i++;
		}
	}	
	
	len_sbuf = 0;
	for(j = i-1; j>-1; j--)
	{
		sbuf[len_sbuf] = outbuf[j];
		len_sbuf++;
	}
	sbuf[len_sbuf] = 0;
	qfree(outbuf);
	
	return TRUE;
}


/*****************************************************************
* Function:	ExpenseGetNewExpenseType
* Purpose: 	This function is used to get type settings of a new expense
in the expense record
* Scope:		application
* Input:		None
* Output:		None
* Return:		buffer				Expense type
* Comment: 	None
*****************************************************************/
UWORD ExpenseGetNewExpenseType(void)
{
	BYTE		*buffer;
	UWORD		type;
	UWORD		byte_read, rec_num;
	RecordID	dummy_rec_id;
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return -1;
	if (DataRecIDtoNum(Expense_dbid, NewExpense_rec_id, &rec_num) != TRUE)
		return -1;
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return -1;
	if (DataGetField(Expense_dbid, NewExpense_rec_id, F_TYPE, &buffer, &byte_read) != TRUE)
		return -1;
	if (DataCloseRecord(Expense_dbid, NewExpense_rec_id) != TRUE)
		return -1;
	type = *((UWORD*)buffer);
	qfree(buffer);
	
	return type;
}



/*****************************************************************
* Function:	ExpenseSetType
* Purpose: 	This function is used to set type settings into the
*				expense record
* Scope:		application
* Input:		type				The input type
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
//t==================================================================
BOOLEAN ExpenseSetType(UBYTE type)
{
	UWORD		rec_num;
	RecordID	dummy_rec_id, type_rec_id;
	DatabaseID	Expense_dbid, Expense_type_dbid;
	
	if ((type != USER_DEFINE) && (type != OTHER))
	{
		if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
			return FALSE;
		if (!DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW))
			return FALSE;
		
		DataOpenRecord(Expense_type_dbid, (UWORD)(type), &type_rec_id, NULL);
		
		if (DataCloseRecord(Expense_type_dbid, type_rec_id) != TRUE)
			return FALSE;
	}
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	if (DataRecIDtoNum(Expense_dbid, NewExpense_rec_id, &rec_num) != TRUE)
		return FALSE;
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return FALSE;
	
	if ((type != USER_DEFINE) && (type  != OTHER))
	{
		if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_TYPE, sizeof(UWORD), (BYTE*)&type_rec_id) != TRUE)
			return FALSE;
	}
	else
	{
		type_rec_id = (UWORD)type;
		if (DataWriteField(Expense_dbid, NewExpense_rec_id, F_TYPE, sizeof(UWORD), (BYTE*)&type_rec_id) != TRUE)
			return FALSE;
	}
	if (DataCloseRecord(Expense_dbid, NewExpense_rec_id) != TRUE)
		return FALSE;
	
	return TRUE;
}

/*****************************************************************
* Function:	ExpenseSetCurr
* Purpose: 	This function is used to set curriences settings into the
*				expense record
* Scope:		application
* Input:		curr				The currency of the active list page
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseSetCurr(BYTE curr)
{
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	
	if (DataWriteField(Expense_dbid, EXPENSE_CURR_REC_ID, CatNum, sizeof(BYTE), (BYTE*)&curr) != TRUE)
		return FALSE;
	
	return TRUE;
}



/*****************************************************************
* Function:	ExpenseSetAmount
* Purpose: 	This function is used to set amount settings into the
*				expense record
* Scope:		application
* Input:		item_num			the item number of the texbox storing the amount
amount				input amount
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseSetAmount(SHORT item_num, double amount)
{
	DatabaseID	Expense_dbid;
	RecordID	dummy_rec_id;
	UWORD		rec_num, byte_read;
	BYTE		*buffer;
	UWORD		type = (UWORD)EXPENSE_TYPE;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	if (DataRecIDtoNum(Expense_dbid, RecInCat[item_num + NewItemNum - 10], &rec_num) != TRUE)
		return FALSE;
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return FALSE;
	
	amount += 0.0000000001;
	if (DataWriteField(Expense_dbid, RecInCat[item_num + NewItemNum - 10], F_AMT, sizeof(double), (BYTE*)&amount) != TRUE)
		return FALSE;
	
	if (DataGetField(Expense_dbid, RecInCat[item_num + NewItemNum - 10], F_TYPE, &buffer, &byte_read) != TRUE)
		return FALSE;
	
	if ((RecInCat[item_num + NewItemNum - 10] == NewExpense_rec_id)&&(*((UWORD*)buffer) == EXPENSE_TYPE))
		if (DataWriteField(Expense_dbid, RecInCat[item_num + NewItemNum - 10], F_TYPE, sizeof(UWORD), (BYTE*)&type) != TRUE)
		{
			qfree(buffer);
			return FALSE;
		}
		qfree(buffer);
		if (DataCloseRecord(Expense_dbid, RecInCat[item_num + NewItemNum - 10]) != TRUE)
			return FALSE;
		
		return TRUE;
}


/*****************************************************************
* Function:	ExpenseNewCat
* Purpose: 	This function is used to create/rename a category
* Scope:		application
* Input:		rename_cat			Flag to indicate the category to be renamed or created
* Output:		None
* Return:		TRUE				Complete
*				FALSE				If the category name is already exists
* Comment: 	None
*****************************************************************/
SHORT ExpStricmp(BYTE *string1, BYTE *string2)
{
	BYTE	cp, *str1, *str2;
	WORD	i, len1, len2;
	
	len1 = strlen(string1);
	str1 = (BYTE*)qmalloc(len1 * sizeof(BYTE));
	strcpy(str1, string1);
	
	len2 = strlen(string2);
	str2 = (BYTE*)qmalloc(len2 * sizeof(BYTE));
	strcpy(str2, string2);
	
	for(i=0; i<len1; i++)
	{
		if (str1[i] >= 'a' && str1[i] <= 'z')
			str1[i] -= 32;
	}
	
	for(i=0; i<len2; i++)
	{
		if (str2[i] >= 'a' && str2[i] <= 'z')
			str2[i] -= 32;
	}
	
	--str1;
	--str2;
	
	do {} while ( (*++str2 == (cp = *++str1)) && cp );
	
	//qfree(str1);
	//qfree(str2);
	
	return *str1 - *str2;
}

/*****************************************************************
* Function:	ExpenseNewCat
* Purpose: 	This function is used to delete a category
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE					Complete
*				FALSE					Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseNewCat(BOOLEAN rename_cat)
{
	USHORT	total_num_items;
	SHORT	list_item_num;
	BYTE	*textbox_string, *list_string, cat_string[30], cat_string2[30];
	UBYTE	next_free_cat_location, rename_cat_location, cat[NUM_FLODERS];
	WORD	textbox_num_chars, i;
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	TextboxGetNumOfChars(TEXTBOX_EXPENSE_DIALOG_EDCAT, &textbox_num_chars);
	TextboxGetTextPointer(TEXTBOX_EXPENSE_DIALOG_EDCAT, &textbox_string);
	
	strcpy(cat_string2, textbox_string);
	strcpy(cat_string, EXPEFOLDL);
	if (!ExpStricmp(cat_string, cat_string2))
		return FALSE;
	
	strcpy(cat_string, EXPALL);
	if (!ExpStricmp(cat_string, cat_string2))
		return FALSE;
	
	strcpy(cat_string, EXPUNFILED);
	if (!ExpStricmp(cat_string, cat_string2))
		return FALSE;
	
	if (rename_cat)
	{
		ListGetSelectedItem(LIST_EXPENSE_EDCAT, &list_item_num);
		ListGetListItem(LIST_EXPENSE_EDCAT, list_item_num, &list_string);
	}
	
	total_num_items = (SHORT)DataCategorySort(Expense_dbid, cat);
	
	if (total_num_items > 0)
	{
		for(i=0; i<total_num_items; i++)
		{
			DataCategoryName(Expense_dbid, cat[i], cat_string);
			if (rename_cat)
			{
				if (!ExpStricmp(list_string, cat_string))
					rename_cat_location = cat[i];
			}
			if (!ExpStricmp(textbox_string, cat_string))
				return FALSE;
		}
	}
	
	if (rename_cat)
	{
		DataCategorySetName(Expense_dbid, rename_cat_location, textbox_string);
		CatNum = rename_cat_location;
	}
	else
	{
		DataCategoryNextFree(Expense_dbid, &next_free_cat_location);
		DataCategorySetName(Expense_dbid, next_free_cat_location, textbox_string);
		CatNum = next_free_cat_location;
	}
	ExpenseCatToList(textbox_string, TRUE);
	
	return TRUE;
}

/*****************************************************************
* Function:	ExpenseDeleteCat
* Purpose: 	This function is used to delete a category
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE					Complete
*				FALSE					Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseDeleteCat(void)
{
	USHORT	total_num_cat;
	SHORT	list_item_num;
	BYTE	*list_string, cat_string[20], null_buf[1]={0};
	UBYTE	cat[NUM_FLODERS];
	WORD	i;
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	ListGetSelectedItem(LIST_EXPENSE_EDCAT, &list_item_num);
	ListGetListItem(LIST_EXPENSE_EDCAT, list_item_num, &list_string);
	
	total_num_cat = (SHORT)DataCategorySort(Expense_dbid, cat);
	
	
	if (total_num_cat > 0)
		for(i=0; i<total_num_cat; i++)
		{
			DataCategoryName(Expense_dbid, cat[i], cat_string);
			if (!strcmp(list_string, cat_string))
			{
				ExpenseLoadRecord(cat_string, FALSE);
				ExpenseDeleteAllExpense();
				//				DataMoveCat(Expense_dbid, cat[i], 0);
				DataCategorySetName(Expense_dbid, cat[i], null_buf);
				break;
			}
		}
		else
			return FALSE;
		
		if (i == 0)
			cat_string[0] = 0;
		else if (i+1 == total_num_cat)
			DataCategoryName(Expense_dbid, cat[i-1], cat_string);
		else
			DataCategoryName(Expense_dbid, cat[i+1], cat_string);
		
		ExpenseCatToList(cat_string, TRUE);
		
		return TRUE;
}

/*****************************************************************
* Function:	ExpenseListSetScrollbar
* Purpose: 	This function is called in order to set the values for a scrollbar		
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE				scrollbar is erased
*				FALSE				scrollbar is drawn
* Comment: 	If a scrollbar is not required, then the scrollbar will be erased 
If a scrollbar is required, the scrollbar will be displayed accordingly 
*****************************************************************/
BOOLEAN ExpenseListSetScrollbar(void)
{
	WORD	max_value, min_value;
	
	min_value = 0;
	max_value = TotalRecordInCat - 11;	
	
	if (TotalRecordInCat > 11)
		ScrollbarSetScrollbarVisible(SCROLLBAR_EXPENSE_LIST,TRUE);
	else
	{
		ScrollbarSetScrollbarVisible(SCROLLBAR_EXPENSE_LIST,FALSE);
		ScrollbarEraseScrollbar(SCROLLBAR_EXPENSE_LIST);
		return FALSE;
	}
	
	if (TotalRecordInCat < 11)
		ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_LIST, max_value, max_value, min_value, 10, TotalRecordInCat);
	else
		ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_LIST, NewItemNum-10, max_value, min_value, 10, TotalRecordInCat);
	
	ScrollbarSetScrollbarDrawPagesize(SCROLLBAR_EXPENSE_LIST, 11);
	return TRUE;
	
}



/********************************************************
* Function:	ExpenseScrollbarSetList
* Purpose: 	This function is used to set the view of the 
listing page by scrolling the scrollbar
* Scope:		application
* Input:		new_value			new scrolling value
* Output:		None
* Return:		None
* Comment: 	None
*********************************************************/
void ExpenseScrollbarSetList(USHORT new_value)
{
	USHORT	dummy_new_item_num;
	WORD	max, min, value, pagesize, scroll_total_lines;
	
	ScrollbarGetScrollbar(SCROLLBAR_EXPENSE_LIST, &value, &max, &min, &pagesize, &scroll_total_lines);
	ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_LIST, new_value, max, min, pagesize, scroll_total_lines);
	
	NewItemNum = new_value+10;
	ExpenseRecordToList(&dummy_new_item_num);
	
	return;
}


/********************************************************
* Function:	ExpenseScrollbarSetCat
* Purpose: 	This function is used to set the view of the 
category listing page by scrolling the scrollbar
* Scope:		application
* Input:		new_value			new scrolling value
* Output:		None
* Return:		None
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseScrollbarSetCat(USHORT new_value)
{
	BYTE	cat_string[20];
	UBYTE	cat[NUM_FLODERS];
	WORD	max, min, value, pagesize, scroll_total_lines;
	DatabaseID	Expense_dbid;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	ScrollbarGetScrollbar(SCROLLBAR_EXPENSE_EDCAT, &value, &max, &min, &pagesize, &scroll_total_lines);
	ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_EDCAT, new_value, max, min, pagesize, scroll_total_lines);
	
	if (LargeFontInEdcat)
		new_value += 8;
	else
		new_value += 10;
	
	DataCategorySort(Expense_dbid, cat);
	DataCategoryName(Expense_dbid, cat[new_value], cat_string);
	ExpenseCatToList(cat_string, FALSE);
	
	ScrollbarDrawScrollbar(SCROLLBAR_EXPENSE_EDCAT);		
	
	return TRUE;
}


/*****************************************************************
* Function:	ExpenseIsKeypadVisible
* Purpose: 	This function is used to check the keypad is visible
or not
* Scope:		application
* Input:		None
* Output:		None
* Return:		TRUE			keypad is visible
FALSE			keypad is invisible
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseIsKeypadVisible(void)
{
	BOOLEAN		drawn_attr, enable_attr, active_attr, visible_attr;
	
	BitmapGetAttribute(BITMAP_EXPENSE_LIST_KEYPAD, &drawn_attr, &enable_attr, &active_attr, &visible_attr);
	
	return visible_attr;
}


/*****************************************************************
* Function:	ExpenseSetCatPopupEnable
* Purpose: 	This function is used to enable the popup menu
* Scope:		application
* Input:		None
* Output:		None
* Return:		None
* Comment: 	None
*****************************************************************/
void ExpenseSetCatPopupEnable(void)
{
	BOOLEAN		drawn_attr, enable_attr, active_attr, visible_attr, savebehind_attr;
	
	ControlGetAttributes(POPUP_EXPENSE_LIST, &enable_attr, &drawn_attr, &savebehind_attr, &active_attr, &visible_attr);
	enable_attr = TRUE;
	active_attr = TRUE;
	ControlSetAttributes(POPUP_EXPENSE_LIST, enable_attr, drawn_attr, savebehind_attr, active_attr, visible_attr);
	
	return;
}



/*****************************************************************
* Function:	ExpenseKeypadVisible
* Purpose: 	This function is used to set the keypad visible
* Scope:		application
* Input:		None
* Output:		None
* Return:		None
* Comment: 	None
*****************************************************************/
void ExpenseKeypadVisible(void)
{
	BOOLEAN		drawn_attr, enable_attr, active_attr, visible_attr, set_scroll_attr, savebehind_attr;
	//	BOOLEAN		drawn_attr, enable_attr, active_attr, visible_attr, savebehind_attr;
	ObjectID	bitmap_id = BITMAP_EXPENSE_LIST_KEYPAD;
	
    BYTE		object_type;
	Scrollbar	*scrollbar_ptr;
    Menu		*menu_ptr;
    Control		*control_ptr;
    String		*string_ptr;
	
	/* disable the list objects and set it invisible */
	ListGetAttribute(LIST_EXPENSE_LIST_DATE, &enable_attr, &drawn_attr, &active_attr, &visible_attr, &set_scroll_attr);
	enable_attr  = FALSE;
	active_attr  = FALSE;
	visible_attr = TRUE;
	ListSetAttribute(LIST_EXPENSE_LIST_CURR, enable_attr, drawn_attr, active_attr, visible_attr, set_scroll_attr);
	visible_attr = FALSE;
	ListSetAttribute(LIST_EXPENSE_LIST_DATE, enable_attr, drawn_attr, active_attr, visible_attr, set_scroll_attr);
	ListSetAttribute(LIST_EXPENSE_LIST_TYPE, enable_attr, drawn_attr, active_attr, visible_attr, set_scroll_attr);
	ListEraseList(LIST_EXPENSE_LIST_DATE);
	ListEraseList(LIST_EXPENSE_LIST_TYPE);
	
	/* disable the button objects */
	ControlGetAttributes(BUTTON_EXPENSE_LIST_NEW, &enable_attr, &drawn_attr, &savebehind_attr, &active_attr, &visible_attr);
	enable_attr  = FALSE;
	active_attr  = FALSE;
	ControlSetAttributes(BUTTON_EXPENSE_LIST_NEW, enable_attr, drawn_attr, savebehind_attr, active_attr, visible_attr);
	
	/* enable the objects in the keypad*/
	BitmapGetAttribute(bitmap_id, &drawn_attr, &enable_attr, &active_attr, &visible_attr);
	enable_attr = FALSE;
	visible_attr = TRUE;
	BitmapSetAttribute(bitmap_id, drawn_attr, enable_attr, active_attr, visible_attr);
	BitmapDrawBitmap(bitmap_id++);
	
	BitmapGetAttribute(bitmap_id, &drawn_attr, &enable_attr, &active_attr, &visible_attr);
	enable_attr = TRUE;
	visible_attr = TRUE;
	while(bitmap_id < FORM_EXPENSE_TYPE)
	{
		BitmapSetAttribute(bitmap_id, drawn_attr, enable_attr, active_attr, visible_attr);
		BitmapDrawBitmap(bitmap_id++);
	}
	
	ControlGetAttributes(POPUP_EXPENSE_LIST, &enable_attr, &drawn_attr, &savebehind_attr, &active_attr, &visible_attr);
	enable_attr = FALSE;
	active_attr = FALSE;
	ControlSetAttributes(POPUP_EXPENSE_LIST, enable_attr, drawn_attr, savebehind_attr, active_attr, visible_attr);
	
	FormGetObjectPointer(SCROLLBAR_EXPENSE_LIST, &object_type, (void**)&scrollbar_ptr);
	scrollbar_ptr->scrollbar_attr.scrollbar_active = FALSE;
	scrollbar_ptr->scrollbar_attr.scrollbar_enable = FALSE;
	
	FormGetObjectPointer(MENU_EXPENSE, &object_type, (void**)&menu_ptr);
	menu_ptr->menu_attr.menu_drawn = FALSE;
	menu_ptr->menu_attr.menu_visible = FALSE;
	
	FormGetObjectPointer(POPUP_EXPENSE_LIST, &object_type, (void**)&control_ptr);
	control_ptr->control_attr.control_enable = FALSE;
	control_ptr->control_attr.control_drawn = FALSE;
	control_ptr->control_attr.control_active = FALSE;
	control_ptr->control_attr.control_visible = FALSE;
	
	FormGetObjectPointer(BUTTON_EXPENSE_LIST_NEW, &object_type, (void**)&control_ptr);
	control_ptr->control_attr.control_enable = FALSE;
	control_ptr->control_attr.control_drawn = FALSE;
	control_ptr->control_attr.control_active = FALSE;
	control_ptr->control_attr.control_visible = TRUE;
	
	StringSetText(STRING_EXPENSE_LIST_HEADER, CatText);
	
	FormGetObjectPointer(STRING_EXPENSE_LIST_HEADER, &object_type, (void**)&string_ptr);
	string_ptr->string_attr.string_drawn = TRUE;
	string_ptr->string_attr.string_visible = TRUE;
	
	
#ifdef PR31700
	//t==================================================================
	/*
	InlaySetEnableStatus(FALSE);
	SystemSetMappedHardwareKeyStatus(FALSE);
	AlarmMgrEnable(FALSE);
	*/	
	//t=================================================================
#endif
	
	return;
}


/*****************************************************************
* Function:	ExpenseKeypadInvisible
* Purpose: 	This function is used to set the keypad invisible
* Scope:		application
* Input:		None
* Output:		None
* Return:		None
* Comment: 	None
*****************************************************************/
void ExpenseKeypadInvisible(void)
{
	BOOLEAN		drawn_attr, enable_attr, active_attr, visible_attr, set_scroll_attr, savebehind_attr;
	ObjectID	bitmap_id = BITMAP_EXPENSE_LIST_KEYPAD;
    BYTE		object_type;
	Scrollbar	*scrollbar_ptr;
    Menu		*menu_ptr;
    Control		*control_ptr;
    String		*string_ptr;
	
	/* enable the list objects and set it visible */
	ListGetAttribute(LIST_EXPENSE_LIST_DATE, &enable_attr, &drawn_attr, &active_attr, &visible_attr, &set_scroll_attr);
	enable_attr  = TRUE;
	active_attr  = TRUE;
	visible_attr = TRUE;
	ListSetAttribute(LIST_EXPENSE_LIST_CURR, enable_attr, drawn_attr, active_attr, visible_attr, set_scroll_attr);
	ListSetAttribute(LIST_EXPENSE_LIST_DATE, enable_attr, drawn_attr, active_attr, visible_attr, set_scroll_attr);
	ListSetAttribute(LIST_EXPENSE_LIST_TYPE, enable_attr, drawn_attr, active_attr, visible_attr, set_scroll_attr);
	
	/* enable the button objects */
	ControlGetAttributes(BUTTON_EXPENSE_LIST_NEW, &enable_attr, &drawn_attr, &savebehind_attr, &active_attr, &visible_attr);
	enable_attr  = TRUE;
	active_attr  = TRUE;
	ControlSetAttributes(BUTTON_EXPENSE_LIST_NEW, enable_attr, drawn_attr, savebehind_attr, active_attr, visible_attr);
	
	/* disable the objects in the keypad*/
	BitmapGetAttribute(bitmap_id, &drawn_attr, &enable_attr, &active_attr, &visible_attr);
	enable_attr	 = FALSE;
	visible_attr = FALSE;
	active_attr  = FALSE;
	BitmapSetAttribute(bitmap_id++, drawn_attr, enable_attr, active_attr, visible_attr);
	
	BitmapGetAttribute(bitmap_id, &drawn_attr, &enable_attr, &active_attr, &visible_attr);
	enable_attr	 = FALSE;
	visible_attr = FALSE;
	active_attr  = FALSE;
	while(bitmap_id < FORM_EXPENSE_TYPE)
		BitmapSetAttribute(bitmap_id++, drawn_attr, enable_attr, active_attr, visible_attr);
	
	FormGetObjectPointer(SCROLLBAR_EXPENSE_LIST, &object_type, (void**)&scrollbar_ptr);
	scrollbar_ptr->scrollbar_attr.scrollbar_active = TRUE;
	scrollbar_ptr->scrollbar_attr.scrollbar_enable = TRUE;
	
	FormGetObjectPointer(MENU_EXPENSE, &object_type, (void**)&menu_ptr);
	menu_ptr->menu_attr.menu_drawn = TRUE;
	menu_ptr->menu_attr.menu_visible = TRUE;
	
	FormGetObjectPointer(POPUP_EXPENSE_LIST, &object_type, (void**)&control_ptr);
	control_ptr->control_attr.control_enable = TRUE;
	control_ptr->control_attr.control_drawn = TRUE;
	control_ptr->control_attr.control_visible = TRUE;
	
	FormGetObjectPointer(BUTTON_EXPENSE_LIST_NEW, &object_type, (void**)&control_ptr);
	control_ptr->control_attr.control_enable = TRUE;
	control_ptr->control_attr.control_drawn = TRUE;
	control_ptr->control_attr.control_visible = TRUE;
	
	FormGetObjectPointer(STRING_EXPENSE_LIST_HEADER, &object_type, (void**)&string_ptr);
	string_ptr->string_attr.string_drawn = FALSE;
	string_ptr->string_attr.string_visible = FALSE;
	
	
#ifdef PR31700
	//t==================================================================
	/*
	InlaySetEnableStatus(TRUE);
	SystemSetMappedHardwareKeyStatus(TRUE);
	AlarmMgrEnable(TRUE);
	*/	
	//t==================================================================
#endif
	
	return;
}



/*****************************************************************
* Function:	ExpenseInitTypeCurr
* Purpose: 	This function is used to initialize the option settings 
for expense type and currencies
* Scope:		application
* Input:		None
* Output:		None
* Return:		None
* Comment: 	None
*****************************************************************/
void ExpenseInitTypeCurr(void)
{
	
	BYTE	sbuffer[20];
	
	ExpenseUpdateExpenseType();
	
	ListDeleteAllItems(LIST_EXPENSE_CURR_LIST1);
	ListDeleteAllItems(LIST_EXPENSE_CURR_LIST2);
	
	strcpy(sbuffer, COU1);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 0, sbuffer);
	strcpy(sbuffer, COU2);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 1, sbuffer);
	strcpy(sbuffer, COU3);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 2, sbuffer);
	strcpy(sbuffer, COU4);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 3, sbuffer);
	strcpy(sbuffer, COU5);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 4, sbuffer);
	strcpy(sbuffer, COU6);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 5, sbuffer);
	strcpy(sbuffer, COU7);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 6, sbuffer);
	strcpy(sbuffer, COU8);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 7, sbuffer);
	strcpy(sbuffer, COU9);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 8, sbuffer);
	strcpy(sbuffer, COU10);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 9, sbuffer);
	strcpy(sbuffer, COU11);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 10,sbuffer);
	strcpy(sbuffer, COU12);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 11, sbuffer);
	strcpy(sbuffer, COU13);
	ListInsertItem(LIST_EXPENSE_CURR_LIST1, 12, sbuffer);
	
	strcpy(sbuffer, COU14);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 0, sbuffer);
	strcpy(sbuffer, COU15);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 1, sbuffer);
	strcpy(sbuffer, COU16);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 2, sbuffer);
	strcpy(sbuffer, COU17);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 3, sbuffer);
	strcpy(sbuffer, COU18);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 4, sbuffer);
	strcpy(sbuffer, COU19);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 5, sbuffer);
	strcpy(sbuffer, COU20);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 6, sbuffer);
	strcpy(sbuffer, COU21);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 7, sbuffer);
	strcpy(sbuffer, COU22);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 8, sbuffer);
	strcpy(sbuffer, COU23);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 9, sbuffer);
	strcpy(sbuffer, COU24);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 10, sbuffer);
	strcpy(sbuffer, COU25);
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 11, sbuffer);
	strcpy(sbuffer, "$");
	ListInsertItem(LIST_EXPENSE_CURR_LIST2, 12, sbuffer);
	
	return;
}


/********************************************************
* Function:	ExpenseCheckTextboxDigitOver
* Purpose: 	This function is called in order to check the digits in textbox
are over the input significat figure or not
* Scope:		Application
* Input:		textbox_id		The input textbox ID
input_string	The input string of the display
insert_ptr_pos	Insert point position
sig_fig			significat figure
* Output:		None
* Return:		1				if Over
0				else
* Comment: 	None
*********************************************************/
BYTE ExpenseCheckTextboxDigitOver(ObjectID textbox_id, BYTE *input_string, WORD insert_ptr_pos, SHORT sig_fig)
{
	WORD		i = 0, j = 0;
    BYTE		object_type;
    Textbox		*textbox_ptr;
	
	FormGetObjectPointer(textbox_id, &object_type, (void**)&textbox_ptr);
	if (textbox_ptr->textbox_attr.textbox_highlight)
		return 0;
	
	while((input_string[i] != '.') && (input_string[i] != '\0'))
		i++;
	
	if (input_string[i] == '\0')
	{
		if ((i > 4) && (sig_fig != 0))
			return 1;
		else if(i == 4 && sig_fig == 1)
			return 1;
	}
	else
	{
		if (sig_fig == 0)
			return 1;
		if (insert_ptr_pos <= i)
		{
			if (i < 5)
				return 0;
			else
				return 1;
		}
		while(input_string[i] != '\0')
		{
			j++;
			i++;
		}
		if (j > 2)
			return 1;
	}
	
	return 0;
}


/********************************************************
* Function:	ExpenseSetEdcatListFont
* Purpose: 	This function is called to set the font in edit folders
* Scope:		Application
* Input:		list_id			The input list ID
font			MEDIUM_FONT or SMALL_FONT
* Output:		None
* Return:		None
* Comment: 	None
*********************************************************/
void ExpenseSetEdcatListFont(ObjectID list_id, BYTE font)
{
	WORD	max, min, value, pagesize, scroll_total_lines;
	
	switch(font)
	{
	case MEDIUM_FONT:
		ScrollbarGetScrollbar(SCROLLBAR_EXPENSE_EDCAT, &value, &max, &min, &pagesize, &scroll_total_lines);
		if (value > 8)
			value = 8;
		if (max > 8)
			max = 8;
		//ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_EDCAT, value, max, min, 8, 9+max);
		MenuDeleteItem(MENU_EXPENSE_EDCAT, MENU_ITEM_FONT);
		font = MEDIUM_FONT;
		MenuInsertItem(MENU_EXPENSE_EDCAT, MENU_ITEM_FONT, EXPSFONT);
		ListSetFont(list_id, MEDIUM_FONT);
		break;
		
	case SMALL_FONT:
		ScrollbarGetScrollbar(SCROLLBAR_EXPENSE_EDCAT, &value, &max, &min, &pagesize, &scroll_total_lines);
		//ScrollbarSetScrollbar(SCROLLBAR_EXPENSE_EDCAT, value, max, min, 10, 11+max);
		MenuDeleteItem(MENU_EXPENSE_EDCAT, MENU_ITEM_FONT);
		ListSetFont(list_id, SMALL_FONT);
		font = SMALL_FONT;
		MenuInsertItem(MENU_EXPENSE_EDCAT, MENU_ITEM_FONT, EXPLFONT);
		break;
		
	default:
		return;
	}
	
	return;
}

/********************************************************
* Function:	ExpenseCheckMemoryEmpty
* Purpose: 	This function is called to check the memory status
whether it is empty or not
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseCheckMemoryEmpty()
{
#ifdef PR31700	
	if (MemoryCheckMemLow())
	{
		FormGetActiveFormID(&G_active_form_id);
		return TRUE;
	}
#endif
	return FALSE;
}

//t==============================================================
/********************************************************
* Function:	ExpenseNewExpenseType
* Purpose: 	This function is called to create an new expense type
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseNewExpenseType(BYTE *expense_type_string, UWORD *total_rec)
{
	DatabaseID	Expense_type_dbid;
	RecordID	Expense_type_rec_id;
	UWORD		tt_rec;
	USHORT		i, total_items;
	BYTE		*item_text;
	Err			Error;
	
	ExpenseLoadExpenseType();
	
	if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
		return FALSE;
	if (!DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW))
		return FALSE;
	
	if (!DataTotalRecord(Expense_type_dbid, &tt_rec))
		return FALSE;
	
	tt_rec += 2;
	if (tt_rec > 255)
		return FALSE;
	
	ListGetTotalItems(LIST_EXPENSE_TYPE_LIST1, &total_items);
	if (total_items)
	{
		for(i=0; i<tt_rec; i++)
		{
			ListGetListItem(LIST_EXPENSE_TYPE_LIST1, i, &item_text);
			if (!ExpStricmp(expense_type_string, item_text))
				return FALSE;
		}
	}
	
	if (DataNewRecord(Expense_type_dbid, 0, 2, &Expense_type_rec_id) != TRUE)
		return FALSE;
	
	if (DataWriteField(Expense_type_dbid, Expense_type_rec_id, 0, (strlen(expense_type_string)+1)*sizeof(BYTE), (BYTE*)expense_type_string) != TRUE)
		return FALSE;
	
	if (DataCloseRecord(Expense_type_dbid, Expense_type_rec_id) != TRUE)
		return FALSE;
	
	if (!DataCloseDB(Expense_type_dbid))
		return FALSE;
	
	ExpenseUpdateExpenseType();
	
	if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
		return FALSE;
	
	if (!DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW))
		return FALSE;
	
	DataRecIDtoNum(Expense_type_dbid, Expense_type_rec_id, total_rec);
	
	if (!DataCloseDB(Expense_type_dbid))
		return FALSE;
	return TRUE;
}



/********************************************************
* Function:	ExpenseUpdateExpenseType
* Purpose: 	This function is called to update the expense type
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseUpdateExpenseType(void)
{
	DatabaseID	Expense_type_dbid, Expense_dbid;
	RecordID	type_rec_id, dummy_rec_id;
	UWORD		total_rec, i, byte_read, j = 0, k = 0, rec_num;
	BYTE		*buffer, *type_buffer, highlightOK = 0;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return -1;
	if (DataRecIDtoNum(Expense_dbid, RecIDInList[HighlightRecNumInList], &rec_num) != TRUE)
		return -1;
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return -1;
	if (DataGetField(Expense_dbid, RecIDInList[HighlightRecNumInList], F_TYPE, &type_buffer, &byte_read) != TRUE)
		return -1;
	if (DataCloseRecord(Expense_dbid, NewExpense_rec_id) != TRUE)
		return -1;
	
#ifdef DEBUG
	printf("\n In ExpenseUpdateExpenseType()");
	printf("\n HighlightRecNumInList = %ld", HighlightRecNumInList);
	printf("\n string = %s", type_buffer);
#endif
	
	//L=====================================================
	ControlPopupDeleteAllItems(POPUP_EXPENSE_TYPE);
	ListDeleteAllItems(LIST_EXPENSE_TYPE_LIST1);
	//L=====================================================
	
	if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
		return FALSE;
	
	if (!DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW))
		return FALSE;
	
	if (!DataTotalRecord(Expense_type_dbid, &total_rec))
		return FALSE;
	
	//L=====================================================
	
	if (G_del_expense_type == NO_SELECT && G_rename_expense_type == NO_SELECT)
	{
		ControlPopupInsertItem(POPUP_EXPENSE_TYPE, 0, EXPUDEFINE);
		j++;
		ListInsertItem(LIST_EXPENSE_TYPE_LIST1, 0, EXPUDEFINE);
		ListInsertItem(LIST_EXPENSE_TYPE_LIST1, 1, EXPOTHER);
		k+=2;
	}
	ControlPopupInsertItem(POPUP_EXPENSE_TYPE, 1, EXPOTHER);
	j++;
	
	for(i=0; i<total_rec; i++)
	{
		DataOpenRecord(Expense_type_dbid, i, &type_rec_id, NULL);
		DataGetField(Expense_type_dbid, type_rec_id, 0, &buffer, &byte_read);
		ControlPopupInsertItem(POPUP_EXPENSE_TYPE, i+j, buffer);
		ListInsertItem(LIST_EXPENSE_TYPE_LIST1, i+k, buffer);
		
#ifdef DEBUG
		printf("\n i = %ld", i);
		printf("\n type_buffer = %ld", *((UWORD*)type_buffer));
		printf("\n type_rec_id = %ld", type_rec_id);
#endif
		
		if (*((UWORD*)type_buffer) == type_rec_id)
		{
			if (G_del_expense_type == NO_SELECT && G_rename_expense_type == NO_SELECT)
			{
				ListSetHighlightedItem(LIST_EXPENSE_TYPE_LIST1, i+2);
				highlightOK = 1;
			}
		}
		
		//L=====================================================
		DataCloseRecord(Expense_type_dbid, type_rec_id);
		qfree(buffer);
	}
	
	if (highlightOK == 0)
	{
		ListGetListItem(LIST_EXPENSE_TYPE_LIST1, 0, &buffer);
		if (!ExpStricmp(buffer, EXPUDEFINE))
			ListSetHighlightedItem(LIST_EXPENSE_TYPE_LIST1, 1);
		else
			ListSetHighlightedItem(LIST_EXPENSE_TYPE_LIST1, 0);
	}
	
	qfree(type_buffer);
	
	if (!DataCloseDB(Expense_type_dbid))
		return FALSE;
	
	return TRUE;
}


/********************************************************
* Function:	ExpenseDeleteExpenseType
* Purpose: 	This function is called to delete the expense type
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseDeleteExpenseType(UWORD replaced_expense_type)
{
	DatabaseID	Expense_dbid, Expense_type_dbid;
	RecordID	Expense_rec_id, rename_rec_id;
	UWORD		total_rec, byte_read, i;
	BYTE		*buffer;
	
	//L=====================================================
	
	//Expense_type_rec_id = ExpenseTypeDBNumToDBRecID(G_del_expense_type);
	if (replaced_expense_type == 0)
		rename_rec_id = (UWORD)OTHER;
	else
		rename_rec_id = ExpenseTypeDBNumToDBRecID(--replaced_expense_type);
	
	if (G_del_expense_type == rename_rec_id)
		return TRUE;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	DataTotalRecord(Expense_dbid, &total_rec);
	for(i=0; i<total_rec; i++)
	{
		DataOpenRecord(Expense_dbid, (UWORD)i, &Expense_rec_id, NULL);
		DataGetField(Expense_dbid, Expense_rec_id, F_TypeName, &buffer, &byte_read);
		
		if (*((UWORD*)buffer) == G_del_expense_type)
		{
			DataWriteField(Expense_dbid, Expense_rec_id, F_TYPE, sizeof(UWORD), (BYTE*)&rename_rec_id);
		}
		qfree(buffer);
	}
	
	/*
	DataFindDB(EXPTYPEDB, &Expense_type_dbid);
	DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW);
	DataDeleteRecord(Expense_type_dbid, Expense_type_rec_id, FALSE);
	DataCloseDB(Expense_type_dbid);
	*/
	//L=====================================================
	
	G_del_expense_type = NO_SELECT;
	
	return TRUE;
}




/********************************************************
* Function:	ExpenseTypeDBNumToDBRecID
* Purpose: 	This function is called to delete the expense type
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
RecordID ExpenseTypeDBNumToDBRecID(UWORD db_type_num)
{
	DatabaseID	Expense_type_dbid;
	RecordID	Expense_type_rec_id;
	Err			Error;
	
	//L=====================================================
	/*
	if (db_type_num > 1)
	db_type_num -= 2;
	else
	return 0;
	*/
	//L=====================================================
	Error = DataFindDB(EXPTYPEDB, &Expense_type_dbid);
	Error = DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW);
	
	//L=====================================================
	/*
	DataOpenRecord(Expense_type_dbid, db_type_num, &Expense_type_rec_id, NULL);
	
	  DataCloseRecord(Expense_type_dbid, Expense_type_rec_id);
	*/
	Error = DataNumtoRecID(Expense_type_dbid, db_type_num, &Expense_type_rec_id);
	
	//L=====================================================
	
	Error = DataCloseDB(Expense_type_dbid);
	return Expense_type_rec_id;
}



/********************************************************
* Function:	ExpenseRenameExpenseType
* Purpose: 	This function is called to rename the expense type
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseRenameExpenseType(BYTE *rename_expense_type_string)
{
	DatabaseID	Expense_type_dbid;
	RecordID	Expense_type_rec_id;
	UWORD		rec_num, tt_rec;
	BYTE		*item_text;
	SHORT		i;
	
	if (!ExpStricmp(rename_expense_type_string, EXPUDEFINE))
		return FALSE;
	
	if (!ExpStricmp(rename_expense_type_string, EXPOTHER))
		return FALSE;
	
	if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
		return FALSE;
	
	if (!DataTotalRecord(Expense_type_dbid, &tt_rec))
		return FALSE;
	
	for(i=0; i<tt_rec; i++)
	{
		ListGetListItem(LIST_EXPENSE_TYPE_LIST1, i, &item_text);
		if (!ExpStricmp(rename_expense_type_string, item_text))
			return FALSE;
	}
	
	Expense_type_rec_id = ExpenseTypeDBNumToDBRecID(G_rename_expense_type);
	
	DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW);
	
	DataRecIDtoNum(Expense_type_dbid, Expense_type_rec_id, &rec_num);
	DataOpenRecord(Expense_type_dbid, rec_num, &Expense_type_rec_id, NULL);
	
	//L=====================================================
	//DataWriteField(Expense_type_dbid, Expense_type_rec_id, 1, (strlen(rename_expense_type_string)+1)*sizeof(BYTE), (BYTE*)rename_expense_type_string);
	DataWriteField(Expense_type_dbid, Expense_type_rec_id, 0, (strlen(rename_expense_type_string)+1)*sizeof(BYTE), (BYTE*)rename_expense_type_string);
	//L=====================================================
	
	DataCloseRecord(Expense_type_dbid, Expense_type_rec_id);
	DataCloseDB(Expense_type_dbid);
	
	G_rename_expense_type = NO_SELECT;
	
	return TRUE;
}


//t==============================================================
/*****************************************************************
* Function:	ExpenseSetDate
* Purpose: 	This function is used to set date settings into the
*				expense record
* Scope:		application
* Input:		date				input date settings in expense format
* Output:		None
* Return:		TRUE				Complete
*				FALSE				Error
* Comment: 	None
*****************************************************************/
BOOLEAN ExpenseGetDate(EXPENSE_DATE *in_buf)
{
	UWORD			rec_num;
	RecordID		dummy_rec_id;
	DatabaseID		Expense_dbid;
	UWORD			byte_read;
	EXPENSE_DATE 	*date_buf;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	if (DataRecIDtoNum(Expense_dbid, RecIDInList[HighlightRecNumInList], &rec_num) != TRUE)
		return FALSE;
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return FALSE;
	
	if (DataGetField(Expense_dbid, RecIDInList[HighlightRecNumInList], F_DATE, (BYTE**)&date_buf, &byte_read) != TRUE)
		return FALSE;
	
	
	if (DataCloseRecord(Expense_dbid, RecIDInList[HighlightRecNumInList]) != TRUE)
		return FALSE;
	
	*in_buf = *date_buf;
	qfree(date_buf);
	
	return TRUE;
}
/*****************************************************************
* Function:	SchedulerRestoreDateSettings
* Purpose: 	This function is used to restore the date settings
*				from the timer
* Scope:		application
* Input:		form_id					Form ID of date settings
year_push_id			The first push button ID of year selection
month_push_id			The first push button ID of month selection	
* Output:		row_num					Row number of the table object in date settings
col_num					Column number of the table object in date settings
* Return:		None
* Comment: 	None
*****************************************************************/
void ExpRestoreDateSettings(ObjectID form_id, ObjectID table_id, ObjectID year_push_id, 
							ObjectID month_push_id, USHORT *row_num, USHORT *col_num)
{
	ObjectID	control_id;
	BYTE		year_label[5]={0};
	SHORT		first_year;
	USHORT		i = 0;
	RTM			timer;
	EXPENSE_DATE	date_buf;
	CountrySettings	country;
	
	
	ExpenseGetDate(&date_buf);
	
	timer.year = (SHORT)date_buf.year + SYSETUP_YEAR_OFFSET;
	timer.mon  = (SHORT)date_buf.mon - 1;
	timer.mday = (SHORT)date_buf.day;
	
	SySetupGetCountrySettings(&country);
	//----------------------------------------------
	control_id = year_push_id;
	if (timer.year < 1907)
		first_year = 1905;
	else if(timer.year > 2093)
		first_year = 2095;
	else
		first_year = timer.year - 2;
	
	sprintf((char*)year_label, "%d", first_year);
	while(i < 5)
	{
		ControlSetLabel(control_id, year_label);
		if (first_year+i == timer.year)
			FormSetControlGroupSelection(form_id, control_id);
		i++;
		sprintf((char*)year_label, "%d", first_year+i);
		control_id++;
	}
	//-----------------------------------------------------------------------
	FormSetControlGroupSelection(form_id, (ObjectID)(timer.mon + month_push_id));
	
	SySetupDateUpdateTable(table_id, timer.year, timer.mon, timer.mday,
		country.start_of_week, row_num, col_num);
	
	return;
}

/********************************************************
* Function:	ExpenseUpdateExpenseType
* Purpose: 	This function is called to update the expense type
* Scope:		Application
* Input:		None
* Output:		None
* Return:		TRUE
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseLoadExpenseType(void)
{
	DatabaseID	Expense_type_dbid;
	RecordID	type_rec_id;
	UWORD		total_rec, i, byte_read, j = 0, k = 0, rec_num;
	BYTE		*buffer, highlightOK = 0;
	
	ControlPopupDeleteAllItems(POPUP_EXPENSE_TYPE);
	ListDeleteAllItems(LIST_EXPENSE_TYPE_LIST1);
	
	if (!DataFindDB(EXPTYPEDB, &Expense_type_dbid))
		return FALSE;
	
	if (!DataOpenDB(Expense_type_dbid, F_TypeID | SORT_TEXT_MODE, OPEN_RW))
		return FALSE;
	
	if (!DataTotalRecord(Expense_type_dbid, &total_rec))
		return FALSE;
	
	ControlPopupInsertItem(POPUP_EXPENSE_TYPE, 0, EXPOTHER);
	j++;
	
	for(i=0; i<total_rec; i++)
	{
		DataOpenRecord(Expense_type_dbid, i, &type_rec_id, NULL);
		DataGetField(Expense_type_dbid, type_rec_id, 0, &buffer, &byte_read);
		ControlPopupInsertItem(POPUP_EXPENSE_TYPE, i+j, buffer);
		ListInsertItem(LIST_EXPENSE_TYPE_LIST1, i+k, buffer);
		DataCloseRecord(Expense_type_dbid, type_rec_id);
		qfree(buffer);
	}
	
	if (highlightOK == 0)
		ListSetHighlightedItem(LIST_EXPENSE_TYPE_LIST1, 0);
	
	if (!DataCloseDB(Expense_type_dbid))
		return FALSE;
	
	return TRUE;
}

/********************************************************
* Function:	ExpenseCheckNewRecord
* Purpose: 	This function is to check whether the record
is new or not
* Scope:		Internal
* Input:		None
* Output:		None
* Return:		TRUE		a new record
FALSE		not a new record
* Comment: 	None
*********************************************************/
BOOLEAN ExpenseCheckNewRecord()
{
	BYTE		*buffer;
	UWORD		byte_read, rec_num;
	RecordID	dummy_rec_id;
	DatabaseID	Expense_dbid;
	double		amount;
	
	if (!DataFindDB(EXPDB, &Expense_dbid))
		return FALSE;
	
	if (DataRecIDtoNum(Expense_dbid, NewExpense_rec_id, &rec_num) != TRUE)
		return FALSE;
	
	if (DataOpenRecord(Expense_dbid, rec_num, &dummy_rec_id, NULL) != TRUE)
		return FALSE;
	
	if (DataGetField(Expense_dbid, NewExpense_rec_id, F_AMT, &buffer, &byte_read) != TRUE)
		return FALSE;
	
	if (DataCloseRecord(Expense_dbid, NewExpense_rec_id) != TRUE)
		return FALSE;
	
	amount = (*(double*)buffer);
	qfree(buffer);
	if (amount == 0.0)
		return TRUE;
	
	return FALSE;
}
