/******************************************************************************
 *                                                                         
 *               (C) COPYRIGHT Pacific MindWorks, Inc. 2001-2005
 *                          All rights reserved.
 *
 *****************************************************************************/

#ifndef __NTLEVENTSERVER_INCLUDED
#define __NTLEVENTSERVER_INCLUDED

#import "IviEventServerDLL.dll" no_namespace, raw_interfaces_only


//	Forward declarations
class CEventServerManager;


///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerSource
//

typedef enum
{
	NoSource		= 1,
	SourceAllLevels = 2
};

class CEventServerSource
{
public:
	CEventServerSource(CEventServerManager* pEventServerManager, long lCookie) 
		: m_pEventServerManager(pEventServerManager), m_lCookie(lCookie) {}
	~CEventServerSource() {}

public:
	virtual HRESULT ConnectSource() { return S_OK; }
	virtual HRESULT DisconnectSource() { return S_OK; }

public:
	virtual HRESULT _FireStatusEvent(long lCode, LPCTSTR pszText, va_list argPtr)
	{
		NTL_UNUSED(lCode);
		NTL_UNUSED(pszText);
		NTL_UNUSED(argPtr);

		return S_OK;
	}
	
	virtual HRESULT _FireEvent(long lCode, LPCTSTR pszText, va_list argPtr)
	{
		NTL_UNUSED(lCode);
		NTL_UNUSED(pszText);
		NTL_UNUSED(argPtr);

		return S_OK;
	}
	
	virtual HRESULT _FireWarningEvent(long lCode, LPCTSTR pszText, va_list argPtr)
	{
		NTL_UNUSED(lCode);
		NTL_UNUSED(pszText);
		NTL_UNUSED(argPtr);

		return S_OK;
	}
	
	virtual HRESULT _FireErrorEvent(long lCode, LPCTSTR pszText, va_list argPtr)
	{
		NTL_UNUSED(lCode);
		NTL_UNUSED(pszText);
		NTL_UNUSED(argPtr);

		return S_OK;
	}
	
	virtual HRESULT _FireTraceEvent(long lCode, LPCTSTR pszText, va_list argPtr)
	{
		NTL_UNUSED(lCode);
		NTL_UNUSED(pszText);
		NTL_UNUSED(argPtr);

		return S_OK;
	}

	long GetCookie() const { return m_lCookie; }

protected:
	long m_lCookie;
	CEventServerManager* m_pEventServerManager;
};


///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerNoSource
//

class CEventServerNoSource 	: 
	public CEventServerSource
{
public:
	CEventServerNoSource(CEventServerManager* pEventServerManager) 
		: CEventServerSource(pEventServerManager, -1) {}
	~CEventServerNoSource() {}
};


///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerSourceAllLevels
//

class CEventServerSourceAllLevels :
	public CEventServerSource
{
public:
	CEventServerSourceAllLevels(CEventServerManager* pEventServerManager, long lCookie = -1) 
		: CEventServerSource(pEventServerManager, lCookie) {}

public:
	HRESULT ConnectSource();
	HRESULT DisconnectSource();

public:
	HRESULT _FireStatusEvent(long lCode, LPCTSTR pszText, va_list argPtr);
	HRESULT _FireEvent(long lCode, LPCTSTR pszText, va_list argPtr);
	HRESULT _FireWarningEvent(long lCode, LPCTSTR pszText, va_list argPtr);
	HRESULT _FireErrorEvent(long lCode, LPCTSTR pszText, va_list argPtr);
	HRESULT _FireTraceEvent(long lCode, LPCTSTR pszText, va_list argPtr);
};


///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerSink
//

class CEventServerSink
{
public:
	CEventServerSink(CEventServerManager* pEventServerManager, long lCookie = -1) 
		: m_pEventServerManager(pEventServerManager), m_lCookie(lCookie) {}
	~CEventServerSink() {}

public:
	virtual HRESULT ConnectSink() { return S_OK; }
	virtual HRESULT DisconnectSink() { return S_OK; }

	long GetCookie() const { return m_lCookie; }

private:
	long m_lCookie;
	CEventServerManager* m_pEventServerManager;
};


///////////////////////////////////////////////////////////////////////////////
//	CEventServerNoSink

class CEventServerNoSink :
	public CEventServerSink
{
public:
	CEventServerNoSink(CEventServerManager* pEventServerManager) 
		: CEventServerSink(pEventServerManager, -1) {}
	~CEventServerNoSink() {}
};


///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerManager
//

struct _EVENTSERVER_LOCATION_INFO
{
	const wchar_t* pszSubSystem;
	const wchar_t* pszRole;
};

class CEventServerManager
{
public:
	CEventServerManager();
	~CEventServerManager();

	HRESULT InitializeEventServerManager(const CString& strView);
	HRESULT InitializeEventServerManager(IIviEventServer* pEventServer, long lSourceCookie, long lSinkCookie);
	HRESULT CloseEventServerManager();

public:
	HRESULT FireStatusEvent(long lCode, LPCTSTR pszText, ...);
	HRESULT FireEvent(long lCode, LPCTSTR pszText, ...);
	HRESULT FireWarningEvent(long lCode, LPCTSTR pszText, ...);
	HRESULT FireErrorEvent(long lCode, LPCTSTR pszText, ...);
	HRESULT FireTraceEvent(long lCode, LPCTSTR pszText, ...);

public:
	virtual CEventServerSource* CreateSource() { return NULL; }							// Overridden in generated code
	virtual CEventServerSink* CreateSink() { return NULL; }								// Overridden in generated code
	virtual const _EVENTSERVER_LOCATION_INFO* GetLocationInfo() const { return NULL; }	// Overridden in generated code

public:
	HRESULT GetEventServer(IIviEventServer** ppServer) const;
	HRESULT GetLocation(BSTR* pbstrSubSystem, BSTR* pbstrRole, BSTR* pbstrView) const;
	HRESULT GetSourceEvents(SAFEARRAY** ppEvents, SAFEARRAY** ppLatencies, SAFEARRAY** ppOrders, SAFEARRAY** ppLogs) const;
	long GetSourceCookie() const;
	long GetSinkCookie() const;

protected:
	bool m_bOwned;
	IIviEventServer* m_pEventServer;
	CEventServerSource* m_pSource;
	CEventServerSink* m_pSink;
	CString m_strView;
};

///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerManager implementation
//

inline CEventServerManager::CEventServerManager()
	: m_bOwned(false), m_pEventServer(NULL), m_pSource(NULL), m_pSink(NULL)
{
}

inline CEventServerManager::~CEventServerManager()
{
}

inline HRESULT CEventServerManager::InitializeEventServerManager(const CString& strView)
{
	if (m_pEventServer != NULL)
		return E_FAIL;

	m_bOwned = true;

	m_pSource = CreateSource();
	m_pSink = CreateSink();
	m_strView = strView;

	HRESULT hr = CoCreateInstance(__uuidof(IviEventServerDLL), NULL, CLSCTX_INPROC_SERVER, __uuidof(IIviEventServer), (void**)&m_pEventServer);
	if (SUCCEEDED(hr))
	{		
		hr = m_pSink->ConnectSink();
		if (SUCCEEDED(hr))
		{
			hr = m_pSource->ConnectSource();
		}
	}

	if (FAILED(hr))
	{
		// Something went wrong, so we return E_FAIL and undo everything
		CloseEventServerManager();

		hr = E_FAIL;
	}

	return hr;
}

inline HRESULT CEventServerManager::InitializeEventServerManager(IIviEventServer* pEventServer, long lSourceCookie, long lSinkCookie)
{
	if (m_pEventServer != NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	m_bOwned = false;

	(m_pEventServer = pEventServer)->AddRef();

	if (lSourceCookie == -1)
	{
		m_pSource = new CEventServerNoSource(this);
	}
	else
	{
		m_pSource = new CEventServerSourceAllLevels(this, lSourceCookie);
	}

	if (lSinkCookie == -1)
	{
		m_pSink = new CEventServerNoSink(this);
	}
	else
	{
		m_pSink = new CEventServerSink(this, lSinkCookie);
	}

	return hr;
}

inline HRESULT CEventServerManager::CloseEventServerManager()
{
	HRESULT hr = E_FAIL;
	if (m_pEventServer != NULL)
	{
		if (m_bOwned)
		{
			hr = m_pSink->DisconnectSink();
			if (SUCCEEDED(hr))
			{
				hr = m_pSource->DisconnectSource();
			}
		}

		m_pEventServer->Release();
		m_pEventServer = NULL;

		delete m_pSink;
		m_pSink = NULL;

		delete m_pSource;
		m_pSource = NULL;
	}

	return hr;
}

inline HRESULT CEventServerManager::GetEventServer(IIviEventServer** ppServer) const
{
	if (ppServer == NULL)
		return E_POINTER;

	HRESULT hr = E_FAIL;

	*ppServer = NULL;

	if (m_pEventServer != NULL)
	{
		(*ppServer = m_pEventServer)->AddRef();

		hr = S_OK;
	}

	return hr;
}

inline HRESULT CEventServerManager::GetLocation(BSTR* pbstrSubSystem, BSTR* pbstrRole, BSTR* pbstrView) const
{
	const _EVENTSERVER_LOCATION_INFO* pLocInfo = GetLocationInfo();

	*pbstrSubSystem = CComBSTR(pLocInfo->pszSubSystem).Detach();
	*pbstrRole = CComBSTR(pLocInfo->pszRole).Detach();
	*pbstrView = CComBSTR(CT2OLE(m_strView)).Detach();

	return S_OK;
}

inline HRESULT CEventServerManager::GetSourceEvents(SAFEARRAY** ppEvents, SAFEARRAY** ppLatencies, SAFEARRAY** ppOrders, SAFEARRAY** ppLogs) const
{
	if (ppEvents == NULL)
		return E_POINTER;
	
	if (ppLatencies == NULL)
		return E_POINTER;
	
	if (ppOrders == NULL)
		return E_POINTER;
	
	if (ppLogs == NULL)
		return E_POINTER;

	// Override this function to provide the events
	*ppEvents = NULL;
	*ppLatencies = NULL;
	*ppOrders = NULL;
	*ppLogs = NULL;

	return S_OK;
}

inline long CEventServerManager::GetSourceCookie() const
{
	return m_pSource->GetCookie();
}

inline long CEventServerManager::GetSinkCookie() const
{
	return m_pSink->GetCookie();
}

inline HRESULT CEventServerManager::FireStatusEvent(long lCode, LPCTSTR pszText, ...)
{
	va_list argPtr;
	va_start(argPtr, pszText);

	HRESULT hr = m_pSource->_FireStatusEvent(lCode, pszText, argPtr);

	va_end(argPtr);

	return hr;
}

inline HRESULT CEventServerManager::FireEvent(long lCode, LPCTSTR pszText, ...)
{
	va_list argPtr;
	va_start(argPtr, pszText);

	HRESULT hr = m_pSource->_FireEvent(lCode, pszText, argPtr);

	va_end(argPtr);

	return hr;
}

inline HRESULT CEventServerManager::FireWarningEvent(long lCode, LPCTSTR pszText, ...)
{
	va_list argPtr;
	va_start(argPtr, pszText);

	HRESULT hr = m_pSource->_FireWarningEvent(lCode, pszText, argPtr);

	va_end(argPtr);

	return hr;
}

inline HRESULT CEventServerManager::FireErrorEvent(long lCode, LPCTSTR pszText, ...)
{
	va_list argPtr;
	va_start(argPtr, pszText);

	HRESULT hr = m_pSource->_FireErrorEvent(lCode, pszText, argPtr);

	va_end(argPtr);

	return hr;
}

inline HRESULT CEventServerManager::FireTraceEvent(long lCode, LPCTSTR pszText, ...)
{
	va_list argPtr;
	va_start(argPtr, pszText);

	HRESULT hr = m_pSource->_FireTraceEvent(lCode, pszText, argPtr);

	va_end(argPtr);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
//	
//	CEventServerSourceAllLevels implementation
//

inline HRESULT CEventServerSourceAllLevels::ConnectSource()
{
	IIviEventServer* pServer = NULL;
	HRESULT hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		CComBSTR bstrSubSystem;
		CComBSTR bstrRole;
		CComBSTR bstrView;

		hr = m_pEventServerManager->GetLocation(&bstrSubSystem, &bstrRole, &bstrView);
		if (SUCCEEDED(hr))
		{
			SAFEARRAY* pEvents = NULL;
			SAFEARRAY* pLatencies = NULL;
			SAFEARRAY* pOrders = NULL;
			SAFEARRAY* pLogs = NULL;

			hr = m_pEventServerManager->GetSourceEvents(&pEvents, &pLatencies, &pOrders, &pLogs);
			if (SUCCEEDED(hr))
			{
				hr = pServer->ConnectSource(NULL, NULL, 0, bstrSubSystem, bstrRole, bstrView, &pEvents, &pLatencies, &pOrders, &pLogs, &m_lCookie);

				if (pEvents != NULL)
				{
					::SafeArrayDestroy(pEvents);
				}
				
				if (pLatencies != NULL)
				{
					::SafeArrayDestroy(pLatencies);
				}
				
				if (pOrders != NULL)
				{
					::SafeArrayDestroy(pOrders);
				}

				if (pLogs != NULL)
				{
					::SafeArrayDestroy(pLogs);
				}
			}
		}

		pServer->Release();
	}

	return hr;
}

inline HRESULT CEventServerSourceAllLevels::DisconnectSource()
{
	IIviEventServer* pServer = NULL;
	HRESULT hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		if (m_lCookie != -1)
		{
			hr = pServer->DisconnectSource(m_lCookie);
			m_lCookie = -1;
		}

		pServer->Release();
	}

	return hr;
}

inline HRESULT CEventServerSourceAllLevels::_FireStatusEvent(long lCode, LPCTSTR pszText, va_list argPtr)
{
	HRESULT hr = S_OK;

	CString strResult;
	strResult.FormatV(pszText, argPtr);

	IIviEventServer* pServer;
	hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		hr = pServer->SendEventEx(IviEventServerEventTypeStatus, lCode, CComBSTR(CT2OLE(strResult)), NULL, m_lCookie);
		pServer->Release();
	}

	return hr;
}

inline HRESULT CEventServerSourceAllLevels::_FireEvent(long lCode, LPCTSTR pszText, va_list argPtr)
{
	HRESULT hr = S_OK;

	CString strResult;
	strResult.FormatV(pszText, argPtr);

	IIviEventServer* pServer;
	hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		hr = pServer->SendEventEx(IviEventServerEventTypeEvent, lCode, CComBSTR(CT2OLE(strResult)), NULL, m_lCookie);
		pServer->Release();
	}

	return hr;
}

inline HRESULT CEventServerSourceAllLevels::_FireWarningEvent(long lCode, LPCTSTR pszText, va_list argPtr)
{
	HRESULT hr = S_OK;

	CString strResult;
	strResult.FormatV(pszText, argPtr);

	IIviEventServer* pServer;
	hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		hr = pServer->SendEventEx(IviEventServerEventTypeWarning, lCode, CComBSTR(CT2OLE(strResult)), NULL, m_lCookie);
		pServer->Release();
	}

	return hr;
}

inline HRESULT CEventServerSourceAllLevels::_FireErrorEvent(long lCode, LPCTSTR pszText, va_list argPtr)
{
	HRESULT hr = S_OK;

	CString strResult;
	strResult.FormatV(pszText, argPtr);

	IIviEventServer* pServer;
	hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		hr = pServer->SendEventEx(IviEventServerEventTypeError, lCode, CComBSTR(CT2OLE(strResult)), NULL, m_lCookie);
		pServer->Release();
	}

	return hr;
}

inline HRESULT CEventServerSourceAllLevels::_FireTraceEvent(long lCode, LPCTSTR pszText, va_list argPtr)
{
	HRESULT hr = S_OK;

	CString strResult;
	strResult.FormatV(pszText, argPtr);

	IIviEventServer* pServer;
	hr = m_pEventServerManager->GetEventServer(&pServer);
	if (SUCCEEDED(hr))
	{
		hr = pServer->SendEventEx(IviEventServerEventTypeDebug, lCode, CComBSTR(CT2OLE(strResult)), NULL, m_lCookie);
		pServer->Release();
	}

	return hr;
}

#endif // __NTLEVENTSERVER_INCLUDED
