// CStatusCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "GobiTestApp.h"
#include "StatusCtrl.h"

#define MAX_LinesStatus	10000
#define COL_Time		0
#define COL_Type		1
#define COL_Msg			2

//
// Singleton.
//
CStatusCtrl* CStatusCtrl::s_Instance = NULL;

CStatusCtrl::CStatusCtrl(CWnd* pParent /*=NULL*/)
{
//	m_pParent = NULL;
	m_nNumberLines = 0;
	m_bAutoScroll = TRUE;
	InitializeCriticalSection(&m_csStatus);
	m_lstStatusItems.RemoveAll();
}

CStatusCtrl* CStatusCtrl::Instance(CListCtrl* pStatusCtrl)
{
	if (!s_Instance && pStatusCtrl)
	{
		s_Instance = new CStatusCtrl;

		if (s_Instance)
		{
			if (!s_Instance->Initialize(pStatusCtrl))
			{
				delete s_Instance;
				s_Instance = NULL;
			}
		}
	}

	return s_Instance;
}

CStatusCtrl* CStatusCtrl::Instance()
{
	if (!s_Instance)
	{
		// TODO
	}

	return s_Instance;
}

void CStatusCtrl::DeleteInstance()
{
	if (s_Instance)
	{
		delete s_Instance;
		s_Instance = NULL;
	}
}

CStatusCtrl::~CStatusCtrl()
{
	DeleteCriticalSection(&m_csStatus);
}

BOOL CStatusCtrl::Initialize(CListCtrl* pStatusCtrl)
{
	if (!pStatusCtrl)
	{
		TBD_OUTPUT(TBDCT_ALWAYS, TBDOL_ERROR, _T("CStatusCtrl::Initialize - Invalid Parameter"));
		return FALSE;
	}

	m_pStatusCtrl = pStatusCtrl;

#ifndef UNDER_CE
#define COL_WIDTH_TIME	75
#else
// do not display Time column on WinCE platforms (real estate issue)
#define COL_WIDTH_TIME	1
#endif

	// Format status window control
	m_pStatusCtrl->InsertColumn(COL_Time, L"Time", LVCFMT_CENTER, COL_WIDTH_TIME);
	m_pStatusCtrl->InsertColumn(COL_Type, L"Type", LVCFMT_CENTER, 30);
	m_pStatusCtrl->InsertColumn(COL_Msg, L"Message", LVCFMT_LEFT, 364);

	return TRUE;
}

BOOL CStatusCtrl::AddStatus(const WCHAR* pszStatus, TYPE_STATUS_MSG eType /* = STATUSMSG_Action */)
{
	// May be called from multiple threads.
	EnterCriticalSection(&m_csStatus);

	// cache info to be updated later by GUI
	STRUCT_StatusItem sStatusItem;
	sStatusItem.eMsgType = eType;
	sStatusItem.szStatusMsg = pszStatus;

	m_lstStatusItems.AddTail(sStatusItem);

	// Tell GUI to update status window
	m_pStatusCtrl->GetParent()->PostMessage(WM_USER_StatusUpdate);

	LeaveCriticalSection(&m_csStatus);

	return TRUE;
}

////////////////////////////////////////////////////////////////////////////////
//
//   Function   :	GetLocalTimeFormat
//
//   Description:	Format current local time in HH:MM:SS.sss format
//
//   Arguments  :	[IN] psBuffer - buffer for the output formatted string
//					[IN] sizeBuffer - size of psBuffer
//
//   Returns:   :	true if successfully formatted, false otherwise
//
//   Comments   :	
//
////////////////////////////////////////////////////////////////////////////////
bool CStatusCtrl::GetLocalTimeFormat(LPTSTR psBuffer, size_t sizeBuffer)
{
	SYSTEMTIME stLocal;
	GetLocalTime(&stLocal);

#ifndef UNDER_CE
	return -1 != _stprintf_s(psBuffer, sizeBuffer, _T("%02d:%02d:%02d.%03d"),
		stLocal.wHour, stLocal.wMinute, stLocal.wSecond, stLocal.wMilliseconds);
#else
	return -1 != _stprintf(psBuffer, _T("%02d:%02d:%02d.%03d"),
		stLocal.wHour, stLocal.wMinute, stLocal.wSecond, stLocal.wMilliseconds);
#endif
}

void CStatusCtrl::UpdateStatus(void)
{
	EnterCriticalSection(&m_csStatus);

	TCHAR szTime[64];
	TBD_OUTPUT_LEVEL eTbdOutputLevel = TBDOL_INFORMATION;
	CString szType;
	STRUCT_StatusItem pStatusItem; 

	// update all status items in cache
	while (m_lstStatusItems.GetSize())
	{
		// get status item from cache
		pStatusItem = m_lstStatusItems.RemoveHead();

		// Get current time
		GetLocalTimeFormat(szTime, 64);

		// Format message type
		switch (pStatusItem.eMsgType)
		{
			case STATUSMSG_Error:
				szType = _T("**");
				eTbdOutputLevel = TBDOL_ERROR;
				break;
			case STATUSMSG_Send:
				szType = _T("->");
				break;
			case STATUSMSG_Receive:
				szType = _T("<-");
				break;
			case STATUSMSG_Notif:
				szType = _T("<<");
				break;
			case STATUSMSG_Status:
			default:
				szType = _T("");
				break;
		}

		// Add item to status window
		m_pStatusCtrl->InsertItem(m_nNumberLines, szTime);
		m_pStatusCtrl->SetItemText(m_nNumberLines, COL_Type, szType);
		m_pStatusCtrl->SetItemText(m_nNumberLines, COL_Msg, pStatusItem.szStatusMsg);
		m_pStatusCtrl->SetColumnWidth(COL_Msg,LVSCW_AUTOSIZE); 		

		// Auto scroll
		if (m_bAutoScroll)
			m_pStatusCtrl->EnsureVisible(m_nNumberLines, TRUE);

		// Restrict number of lines
		if (MAX_LinesStatus <= m_nNumberLines)
		{
			m_pStatusCtrl->DeleteItem(0);
			m_nNumberLines = MAX_LinesStatus;
		}
		else
		{
			// increment number of lines
			m_nNumberLines++;
		}

		TBD_OUTPUT(TBDCT_INFO, eTbdOutputLevel, _T("%s%s"), szType, pStatusItem.szStatusMsg);
	}

	LeaveCriticalSection(&m_csStatus);
}