#include "StdAfx.h"
#include "ApiHelperGobi.h"
#include <GobiAPI.h>
#include "GobiConnectionMgmtApi.h"
#include "StatusCtrl.h"
#include "FuncList.h"
#include "GobiApiDev.h"
#include "GobiApiDms.h"
#include "GobiApiNas.h"
#include "GobiApiWds.h"
#include "GobiApiWms.h"
#include "GobiApiOma.h"
#include "GobiApiPds.h"
#include "GobiApiFwMgmt.h"
#include "GobiApiRms.h"
#include "GobiApiCat.h"
#include "GobiApiSwiOma.h"
#include "GobiApiSar.h"

CApiHelperGobi::CApiHelperGobi(void)
{
	WCHAR szSecondApiName[MAX_PATH] = L"GobiConnectionMgmt.dll";
	CString szRegPath = L"";
	szRegPath.Format(L"%s\\%s", REGKEY_SWI, REGKEY_AppName);
	DWORD dwUseSecondApi = 0;
	m_hQCApiDll = NULL;
	
	HKEY hKey = NULL;
	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0, KEY_READ, &hKey))
	{
		DWORD dwSize = MAX_PATH-1;

		if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGVAL_SecondApi, NULL, NULL, (LPBYTE)&szSecondApiName, &dwSize))
		{
			TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Over-riding secondary API: %s", szSecondApiName);
		}

		dwSize = sizeof(DWORD);
		if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGVAL_UseSecond, NULL, NULL, (LPBYTE)&dwUseSecondApi, &dwSize))
		{
			TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Using secondary API: %i", dwUseSecondApi);
		}

		if (dwUseSecondApi)
		{
			m_hQCApiDll = LoadLibrary(szSecondApiName);

			if (!m_hQCApiDll)
				TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Failed to load Qualcomm DLL");
		}

		RegCloseKey(hKey);
	}

	m_pDev = new CGobiApiDev(m_hQCApiDll);
	m_pNas = new CGobiApiNas(m_hQCApiDll);
	m_pWds = new CGobiApiWds(m_hQCApiDll);
	m_pDms = new CGobiApiDms(m_hQCApiDll);
	m_pWms = new CGobiApiWms(m_hQCApiDll);
	m_pFwm = new CGobiApiFwMgmt(m_hQCApiDll);
	m_pOma = new CGobiApiOma(m_hQCApiDll);
	m_pPds = new CGobiApiPds(m_hQCApiDll);
	m_pRms = new CGobiApiRms(m_hQCApiDll);
	m_pCat = new CGobiApiCat(m_hQCApiDll);
	m_pSwiOma = new CGobiApiSwiOma(m_hQCApiDll);
	m_pSar = new CGobiApiSar(m_hQCApiDll);
}

CApiHelperGobi::~CApiHelperGobi(void)
{
	// Un-initialize API
	QCWWANDisconnect();

	// Un-initialize Qualcomm API
	if (m_hQCApiDll)
		GetProcAddress_W(m_hQCApiDll, L"QCWWANDisconnect")();

	// destroy objects
	delete m_pDev;
	delete m_pDms;
	delete m_pNas;
	delete m_pWds;
	delete m_pWms;
	delete m_pFwm;
	delete m_pOma;
	delete m_pPds;
	delete m_pRms;
	delete m_pCat;
	delete m_pSwiOma;
	delete m_pSar;
}

BOOL CApiHelperGobi::GetAvailFuncList(CFuncList* pFuncList)
{
	m_pDev->GetAvailFuncList(pFuncList);
	m_pNas->GetAvailFuncList(pFuncList);
	m_pDms->GetAvailFuncList(pFuncList);
	m_pWds->GetAvailFuncList(pFuncList);
	m_pWms->GetAvailFuncList(pFuncList);
	m_pFwm->GetAvailFuncList(pFuncList);
	m_pOma->GetAvailFuncList(pFuncList);
	m_pPds->GetAvailFuncList(pFuncList);
	m_pRms->GetAvailFuncList(pFuncList);
	m_pCat->GetAvailFuncList(pFuncList);
	m_pSwiOma->GetAvailFuncList(pFuncList);
	m_pSar->GetAvailFuncList(pFuncList);

	return TRUE;
}

BOOL CApiHelperGobi::Initialize(CWnd* pParent)
{
	if (m_bInitialized)
		return TRUE;

	TBD_FUNCTION(CApiHelperGobi::Initialize);

	// validate input params
	if (!pParent)
	{
		TBD_OUTPUT(TBDCT_ALWAYS, TBDOL_ERROR, L"Invalid parameter");
		return FALSE;
	}

	return CApiHelper::Initialize(pParent);
}

BOOL CApiHelperGobi::Uninitialize()
{
	TBD_FUNCTION(CApiHelperGobi::Uninitialize);

	m_bInitialized = FALSE;

	// Un-initialize Qualcomm API
	if (m_hQCApiDll)
	{
		TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Un-initializing QC DLL");
		GetProcAddress_W(m_hQCApiDll, L"QCWWANDisconnect")();
	}

	TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Un-initializing SWI DLL");
	return (QCWWANDisconnect() == 0)?TRUE:FALSE;
}

BOOL CApiHelperGobi::ExecuteFunctions(CFuncList* pFuncList)
{
	TBD_FUNCTION(CApiHelperGobi::ExecuteFunctions);

	// clear function list
	m_FuncList.RemoveAll();

	// copy list of functions to execute and release GUI thread
	pFuncList->Copy(&m_FuncList);

	// Set action event and release caller thread.  
	// Worker thread does all the API calls.
	return SetEvent(m_hActionToDo);
}

BOOL CApiHelperGobi::Execute()
{
	TBD_FUNCTION(CApiHelperGobi::Execute);

	// Pass the function list to all the services.  Each service will execute their own functions

	// TODO: Is order important here?  Do we want to abort if an error occurs along the way?
	UINT nNasTotal =0, nDmsTotal = 0, nWdsTotal = 0, nFwmTotal = 0, nWmsTotal = 0;
	UINT nOmaTotal = 0, nPdsTotal = 0, nRmsTotal = 0, nCatTotal =0, nDevTotal = 0;
	UINT nSwiOmaTotal = 0, nSarTotal = 0;

	UINT nDevErrors = m_pDev->ExecuteFunctions(&m_FuncList, nDevTotal);
	UINT nNasErrors = m_pNas->ExecuteFunctions(&m_FuncList, nNasTotal);
	UINT nDmsErrors = m_pDms->ExecuteFunctions(&m_FuncList, nDmsTotal);
	UINT nWdsErrors = m_pWds->ExecuteFunctions(&m_FuncList, nWdsTotal);
	UINT nWmsErrors = m_pWms->ExecuteFunctions(&m_FuncList, nWmsTotal);
	UINT nFwmErrors = m_pFwm->ExecuteFunctions(&m_FuncList, nFwmTotal);
	UINT nOmaErrors = m_pOma->ExecuteFunctions(&m_FuncList, nOmaTotal);
	UINT nPdsErrors = m_pPds->ExecuteFunctions(&m_FuncList, nPdsTotal);
	UINT nRmsErrors = m_pRms->ExecuteFunctions(&m_FuncList, nRmsTotal);
	UINT nCatErrors = m_pCat->ExecuteFunctions(&m_FuncList, nCatTotal);
	UINT nSwiOmaErrors = m_pSwiOma->ExecuteFunctions(&m_FuncList, nSwiOmaTotal);
	UINT nSarErrors = m_pSar->ExecuteFunctions(&m_FuncList, nSarTotal);

	// Display summary
	ADDSTATUS(L"Execution complete", STATUSMSG_Status);

	CString strTemp;
	if (nDevTotal)
	{
		strTemp.Format(L"DEV total: %i, errors: %i", nDevTotal, nDevErrors);
		ADDSTATUS(strTemp, 0==nDevErrors?STATUSMSG_Status:STATUSMSG_Error);
	}

	if (nNasTotal)
	{
		strTemp.Format(L"NAS total: %i, errors: %i", nNasTotal, nNasErrors);
		ADDSTATUS(strTemp, 0==nNasErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nDmsTotal)
	{
		strTemp.Format(L"DMS total: %i, errors: %i", nDmsTotal, nDmsErrors);
		ADDSTATUS(strTemp, 0==nDmsErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nWdsTotal)
	{
		strTemp.Format(L"WDS total: %i, errors: %i", nWdsTotal, nWdsErrors);
		ADDSTATUS(strTemp, 0==nWdsErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nWmsTotal)
	{
		strTemp.Format(L"WMS total: %i, errors: %i", nWmsTotal, nWmsErrors);
		ADDSTATUS(strTemp, 0==nWmsErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nFwmTotal)
	{
		strTemp.Format(L"FWM total: %i, errors: %i", nFwmTotal, nFwmErrors);
		ADDSTATUS(strTemp, 0==nFwmErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nOmaTotal)
	{
		strTemp.Format(L"OMA total: %i, errors: %i", nOmaTotal, nOmaErrors);
		ADDSTATUS(strTemp, 0==nOmaErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nPdsTotal)
	{
		strTemp.Format(L"PDS total: %i, errors: %i", nPdsTotal, nPdsErrors);
		ADDSTATUS(strTemp, 0==nPdsErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nRmsTotal)
	{
		strTemp.Format(L"RMS total: %i, errors: %i", nRmsTotal, nRmsErrors);
		ADDSTATUS(strTemp, 0==nRmsErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	if (nCatTotal)
	{
		strTemp.Format(L"CAT total: %i, errors: %i", nCatTotal, nCatErrors);
		ADDSTATUS(strTemp, 0==nCatErrors?STATUSMSG_Status:STATUSMSG_Error);
	}

	if (nSwiOmaTotal)
	{
		strTemp.Format(L"SWI-OMA total: %i, errors: %i", nSwiOmaTotal, nSwiOmaErrors);
		ADDSTATUS(strTemp, 0==nSwiOmaErrors?STATUSMSG_Status:STATUSMSG_Error);
	}

	if (nSarTotal)
	{
		strTemp.Format(L"SAR total: %i, errors: %i", nSarTotal, nSarErrors);
		ADDSTATUS(strTemp, 0==nSwiOmaErrors?STATUSMSG_Status:STATUSMSG_Error);
	}
	
	return TRUE;
}

void CApiHelperGobi::DeviceRemovalCallback(ULONG nStatus)
{
	CString strTemp;
	strTemp.Format(L"Device Removal 0x%04x", nStatus);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  

	ADDSTATUS(L"Calling FuncGetRFInfo from callback thread", STATUSMSG_Send);

	BYTE nSize = 10;
	const int MAX_BUFFER_SIZE = 120;
	BYTE  arParam[MAX_BUFFER_SIZE];  // RF info instance elements are comprised for three ULONGs (so this buffer holds 10 elements)

	// clear structure
	memset(&arParam, 0, MAX_BUFFER_SIZE);

	// call Sierra interface
	ULONG nRet = GetRFInfo(&nSize, arParam);

	// display output in GUI
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Error:STATUSMSG_Receive);

	if (m_pParent)
		m_pParent->PostMessage(WM_USER_DeviceRemoval, nStatus, NULL);
}