///////////////////////////////////////////////
//	main.cpp - core code for the application //
///////////////////////////////////////////////

/************************************
REVISION LOG ENTRY
Revision By: Chris Gil
Revised on 23/07/2002 19:40:00
Version: V
Comments: Added SNMP 
************************************/

/************************************
REVISION LOG ENTRY
Revision By: TimA
Revised on 18/07/2001 11:29:51
Version: V
Comments: Modified extinfo, extclient, extdriver, to have connect() function so
all constructors take no parameters
************************************/


/************************************
REVISION LOG ENTRY
Revision By: TimA
Revised on 28/03/2001 14:42:29
Version: V
Comments: new comms class specifies the serial port number in the open() function
now, rather than the constructor
************************************/



#include "stdafx.h"
#define EXT
#include "Rtr_Trig.h"

//
//  FUNCTION: WinMain()
//
//  PURPOSE: 
//
//  COMMENTS: main entry point for BNCS Driver "Rtr_Trig"
//
//
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	
	MSG msg;
	HACCEL hAccelTable;
	char acTemp[256];
	
	lstrcpyn(acTemp,lpCmdLine,255);
	iDevice=atoi(acTemp);
	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, acTemp, MAX_LOADSTRING);
	wsprintf(szTitle,acTemp,iDevice);
	LoadString(hInstance, IDC_APPCLASS, szWindowClass, MAX_LOADSTRING);
	
	MyRegisterClass(hInstance);
	
	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}
	
	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_RTR_TRIG);
	
	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	
	return msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;
	
	wcex.cbSize = sizeof(WNDCLASSEX); 
	
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_REG);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= (LPCSTR)IDC_RTR_TRIG;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
	
	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	hInst = hInstance; // Store instance handle in our global variable
	
	hWndMain = CreateWindow(szWindowClass, szTitle, WS_SYSMENU|WS_MINIMIZEBOX ,
		CW_USEDEFAULT, 0, APP_WIDTH, APP_HEIGHT, NULL, NULL, hInstance, NULL);
	
	ghWnd=hWndMain; // Store Main Window handle in our global variable

//	SetTimer(ghWnd, LASTSOURCEPOLLTIMER, LASTSOURCEPOLLDELAY, NULL);

	if (!hWndMain)
	{
		return FALSE;
	}
	
#ifdef _DEBUG
	ShowWindow(hWndMain,nCmdShow);
#else
	ShowWindow(hWndMain, SW_MINIMIZE);
#endif
	
	UpdateWindow(hWndMain);
	
	return TRUE;

}

//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  
//	COMMENTS:
//	
//	WM_COMMAND	- process the application menu
//  WM_DESTROY	- post a quit message and return
//	
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	RECT rctWindow;
	int wmId, wmEvent;
	char szFileName[256];
	char szSection [MAX_LOADSTRING];
	LoadString(hInst, IDS_SECTION, szSection, MAX_LOADSTRING);
	
	switch (message) 
	{
	case WM_CREATE:
		return InitApp(hWnd);
		
		// TODO: Add WM_TIMER processing if required
		
	case WM_SIZE: // if the main window is resized, resize the listbox too
		//Don't resize window with child dialog
		break;
		
	/*	case WM_TIMER:
			switch (wParam)
			{
			case LASTSOURCETIMER:
				{
				fLastSourceTimeOut = 0;
				Debug("LastSource timeout");
				KillTimer(hWnd, LASTSOURCETIMER);
				break;
				}
			case LASTSOURCEPOLLTIMER:
				{
				ec.txrtrcmd(sLASTSOURCEPOLL);
				Debug("Re-polling router until lastsource revertive received : % s", sLASTSOURCEPOLL);
				break;
				}
			}
			break;*/
			
	case WM_COMMAND:
		wmId    = LOWORD(wParam); 
		wmEvent = HIWORD(wParam); 
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
			break;
			
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
			
		case ID_DEBUG_CLEAR:
			SendMessage(hWndList,LB_RESETCONTENT,0,0L);
			break;
			
		case ID_DEBUG_ON:
			GetWindowRect(hWnd, &rctWindow);
			if (fDebug==TRUE) {
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_ON,MF_UNCHECKED);
				sprintf(szFileName, "dev_%03d.ini", iDevice);
				w_p(szFileName, szSection, "DebugMode", "0");
				fDebug=FALSE;
				
			} 
			else {
				MoveWindow(hWnd, rctWindow.left, rctWindow.top, APP_WIDTH, APP_HEIGHT, TRUE);
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_ON,MF_CHECKED);
				sprintf(szFileName, "dev_%03d.ini", iDevice);
				w_p(szFileName, szSection, "DebugMode", "1");
				fDebug=TRUE;
				
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_HIDE,MF_UNCHECKED);
				fDebugHide=FALSE;
			}
			break;
			
		case ID_DEBUG_HIDE:
			GetWindowRect(hWnd, &rctWindow);
			if (fDebugHide==TRUE) {
				MoveWindow(hWnd, rctWindow.left, rctWindow.top, APP_WIDTH, iChildHeight + 42, TRUE);
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_HIDE,MF_CHECKED);
				fDebugHide=FALSE;
				
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_ON,MF_UNCHECKED);
				sprintf(szFileName, "dev_%03d.ini", iDevice);
				w_p(szFileName, szSection, "DebugMode", "0");
				fDebug=FALSE;
			} 
			else {
				MoveWindow(hWnd, rctWindow.left, rctWindow.top, APP_WIDTH, APP_HEIGHT, TRUE);
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_HIDE,MF_UNCHECKED);
				fDebugHide=TRUE;
				
				CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_ON,MF_CHECKED);
				sprintf(szFileName, "dev_%03d.ini", iDevice);
				w_p(szFileName, szSection, "DebugMode", "1");
				fDebug=TRUE;
			}
			break;
			
		case ID_TEST_SET: // set a couple of slots
			{
				char *array[2]={"0","1"};
				ei.setslot(1,array[0]);
				ei.setslot(2,array[1]);
			}
			break; 
			
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
		
		case WM_DESTROY:
			CloseApp(hWnd);
			PostQuitMessage(0);
			break;
			
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

//
//  FUNCTION: DlgProcChild()
//
//  PURPOSE: Message handler for child dialog.
//
//  COMMENTS: Displays the interface status
//
// 
LRESULT CALLBACK DlgProcChild(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_INITDIALOG:
		return TRUE;
		break;
	default:
		break;
	}
    return FALSE;
}

//  FUNCTION: Version Info()
//
//
//  PURPOSE: Load global variables with version info
//
//  COMMENTS: 
//			
//			
//
void VersionInfo() {
	LPBYTE   abData;
	DWORD  handle;
	DWORD  dwSize;
	LPBYTE lpBuffer;
	LPSTR szName, szModFileName, szBuf;
	char acBuf[16];
	#define	PATH_LENGTH	256
			
	szName=(LPSTR)malloc(PATH_LENGTH);
	szModFileName=(LPSTR)malloc(PATH_LENGTH);
	szBuf=(LPSTR)malloc(PATH_LENGTH);

	/*get version info*/

	GetModuleFileName(hInst,szModFileName,PATH_LENGTH);

	dwSize = GetFileVersionInfoSize(szModFileName, &handle);
	abData=(LPBYTE)malloc(dwSize);
	GetFileVersionInfo(szModFileName, handle, dwSize, abData);
	if (dwSize) {
		/* get country translation */
		VerQueryValue((LPVOID)abData, "\\VarFileInfo\\Translation", (LPVOID*)&lpBuffer, (UINT *) &dwSize);
		/* make country code */
		wsprintf(acBuf,"%04X%04X",*(WORD*)lpBuffer,*(WORD*)(lpBuffer+2));
		if (dwSize!=0) {
			/* get a versioninfo file version number */
			wsprintf(szName,"\\StringFileInfo\\%s\\FileVersion",(LPSTR)acBuf);
			VerQueryValue((LPVOID)abData, (LPSTR) szName, (LPVOID*)&lpBuffer,(UINT *) &dwSize);
		}
		/* copy version number from byte buffer to a string buffer */
		lstrcpyn(szModFileName,(LPSTR)lpBuffer,(int)dwSize);

		//Save the version number
		strcpy(szVersion, szModFileName);

		/* copy to the dialog static text box */
		wsprintf(szBuf,"%s",szModFileName);
		SetDlgItemText(hWndDlg, IDC_VERSION, szBuf);
	}			
	free((PVOID)abData);
	free((PVOID)szName);
	free((PVOID)szModFileName);
	free((PVOID)szBuf);
}
//
//  FUNCTION: About()
//
//  PURPOSE: Message handler for about box.
//
//  COMMENTS: Displays the compile date info
//				and used to display version info from
//				a version resource
//
// 
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_INITDIALOG:
		{
			LPBYTE   abData;
			DWORD  handle;
			DWORD  dwSize;
			LPBYTE lpBuffer;
			LPSTR szName, szModFileName, szBuf;
			char acBuf[16];
#define	PATH_LENGTH	256
			
			szName=(LPSTR)malloc(PATH_LENGTH);
			szModFileName=(LPSTR)malloc(PATH_LENGTH);
			szBuf=(LPSTR)malloc(PATH_LENGTH);
			
			/*get version info*/
			
			GetModuleFileName(hInst,szModFileName,PATH_LENGTH);
			
			dwSize = GetFileVersionInfoSize(szModFileName, &handle);
			
			abData=(LPBYTE)malloc(dwSize);
			
			GetFileVersionInfo(szModFileName, handle, dwSize, abData);
			
			if (dwSize)
			{
				/* get country translation */
				VerQueryValue((LPVOID)abData, "\\VarFileInfo\\Translation", (LPVOID*)&lpBuffer, (UINT *) &dwSize);
				/* make country code */
				wsprintf(acBuf,"%04X%04X",*(WORD*)lpBuffer,*(WORD*)(lpBuffer+2));
				
				if (dwSize!=0)
				{
					/* get a versioninfo file version number */
					wsprintf(szName,"\\StringFileInfo\\%s\\FileVersion",(LPSTR)acBuf);
					VerQueryValue((LPVOID)abData, (LPSTR) szName, (LPVOID*)&lpBuffer,(UINT *) &dwSize);
				}
				
				/* copy version number from byte buffer to a string buffer */
				lstrcpyn(szModFileName,(LPSTR)lpBuffer,(int)dwSize);
				
				/* copy to the dialog static text box */
				wsprintf(szBuf,"Version %s",szModFileName);
				SetDlgItemText (hDlg, IDC_VERSION, szBuf);
			}
			
			wsprintf(szName,"%s - %s",(LPSTR)__DATE__,(LPSTR)__TIME__);
			SetDlgItemText(hDlg,IDC_COMPID,szName);
			
			free((PVOID)abData);
			free((PVOID)szName);
			free((PVOID)szModFileName);
			free((PVOID)szBuf);
		}
		return TRUE;
		
	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
		{
			EndDialog(hDlg, LOWORD(wParam));
			return TRUE;
		}
		break;
	}
    return FALSE;
}

//
//  FUNCTION: InitApp()
//
//  PURPOSE: Things to do when main window is created
//
//  COMMENTS: Called from WM_CREATE message
//			 We create a list box to fill the main window to use as a
//			debugging tool, and configure the serial port and infodriver 
//			connections, as well as a circular fifo buffer
//
//

LRESULT InitApp(HWND hWnd)
{
	/* return 0 if OK, or -1 if an error occurs*/
	RECT rctWindow;
	rsh = 0;
	LastSce =0;
	iTBSState = 0;
	// Init Status Dialogs
	hWndDlg = CreateDialog(hInst, (LPCTSTR)IDD_STATUS, hWnd, (DLGPROC)DlgProcChild);
	GetClientRect(hWndDlg, &rctWindow);
	iChildHeight = rctWindow.bottom - rctWindow.top + 2;
	
	GetClientRect(hWnd,&rc);
	hWndList=CreateWindow("LISTBOX","",WS_CHILD | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS,
		0,iChildHeight,rc.right-rc.left,rc.bottom-rc.top-iChildHeight,
		hWnd,(HMENU)IDW_LIST,hInst,0);
	ShowWindow(hWndList,SW_SHOW);
	
	LoadIni();
	blnContinueAutoInit = TRUE;

	VersionInfo();
	SetDlgItemText(hWndDlg, IDC_AUTO_VERSION, szVersion);

	if (fDebug) {
		MoveWindow(hWnd, rctWindow.left, rctWindow.top, APP_WIDTH, APP_HEIGHT, TRUE);
		CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_ON,MF_CHECKED);
		CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_HIDE,MF_UNCHECKED);
	}
	else {
		MoveWindow(hWnd, rctWindow.left, rctWindow.top, APP_WIDTH, iChildHeight + 42, TRUE);
		CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_ON,MF_UNCHECKED);
		CheckMenuItem(GetSubMenu(GetMenu(hWnd),1),ID_DEBUG_HIDE,MF_CHECKED);
	}
	SetDlgItemText(hWndDlg, IDC_AUTO_STATUS, "Initialising");

	//Connect To CSI First
	ec.notify(CSIClientNotify);
	switch (ec.connect())
	{
	case CONNECTED: 
		Debug("Connected OK to CSI");
		/* note: this registration is an example */
		SetDlgItemText(hWndDlg, IDC_CSI_STATUS, "Connected OK");
		
		//ec.regtallyrange(80,1,32);
		break;
		
	case CANT_FIND_CSI:
		Debug("Connect failed to CSI");
		SetDlgItemText(hWndDlg, IDC_CSI_STATUS, "CSI connect FAILED");
		SetDlgItemText(hWndDlg, IDC_AUTO_STATUS, "ERROR - in FAIL state");
		blnContinueAutoInit	= FALSE;
		break;
		
	default:
		Debug("Other Error - code %d",ec.getstate());
		Debug("ERROR ERROR - Connect failed to infodriver, code %d",ei.connect(iDevice));
	
		SetDlgItemText(hWndDlg, IDC_INFO_STATUS, "Info connect FAILED");
		SetDlgItemText(hWndDlg, IDC_AUTO_STATUS, "ERROR - in FAIL state");
		blnContinueAutoInit	= FALSE;
	}
	ec.setcounters(&lTXCSI, &lRXCSI);
	
	//Now connect to Infodriver
	if (blnContinueAutoInit == TRUE) {
		ei.notify(InfoNotify);
		switch (ei.connect(iDevice)) // connect to infodriver
		{
		case CONNECTED: 
			Debug("Connected OK to infodriver %d",ei.iDevice);
			SetDlgItemText(hWndDlg, IDC_INFO_STATUS, "Connected OK");
			switch(ei.getmode()){
				case IFMODE_NONE:
					SetDlgItemText(hWndDlg,IDC_INFO_TXRXMODE,"NONE");
					break;
				case IFMODE_TXRX:
					SetDlgItemText(hWndDlg,IDC_INFO_TXRXMODE,"TX/RX");
					break;
				case IFMODE_RXONLY:
					SetDlgItemText(hWndDlg,IDC_INFO_TXRXMODE,"RX Only");
					break;
				case IFMODE_RXONLYBROKEN:
					SetDlgItemText(hWndDlg,IDC_INFO_TXRXMODE,"RX Only Broken");
					break;
			}
			break;
			
		case CANT_FIND_INFODRIVER:
			Debug("ERROR ERROR - Connect failed to infodriver %d",ei.iDevice);
			Debug("ERROR ERROR -  Driver not functioning");
			SetDlgItemText(hWndDlg, IDC_INFO_STATUS, "Info connect FAILED");
			SetDlgItemText(hWndDlg, IDC_AUTO_STATUS, "ERROR - in FAIL state");
			blnContinueAutoInit	= FALSE;
			break;
			
		default:
			Debug("ERROR ERROR - Connect failed to infodriver, code %d",ei.connect(iDevice));
			Debug("ERROR ERROR -  Driver not functioning");
			SetDlgItemText(hWndDlg, IDC_INFO_STATUS, "Info connect FAILED");
			SetDlgItemText(hWndDlg, IDC_AUTO_STATUS, "ERROR - in FAIL state");
			blnContinueAutoInit	= FALSE;
		}
		ei.setcounters(&lTXID, &lRXID);
	}
	else
		return 0;

	if(blnContinueAutoInit == TRUE)
	{
		LoadConfig();

		//Initialise Router Shim
		int iRouter = atoi(sRouter);
		if(iRouter && iRouter== iVisionRouter)
		{
		
			Debug("Our Router dest is on Vision Router - initialise router shimm %d",iRouter);
			rsh = new routerShim(iVisionRouter);
		}
		//Initislise Last Source Helper
		if(iSave_LastSource)
			LastSce = new LastSceRouteHandler();


	}
	else
	{
		
		return 0;
	}
	
	
	
	return 0;
}

//
//  FUNCTION: CloseApp()
//
//  PURPOSE: Things to do when main window is destroyed
//
//  COMMENTS: Called from WM_DESTROY message
//			The listbox debug window is a child of the main, so it will be 
//			destroyed automatically. 
//
void CloseApp(HWND hWnd)
{

	//Delete the routerShim when the app shuts down
	if(rsh)
		delete rsh;
	if(LastSce)
		delete LastSce;
}


//
//  FUNCTION: LoadIni()
//
//  PURPOSE: Assign (global) variables with values from .ini file
//
//  COMMENTS: The [section] name is gotten from a stringtable resource
//			 which defines it. It is the same name as the application, defined by the wizard
//			
//			
void LoadIni(void)
{
	char szFileName[32];
	char szSection [MAX_LOADSTRING];

	//iWorkstation=atoi(r_p("CSI.INI","Network","Workstation","0",FALSE));
	iWorkstation=getWS();
	
	wsprintf(szFileName,"DEV_%03d.ini",iDevice);
	LoadString(hInst, IDS_SECTION, szSection, MAX_LOADSTRING);
	
	/* extract debug and log parameters from ini file */
	fDebug=atoi(r_p(szFileName,szSection,"DebugMode","1",TRUE));
	fDebugHide = fDebug;
	fLog=atoi(r_p(szFileName,szSection,"LogMode","0",TRUE));

	iLastTriggerUsed=0;
	fLastSourceTimeOut=0;
}


/*returns int The workstation number

  brief Function to get the workstation number
  
	First checks to see if %CC_WORKSTATION% is defined
	otherwise returns the WS stored in %WINDIR%\csi.ini
	
	  NOTE: 
	  In BNCSWizard apps the following change should be made to LoadINI()
	  - Replace:
	  iWorkstation=atoi(r_p("CSI.INI","Network","Workstation","0",FALSE));
	  - With:
	  iWorkstation=getWS();
	  - Also add the following to "app_name.h":

int                     getWS(void);
*/
int getWS(void)
{
	char* szWS = getenv( "CC_WORKSTATION" );
	
	if(szWS){
		return atoi(szWS);
	}
	else{
		return atoi(r_p("CSI.INI","Network","Workstation","0",FALSE));
	}
}


/*!
\returns char* Pointer to data obtained
\param char* file The file to read from
\param char* section The section - [section]
\param char* entry The entry - entry=
\param char* defval The default value to return if not found
\param BOOL fWrite Flag - write the default value to the file

  \brief Function to read one item of user data from an INI file
  
	First checks to see if %CC_ROOT% and %CC_SYSTEM% are defined
	If so the config files in %CC_ROOT%\%CC_SYSTEM%\config\system are used
	Otherwise the config files in %WINDIR% are used
*/
char* r_p(char* file, char* section, char* entry, char* defval, BOOL fWrite)
{
	char szPath[256];          
	char* szCCRoot = getenv( "CC_ROOT" );
	char* szCCSystem = getenv( "CC_SYSTEM" );
	
	if(szCCRoot && szCCSystem){
		//sprintf(szPath, "%s\\%s\\system\\config\\%s", szCCRoot, szCCSystem, file);
		//NOTE: replace the above line with the one below when V4CSI is fixed
		sprintf(szPath, "%s\\%s\\config\\system\\%s", szCCRoot, szCCSystem, file);
	}
	else {
		strcpy(szPath, file);
	}
	
	GetPrivateProfileString(section, entry, defval, szResult, sizeof(szResult), szPath);
	if (fWrite)
		w_p(file,section,entry,szResult);
	
	return szResult;
}

/*!
\returns void 
\param char* file The file to read from
\param char* section The section - [section]
\param char* entry The entry - entry=
\param char* setting The value to write - =value

  \brief Function to write one item of user data to an INI file
  
	First checks to see if %CC_ROOT% and %CC_SYSTEM% are defined
	- If so the config files in %CC_ROOT%\%CC_SYSTEM%\config\system are used
	- Otherwise the config files in %WINDIR% are used
*/

void w_p(char* file, char* section, char* entry, char* setting)

{
	
	char szPath[256];          
	char* szCCRoot = getenv( "CC_ROOT" );
	char* szCCSystem = getenv( "CC_SYSTEM" );
	if(szCCRoot && szCCSystem){
		//sprintf(szPath, "%s\\%s\\system\\config\\%s", szCCRoot, szCCSystem, file);
		//NOTE: replace the above line with the one below when V4CSI is fixed
		sprintf(szPath, "%s\\%s\\config\\system\\%s", szCCRoot, szCCSystem, file);
	}
	
	else {
		strcpy(szPath, file);
	}
	
	WritePrivateProfileString(section, entry, setting, szPath);
}

//
//  FUNCTION: UpdateCounters()
//
//  PURPOSE: Writes current counter values to child dialog
//
//  COMMENTS: 
//				
//			
//			
void UpdateCounters(void) {
	char szBuf[32];
		//Update CSI Message Count
	wsprintf(szBuf, "%08d", lTXCSI);
	SetDlgItemText(hWndDlg, IDC_CSI_TX, szBuf);
	wsprintf(szBuf, "%08d", lRXCSI);
	SetDlgItemText(hWndDlg, IDC_CSI_RX, szBuf);

	//Update Infodriver External Message Count
	wsprintf(szBuf, "%08d", lTXID);
	SetDlgItemText(hWndDlg, IDC_ID_TX, szBuf);
	wsprintf(szBuf, "%08d", lRXID);
	SetDlgItemText(hWndDlg, IDC_ID_RX, szBuf);
}

//
//  FUNCTION: Debug()
//
//  PURPOSE: Writes debug information to the listbox
//
//  COMMENTS: The function works the same way as printf
//				example: Debug("Number=%d",iVal);
//			
//			
void Debug(LPCSTR szFmt, ...)
{
	if (fDebug)
	{
		LPSTR szDebug=(LPSTR)malloc(0x10000);
		va_list argptr;
		
		va_start(argptr,szFmt);
		vsprintf(szDebug,szFmt,argptr);
		va_end(argptr);
		
		if (strlen(szDebug) > 160)
			szDebug[160]=0; //Truncate long debug messages

		//added OutputDebugString
		OutputDebugString(szDebug);
		
		SendMessage(hWndList, LB_ADDSTRING,0,(LPARAM) szDebug);	//Add message
		long lCount = SendMessage(hWndList,LB_GETCOUNT,0,0);	//Get List Count
		if (lCount > MAX_LB_ITEMS)
		{
			SendMessage(hWndList, LB_DELETESTRING, 0, 0);	//Delete item
			lCount--;
		}
		SendMessage(hWndList, LB_SETTOPINDEX, (WPARAM) lCount - 1, 0);	//Set Top Index
		free((PVOID)szDebug);
	}
}

//
//  FUNCTION: Log()
//
//  PURPOSE: Writes information to the log file
//
//  COMMENTS: The function works the same way as printf
//				example: Debug("Number=%d",iVal);
//			
//			
void Log(LPCSTR szFmt, ...)
{
	char szLogFile[40];
	
	if (fLog)
	{
		char tBuffer[9];
		char szDate[16];
		FILE *fp;
		LPSTR szLog=(LPSTR)malloc(0x10000);
		va_list argptr;
		struct tm *newtime;
		time_t long_time;
		
		va_start(argptr,szFmt);
		vsprintf(szLog,szFmt,argptr);
		va_end(argptr);
		
		time( &long_time );                // Get time as long integer. 
		newtime = localtime( &long_time ); // Convert to local time. 
		_strtime( tBuffer );
		sprintf(szDate, "%04d%02d%02d", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday);
		
		wsprintf(szLogFile, "c:\\bncslogs\\%s_child2_%d.log", szDate, iDevice);
		Debug(szLogFile);
		if (fp = fopen(szLogFile, "a"))
		{
			fprintf(fp, tBuffer);
			fprintf(fp, " - ");
			fprintf(fp, szLog);
			fprintf(fp, "\r\n");
			fclose(fp);
		}
		
		free((PVOID)szLog);
	}
}


//
// Function name	: SplitString
// Description	   : Split a delimited string to an array of pointers to strings
// Return type		: int number of elements returned
//
//----------------------------------------------------------------------------//
// Takes a string and splits it up creating an array of pointers to the start //
// of the sections delimted by the array of specified char delimiters         //
// the delimter characters in "string" are overwritten with NULLs             //
// Usage:                                                                     //
// char szString[] = "1,2|3'4,5,6,7,";                                        //
// char delim[] = {',', '|', '\'', ',', ',', ',', ',',};                      //
// UINT count=7;                                                              //
// char *pElements[7];                                                        //
// int iLen;                                                                  //
//	iLen = SplitString( szString, delim, 7, pElements);                        //
//                                                                            //
// NOTE: This funcion works differently to strtok in that consecutive         //
// delimiters are not overlooked and so a NULL output string is possible      //
// i.e. a string                                                              //
//    hello,,dave                                                             //
// where ,,, is the delimiter will produce 3 output strings the 2nd of which  //
// will be NULL                                                               //
//----------------------------------------------------------------------------//
int SplitString(char *string, char *delim, UINT count, char **outarray )
{
	UINT x;
	UINT y;
	UINT len;										// length of the input string
	static char *szNull = "";				// generic NULL output string
	int delimlen;
	int dp;
	
	len = strlen( string );
	delimlen = strlen( delim );
	
	if(!len)										// if the input string is a NULL then set all the output strings to NULL
	{
		for (x = 0 ; x < count; x++ )
			outarray[x] = szNull;
		return 0;
	}
	
	outarray[0] = string;					// set the 1st output string to the beginning of the string
	
	for( x = 0,y = 1 ; (x < len) && (y < count); x++ )
	{
		if( delimlen < 2 )
			dp = 1;
		else
			dp = y;
		if(string[x] == delim[dp-1])
		{
			string[ x ] = '\0';
			if((x+1) < len)					// if there is another string following this one....
			{
				outarray[ y ] = &string[x+1];
				y++;								// increment the number of assigned buffer
			}
			else
			{
				outarray[ y ] = szNull;
			}
		}
	}
	
	x = y;
	while( x < count )
		outarray[x++] = szNull;
	return y;									// return the number of strings allocated
}
