// GobiTestAppDlg.cpp : implementation file
//

#include "stdafx.h"
#include <GobiAPI.h>
#include "GobiTestApp.h"
#include "GobiTestAppDlg.h"
#include "StatusCtrl.h"
#include "ApiHelperGobi.h"
#include "ToolboxHelper.h"
#include "FuncList.h"
#include "GobiConnectionMgmtAPI.h"
#include "SwiWwanCmApi.h"

#define STR_Component	_T("GobiTestApp")
#define STR_LogFile		_T("GobiTestApp.txt")

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define TIMER_DeviceSearch		WM_USER + 0x1000
#define WM_USER_CheckState		WM_USER + 0x1001
#define TIMEOUT_DeviceSearch	1000
#define MAX_FindModemAttempts	5

// CGobiTestAppDlg dialog


CGobiTestAppDlg::CGobiTestAppDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CGobiTestAppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pApiHelper = NULL;
	m_nFindModemCounter = 0;
	m_bSelectAllFuncs = FALSE;
}

void CGobiTestAppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BTN_Execute, m_btnExecute);
	DDX_Control(pDX, IDC_LST_Status, m_ctrStatus);
	DDX_Control(pDX, IDC_TRE_CmdAvail, m_ctrCmdsAvail);
	DDX_Control(pDX, IDC_LST_FuncParams, m_ctrFuncParams);
	DDX_Control(pDX, IDC_BTN_CANCEL, m_btnCancel);
}

BEGIN_MESSAGE_MAP(CGobiTestAppDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_WM_DESTROY()
	ON_WM_TIMER()
	ON_MESSAGE(WM_USER_ExecutionComplete, OnExecutionComplete)
	ON_MESSAGE(WM_USER_StatusUpdate, OnStatusUpdate)
	ON_MESSAGE(WM_USER_DeviceRemoval, OnNotifyDeviceRemoval)
	ON_BN_CLICKED(IDC_BTN_Execute, &CGobiTestAppDlg::OnBnClickedBtnExecute)
	ON_NOTIFY(NM_CLICK, IDC_LST_FuncParams, &CGobiTestAppDlg::OnNMClickLstFuncParams)
	ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LST_FuncParams, &CGobiTestAppDlg::OnLvnEndLabelEditLstFuncParams)
	ON_NOTIFY(TVN_SELCHANGED, IDC_TRE_CmdAvail, &CGobiTestAppDlg::OnTvnSelchangedTreCmdavail)
	ON_NOTIFY(NM_CLICK, IDC_TRE_CmdAvail, &CGobiTestAppDlg::OnNMClickTreCmdavail)
	ON_NOTIFY(TVN_KEYDOWN, IDC_TRE_CmdAvail, &CGobiTestAppDlg::OnTvnKeydownTreCmdavail)
	ON_BN_CLICKED(IDC_BTN_CANCEL, &CGobiTestAppDlg::OnBnClickedBtnCancel)
END_MESSAGE_MAP()


// CGobiTestAppDlg message handlers

BOOL CGobiTestAppDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	STRUCT_TBD_Logging sLogging;
	sLogging.bTbdAllFunc = true;
	sLogging.bTbdAllMem = true;
	sLogging.bTbdInfo = true;
	sLogging.bTbdRead = false;
	sLogging.eLevel = TBDOL_INFORMATION;
	sLogging.hKey = HKEY_CURRENT_USER;
	sLogging.nMaxLogSize = MAX_LogFileSize;
	sLogging.bMainApp = true;
	_tcscpy_s(sLogging.strFileName, MAX_PATH, STR_Component);

	// Enable TBD logging
	LoggingInit(STR_LogFile, STR_Component, true, &sLogging);

	CStatusCtrl::Instance(&m_ctrStatus);
	ADDSTATUS(L"Initializing", STATUSMSG_Status);
	SetGuiState(GUISTATE_Uninitialized);

	m_UiFuncParamsCtrl.Initialize(&m_ctrFuncParams);

	m_pApiHelper = new CApiHelperGobi;

	if (!m_pApiHelper)
	{
		TBD_OUTPUT(TBDCT_ALWAYS, TBDOL_ERROR, L"Failed to create GobiApiHelper");
		return FALSE;
	}

	if (!m_pApiHelper->GetAvailFuncList(&m_lstAvailFuncs))
	{
		TBD_OUTPUT(TBDCT_ALWAYS, TBDOL_ERROR, L"Failed to get list of available functions");
		return FALSE;
	}

	m_UiCmdsAvailCtrl.Initialize(&m_ctrCmdsAvail, &m_lstAvailFuncs);
	SetTimer(TIMER_DeviceSearch, TIMEOUT_DeviceSearch, NULL);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CGobiTestAppDlg::OnPaint()
{
#ifndef UNDER_CE
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
#else
	CDialog::OnPaint();
#endif
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CGobiTestAppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CGobiTestAppDlg::OnDestroy()
{
	CDialog::OnDestroy();

	if (m_pApiHelper)
	{
		m_pApiHelper->Uninitialize();
		delete m_pApiHelper;
	}

	LoggingDeinit();
	CStatusCtrl::DeleteInstance();

	// TODO: Add your message handler code here
}

void CGobiTestAppDlg::OnTimer(UINT_PTR nIDEvent)
{
	switch (nIDEvent)
	{
	case TIMER_DeviceSearch:
		if (m_pApiHelper->Initialize(this))
		{
			ADDSTATUS(L"Ready; use API functions to connect to device", STATUSMSG_Status);
			KillTimer(TIMER_DeviceSearch);

			// check to see if any functions are selected
			if (0 <m_lstSelectedFuncs.GetCount())
				SetGuiState(GUISTATE_FunctionSelected);
			else
				// device found, wait for user selection
				SetGuiState(GUISTATE_Ready);

			m_nFindModemCounter = 0;
		}
		else
		{
			m_pApiHelper->Uninitialize();
			m_nFindModemCounter++;

			// we want to keep searching frequently, but only display an error message occasionally
			if (m_nFindModemCounter  == MAX_FindModemAttempts)
			{
				ADDSTATUS(L"Unable to find device", STATUSMSG_Error);
				m_nFindModemCounter = 0;
			}
		}
		break;
	default:
		break;
	}

	CDialog::OnTimer(nIDEvent);
}

void CGobiTestAppDlg::SetGuiState(TYPE_GUI_STATE eState)
{
	switch (eState)
	{
		// API initialized
		case GUISTATE_Ready:
			m_btnExecute.EnableWindow(TRUE);
			m_ctrCmdsAvail.EnableWindow(TRUE);
			m_ctrFuncParams.EnableWindow(FALSE);
			m_btnCancel.EnableWindow(FALSE);
			break;
		case GUISTATE_FunctionSelected:
			m_btnExecute.EnableWindow(TRUE);
			m_ctrCmdsAvail.EnableWindow(TRUE);
			m_btnCancel.EnableWindow(FALSE);
			break;
		case GUISTATE_Executing:
			m_btnExecute.EnableWindow(FALSE);
			m_ctrCmdsAvail.EnableWindow(FALSE);
			m_ctrFuncParams.EnableWindow(FALSE);
			m_btnCancel.EnableWindow(TRUE);
			break;
		// API not initialized
		case GUISTATE_Uninitialized:
		default:
			m_btnExecute.EnableWindow(FALSE);
			m_ctrCmdsAvail.EnableWindow(FALSE);
			m_ctrFuncParams.EnableWindow(FALSE);
			m_btnCancel.EnableWindow(FALSE);
			break;
	}
}

// This function is called whenever the user clicks the Execute button
void CGobiTestAppDlg::OnBnClickedBtnExecute()
{
	SetGuiState(GUISTATE_Executing);

	// get list of selected functions
	m_UiCmdsAvailCtrl.GetSelectedFunctions(&m_lstSelectedFuncs);

	// copy parameters from master list
	CParamList sParams;

	for (int i=0; i<m_lstSelectedFuncs.GetCount(); i++)
	{
		if (m_lstAvailFuncs.GetFuncParams(m_lstSelectedFuncs.GetFunctionName(i), sParams))
			m_lstSelectedFuncs.SetFuncParams(m_lstSelectedFuncs.GetFunctionName(i), &sParams);
	}

	// execute list of selected functions
	m_pApiHelper->ExecuteFunctions(&m_lstSelectedFuncs);
}

// This function is triggered by the Execution Complete event
LRESULT CGobiTestAppDlg::OnExecutionComplete(WPARAM, LPARAM)
{
	SetGuiState(GUISTATE_FunctionSelected);
	return S_OK;
}

// Triggered by update status event
LRESULT CGobiTestAppDlg::OnStatusUpdate(WPARAM, LPARAM)
{
	CStatusCtrl::Instance()->UpdateStatus();

	return 0;
}

// Triggered by device removal notification from API helper
LRESULT CGobiTestAppDlg::OnNotifyDeviceRemoval(WPARAM, LPARAM)
{
	if (m_pApiHelper)
	{
		m_pApiHelper->Uninitialize();
	}

	ADDSTATUS(L"Re-initializing", STATUSMSG_Status);
	SetTimer(TIMER_DeviceSearch, TIMEOUT_DeviceSearch*3, NULL);

	return 0;
}

//////////////////////////////////////////////////
// Commands Available control handlers

// This function is called whenever a new function selection has been made in the Available control
void CGobiTestAppDlg::OnTvnSelchangedTreCmdavail(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNREFERENCED_PARAMETER(pNMHDR);
//	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;

	// Display parameters if applicable
	HTREEITEM pSelection = m_ctrCmdsAvail.GetSelectedItem();

	// Do not attempt to look for parameter list if parent item
	if (pSelection && !m_ctrCmdsAvail.GetChildItem(pSelection))
	{
		CString szFuncName = m_ctrCmdsAvail.GetItemText(pSelection);

		CParamList sParamList;
		if (m_lstAvailFuncs.GetFuncParams(szFuncName, sParamList) && sParamList.GetCount())
		{
			m_UiFuncParamsCtrl.Display(&sParamList);	// display parameters
			m_ctrFuncParams.EnableWindow(TRUE);		// enable control for editing
		}
		else
		{
			m_UiFuncParamsCtrl.Display(NULL);		// clear control
			m_ctrFuncParams.EnableWindow(FALSE);	// disable control
		}	
	}
	else
	{
		m_UiFuncParamsCtrl.Display(NULL);			// clear control
		m_ctrFuncParams.EnableWindow(FALSE);		// disable control
	}
}


// This function is called whenever the user clicks on the Commands Available control
void CGobiTestAppDlg::OnNMClickTreCmdavail(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: Add your control notification handler code here
	*pResult = 0;

	// KB261289 - Check box notifications are not sent.  If the user has clicked the check box, 
	// we need to check the state again since NM_CLICK is generated before the check box
	// selection state is updated.

	// Check to see if modification were made to a check box of a parent item
	CPoint pt; 
	GetCursorPos(&pt); 
	m_ctrCmdsAvail.ScreenToClient(&pt); 
	UINT uFlags; 

	HTREEITEM ht = m_ctrCmdsAvail.HitTest(pt, &uFlags);

	switch (uFlags)
	{
		case TVHT_ONITEMSTATEICON:
			// User clicked on check box.

			// Check to see if it was a parent item.
			if (m_ctrCmdsAvail.GetChildItem(ht))
			{
				// User clicked on a parent item.  Toggle child settings.  Note that the check state does not
				// get updated right away.
				m_UiCmdsAvailCtrl.SelectAllChildren(ht, !m_ctrCmdsAvail.GetCheck(ht));
			}
			
			break;
		default:
			// user clicked on something else, do nothing
			break;
	}

	// If the user clicked on the same item, we want to re-enable parameter list
	OnTvnSelchangedTreCmdavail(pNMHDR, pResult);
}

void CGobiTestAppDlg::OnTvnKeydownTreCmdavail(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTVKEYDOWN pTVKeyDown = reinterpret_cast<LPNMTVKEYDOWN>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;

	// Space bar can be used to toggle check boxes.  Check box updates are not notified (KB261289).
	// Validated selected functions on space bar press.
	if (pTVKeyDown->wVKey == VK_SPACE)
	{
		// Check to see if it was a parent item.
		HTREEITEM pItem = m_ctrCmdsAvail.GetSelectedItem();

		if (m_ctrCmdsAvail.GetChildItem(pItem))
		{
			// User selected a parent item.  Toggle child settings.  Note that the check state does not
			// get updated right away.
			m_UiCmdsAvailCtrl.SelectAllChildren(pItem, !m_ctrCmdsAvail.GetCheck(pItem));
		}

		// Check to see if any functions are actually selected
		//PostMessage(WM_USER_CheckState, 0, (LPARAM)pNMHDR);
	}

}

//////////////////////////////////////////////////
// Function Parameter control handlers

// User has clicked in the Function Parameter list control
void CGobiTestAppDlg::OnNMClickLstFuncParams(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: Add your control notification handler code here
	*pResult = 0;

	m_UiFuncParamsCtrl.OnUserClick(pNMHDR, pResult);
}

// A Function Parameter control item has just been updated
void CGobiTestAppDlg::OnLvnEndLabelEditLstFuncParams(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;

	// Get selected function from the control
	HTREEITEM pSelection = m_ctrCmdsAvail.GetSelectedItem();

	if (pSelection)
	{
		// Get the selected function name
		CString szFuncName = m_ctrCmdsAvail.GetItemText(pSelection);

		// Local variable to store the parameter list
		CParamList sParamList;

		// Get original parameters for the selected function
		if (m_lstAvailFuncs.GetFuncParams(szFuncName, sParamList) && sParamList.GetCount())
		{
			// Update parameters with user input
			CString szLabel, szValue;

			// Only one value can be updated at a time, so get the label/value in question
			if (!sParamList.GetAt(pDispInfo->item.iItem, szLabel, szValue))
				return;
			// Update the value
			sParamList.Add(szLabel, pDispInfo->item.pszText);
			// Update the original function list with the new parameters
			m_lstAvailFuncs.SetFuncParams(szFuncName, &sParamList);
			// display updated parameters
			m_UiFuncParamsCtrl.Display(&sParamList);	
		}
	}
}


void CGobiTestAppDlg::OnBnClickedBtnCancel()
{
    // Remove all the functions selected 
    CFuncList* pCurrentFuncList = NULL;
    pCurrentFuncList = m_pApiHelper->GetCurrentFuncList();
    if(pCurrentFuncList)
        pCurrentFuncList->RemoveAll();

    QCWWANCancel();
    //Restore the button status
    SetGuiState(GUISTATE_Ready);
}
