/******************************************************************************
   AUTHOR:		Andy Woodhouse, BBC Academy
   FILENAME:	awExtInfo.h
   SEE ALSO:	awExtInfo.cpp

   PURPOSE:
   Encapsulate the interface to a BNCS Infodriver to enable a programmer to
   concentrate on the implementation of driver functionality.

   There are other BNCS libraries that can provide such interfaces - but I have
   no access to the relevant documentation and library linking they need, hence
   this implementation. Most of the code is borrowed from earlier work by
   David Yates of ATOS.
*******************************************************************************/

#if !defined(AFX_AWEXTINFO_H__0EF3B407_6B86_49D2_92FF_9737960379E3__INCLUDED_)
#define AFX_AWEXTINFO_H__0EF3B407_6B86_49D2_92FF_9737960379E3__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <windows.h>
#include <string>
#include <queue>

//using namespace std;

#include "ccCheck.h"
#include "include\cc.h"
#include "include\bncs_string.h"
#include "include\decodebncsstring.h"

/** \class IccInfodriverCallback
\brief Callback interface class for awExtInfo class

For clarity because this class must be inherited, the function names are prepended with cci (for Colledia Control Infodriver)
\sa awExtInfo
*/
class IccInfodriverCallback
{
	friend class awExtInfo;
protected:
	/** Request from client to change a slot
	\param[in] device The device number
	\param[in] index The slot number
	\param[in] slot The requested contents to use
	\note This command does not automatically update the contents of the slot
	*/
	virtual void cciSlotRequest(int device, int index, const string & slot){};
	/** Direct message from a client requesting workstation specific information on this device
	\param[in] workstation The workstation requesting the information
	\param[in] device The device number
	\param[in] message The message string from the client
	\param[in] reference An arbitary message reference that should be returned with the reply to this command
	\sa ccInfodriver::clientMessage();
	\note Implementation of this messaging mechanism is patchy so beware....
	*/
	virtual void cciClientMessage(int workstation, int device, const string & message, const string & clientHandle, const string & reference){};
	/** Notification of redundancy mode
	\param[in] mode The current mode
	*/
	virtual void cciRedundancyState(enum cc::redundancyState state){};
	/** Connected event */
	virtual void cciConnected(void){};
	/** Disconnected event */
	virtual void cciDisconnected(void){};

};


//***********************************************************************************************************
class ccInfodriverPost
{
public:
	ccInfodriverPost(int type, int slot, const string & contents)
	{
		m_type = type;
		m_slot = slot;
		m_contents = contents;
	};
	int m_type;
	int m_slot;
	string m_contents;
};

//***********************************************************************************************************
class awExtInfo : public ccCheck
{
public:
	awExtInfo(IccInfodriverCallback * callback = 0, const string & debugStringHeader = "ccInfodriver");
	virtual ~awExtInfo();

	long version(void);

	bool connect(int device, enum cc::ipcType ipc = cc::bbc, long ipcOptions = 0);
	/** Connect to a running infodriver
	\param[in] device  The device number of the infodriver
	\param[in] ipcType The type of communications to use to exchange messages with the infodriver
	\param[in] ipcOptions As yet there are none, but lets be prepared....
	*/
	
	bool disconnect();
	bool isConnected(void);			// Check if this interface is connected to an infodriver
	
	bool setSlot(int index, const string & value, bool send = true);
	bool setSlot(int index, int value, const string & format = "%d", bool send = true);
	bool setSlot(int index, double value, const string & format = "%f", bool send = true);

	bool updateSlot(int index, const string & value, bool & updated);
	bool sendSlotRange(int start, int end);
	bool slot(int index, string & value);

	void clientMessage(int workstation, int device, const string & message, const string & client, const string & reference);

	void setRedundancyMode(cc::redundancyMode mode);
	void setRedundancyState(enum cc::redundancyState state);
	void setDriverState(enum cc::driverState state, bool forceNow = false);
	enum cc::redundancyState redundancyState(void);
private:
	IccInfodriverCallback * m_callback;
	HWND m_hInfo;
	HWND m_hWndMessage;
	enum cc::ipcType m_ipc;
	long m_ipcOptions;
	int m_workstation;
	int m_device;
	enum cc::redundancyMode m_redundancyMode;
	enum cc::redundancyState m_redundancyState;
	enum cc::driverState m_driverState;

	queue< ccInfodriverPost > postedQueue;
	static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	LRESULT BNCSSendMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, int dataLen, int expectedReturnDataLen, int iDataType);
};

#endif // !defined(AFX_AWEXTINFO_H__0EF3B407_6B86_49D2_92FF_9737960379E3__INCLUDED_)

