#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifdef __AFXWIN_H__
#undef DATAFAR_
#endif
#include "hasp.h"

#if ! defined(FALSE)
#define FALSE 0x0000
#endif

#if ! defined(TRUE)
#define TRUE (!FALSE)
#endif


#include "HaspException.h"

//@Include: HaspException.h


struct HaspPasswd
{
	unsigned int p1;
	unsigned int p2;
};



/** Helper class for NetHasp functionality.

	This class is used to set/get NetHasp protocol information.
*/
class CNethaspProtocol
{
public:
	
	/**@name Enumerations */
	/*@{*/
	/** Protocol types.	*/
	enum ProtocolTypes
	{
		NONE    = 0,
		IPX     = 1,
		NETBIOS = 2,
		TCPIP   = 4,
		ALL_PROTOCOLS = (IPX | NETBIOS | TCPIP)
	};

	/** Search methods. */
	enum SearchMethods
	{
		DEFAULT            = 0, 
		IPX_LOCALNET       = 1, 
		IPX_BINDERY        = 4, 
		UDPIP_NO_BROADCAST = 8, 
		IPX_NO_BROADCAST   = 32,
		TCP                = 128
	};
	/*@}*/

	/** Standard Constructor.*/
	CNethaspProtocol();
	/** Contructs CNethaspProtocol with given protocol values and search method.*/
	CNethaspProtocol(int ConfigProtocol, int SearchMethod = DEFAULT, int MachineProtocol = 0);

	/** Returns config protocol.*/
	inline int GetConfigProtocol() const { return m_ConfigProtocol;};
	/** Returns search method.*/
	inline int GetSearchMethod() const { return m_SearchMethod;};
	/** Returns machine protocol.*/
	inline int GetMachineProtocol() const { return m_MachineProtocol;};

private:
	int m_ConfigProtocol;
	int m_MachineProtocol;
	int m_SearchMethod;
};



/** Wrapper class for HASP service functions.

    Code example 1 (Search for Hasp Demo MA, local and over TCP/IP):
	\begin{verbatim}
try
{
	// Construct Hasp object, we want to set net protocol before attempting connect
	CHasp MyHasp;
	// Create CNethaspProtocol object for using TCP/IP only
	CNethaspProtocol prot(CNethaspProtocol::TCPIP, CNethaspProtocol::TCP);
	// set protocol parameters
	MyHasp.NetHASP_SetProtocol(prot);
	// now search for Demo MA key, if not local, then over network
	MyHasp.AutoSearch(CHasp::LocalFirst, CHasp::TryDemoMA);

	// Is it connected?
	if (MyHasp.IsHasp())
	{
		// Ehm, what passwords do we have?
		UINT p1, p2;
		MyHasp.GetPasswords(&p1, &p2);

		// Do we have memory?
		if (MyHasp.IsMemoHasp())   // We also also could write: if (MyHasp.GetMemorySize()>0)
		{
			int hince = MyHasp.ReadWord(23); // read word at index 23

			if (MyHasp.IsHasp4())  // Is it possible to encode/decode ?
			{
				char kewnce[8] = {1,2,3,4,5,6,7,8}; 
				MyHasp.EncodeByteBlock(kewnce, 0, 8); // encode this
				MyHasp.WriteWordBlock(kewnce,0,4);  // write this 8 byte block (= 4 Words)
			}
			char muuuuh[10] = {0};
			MyHasp.ReadByteBlock(muuuuh,0,9);   // Words don't come easy...
		}
	}
}
catch (CHaspException e)
{
	CString Err;
	Err.Format("Hasp Status Code: %d", e.GetStatus());
	// some error output
}
	\end{verbatim}


    Code example 2 (Try to connect to my local Hasp):
	\begin{verbatim}
try
{
	// Construct Hasp object, start searching directly (implicit AutoSearch call)
	CHasp MyHasp(12345,6789);

	// Do we have memory?
	if (MyHasp.IsMemoHasp())   // We also also could write: if (MyHasp.GetMemorySize()>0)
	{
		int hince = MyHasp.ReadWord(23); // read word at index 23

		if (MyHasp.IsHasp4())
		{
			char kewnce[8] = {1,2,3,4,5,6,7,8}; 
			MyHasp.EncodeByteBlock(kewnce, 0, 8); // encode this
			MyHasp.WriteWordBlock(kewnce,0,4);  // write this 8 byte block (= 4 Words)
		}
		char muuuuh[10] = {0};
		MyHasp.ReadByteBlock(muuuuh,0,9);
	}
}
catch (CHaspException e)
{
	CString Err;
	Err.Format("Hasp Status Code: %d", e.GetStatus());
	// some error output
}
	\end{verbatim}

*/
class CHasp  
{
	friend class CHaspException;
	static struct HaspPasswd DemoPass[];

public:
	/**@name Enumerations */
	/*@{*/
	/** Options for automatic searching mode.
	\begin{itemize} 
	\item NoAutoSearch: Do not search.
	\item LocalOnly: Search on local port only.
	\item NetOnly: Search over network only.
	\item NetFirst: Search first over network, then on local port.
	\item LocalFirst: Search first local port, then over network.
	\end{itemize}
	*/
	enum AutoSearchOptions
	{
		NoAutoSearch,
		LocalOnly,
		NetOnly,
		NetFirst,
		LocalFirst
	};

	/** Options for HASP Demo searching mode. 

	\begin{itemize} 
	\item TryNothing: Do not try any HASP demo key.
	\item TryDemoMA: Try with passwords for HASP Demo MA.
	\item TryDemoAll: Try any HASP Demo key.
	\end{itemize}
	*/
	enum TryMode
	{
		TryNothing,
		TryDemoMA,
		TryDemoAll
	};
	/*@}*/

	/**@name Class Constructors/Destructors */
	/*@{*/
	/** Standard Constructor. Initializes CHasp properties.*/
	CHasp();
	/** Constructs CHasp with parameters necessary to connect a certain HASP. 
	
		As default CHasp does not try to connect to HASP (depends on Options value).
		As default does not try to connect with HASP demo key passwords.
	*/
	CHasp(unsigned int Pass1, unsigned int Pass2, unsigned int LptNum = 0, AutoSearchOptions Options = NoAutoSearch, TryMode Mode = TryNothing);
	virtual ~CHasp();
	/*@}*/

	/**@name Utility methods */
	/*@{*/
	/** Merge two words into a long.*/
	static long MakeLong(int hiword, int loword);
	/*@}*/

	/**@name Methods for reinitialisation and automatic DemoHasp search. */
	/*@{*/
	/** (Re-)Connecting to HASP with actual parameters.*/
	void Refresh(AutoSearchOptions Options = CHasp::NoAutoSearch);
	/** Trying HASP Demo keys.*/
	void AutoSearch(AutoSearchOptions Options, TryMode Mode);
	/*@}*/

	/**@name Methods to set/get actual parameters */
	/*@{*/
	/** Set actual passwords.*/
	void SetPasswords(unsigned int Pass1, unsigned int Pass2) {m_Pass.p1 = Pass1; m_Pass.p2 = Pass2;};
	/** Set actual seed code.*/
	void SetSeedCode(unsigned int SeedCode) {m_SeedCode = SeedCode;};
	/** Set value for searched LPT port.
	\begin{itemize} 
	\item 0: Automatic search at all ports.
	\item 1: Search LPT1 only.
	\item 2: Search LPT2 only.
	\item 3: Search LPT3 only.
	\end{itemize}
	*/
	void SetLptNum(unsigned int LptNum) {m_Lpt = LptNum;};
	/** Set actual LM program number.*/
	void SetProgNum(unsigned int ProgNum) {m_Lpt = ProgNum;};
	/** Get actual value for searched LPT port.*/
	unsigned int GetLptNum() const {return m_Lpt;};
	/** Get actual LM program number.*/
	unsigned int GetProgNum() const {return m_Lpt;};
	/** Set actual passwords.*/
	void GetPasswords(unsigned int *Pass1, unsigned int *Pass2) const {*Pass1 = m_Pass.p1; *Pass2 = m_Pass.p2;};

	/** Get memory size of currently connected HASP.*/
	unsigned int GetMemorySize() {return m_MemorySize;};

	/** Set the four actual HASP parameters.*/
	void SetParams(int par1, int par2, int par3, int par4);
	/** Get the four actual HASP parameters.*/
	void GetParams(int* par1, int* par2, int* par3, int* par4) const;
	/*@}*/

	/**@name Determine the connected HASP key */
	/*@{*/
	/** Returns TRUE if there is a HASP connected, otherwise FALSE.
		
		Passing TRUE causes the IsHasp service to be called again.
	*/
	int IsHasp(int CheckAgain = 0);
	/** Returns TRUE if there is a HASP3 connected, otherwise FALSE.*/
	int IsSimpleHasp() const;
	/** Returns TRUE if connected HASP is a MemoHasp, otherwise FALSE.*/
	int IsMemoHasp() const;
	/** Returns TRUE if there is a TimeHASP connected, otherwise FALSE.*/
	int IsTimeHasp() const;
	/** Returns TRUE if there is a HASP connected remotely, otherwise FALSE.*/
	int IsRemote() const;
	/** Returns TRUE if connected HASP is a HASP4 key, otherwise FALSE.*/
	int IsHasp4() const;
	/** Returns HASP description.*/
	char* GetDescription();
	/** Returns TRUE if connected HASP is a Demo key, otherwise FALSE.*/
	int IsDemo() const;
	/*@}*/

	/**@name HASP services */
	/*@{*/
	/** Get the HASP ID. */
	long HaspID();
	/** Call the HASPCode service with the actual Seedcode. */
	void HaspCode();
	/** Call the HASPCode service with the given Seedcode. */
	void HaspCode(int SeedCode);
	/** Decode given block. */
	void DecodeByteBlock(void *block, int index, int size);
	/** Encode given block. */
	void EncodeByteBlock(void *block, int index, int size);
	/** Write word into HASP memory. */
	void WriteWord(unsigned int index, unsigned int value);
	/** Read word from HASP memory. */
	int ReadWord(unsigned int index);
	/** Write word block into HASP memory. */
	void WriteWordBlock(const void DATAFAR_* block, unsigned int index, unsigned int size);
	/** Read word block from HASP memory. */
	void ReadWordBlock(void DATAFAR_* block, unsigned int index, unsigned int size);
	/** Write byte block into HASP memory. */
	void WriteByteBlock(const void DATAFAR_* block, unsigned int index, unsigned int size);
	/** Read byte block from HASP memory. */
	void ReadByteBlock(void DATAFAR_* block, unsigned int index, unsigned int size);
	/** Write zero terminated string to HASP memory. */
	void WriteString(const char DATAFAR_* string, unsigned int index);
	/*@}*/

	/**@name TimeHASP services */
	/*@{*/
	/** Write byte into TimeHASP memory. */
	virtual void TimeHASP_WriteByte(unsigned int index, unsigned char value);
	/** Read byte from TimeHASP memory. */
	virtual unsigned char TimeHASP_ReadByte(unsigned int index);
	/** Write byte block into TimeHASP memory. */
	virtual void TimeHASP_WriteBlock(const void *block, unsigned int index, unsigned int size);
	/** Read byte block from TimeHASP memory. */
	virtual void TimeHASP_ReadBlock(void *block, unsigned int index, unsigned int size);
	/** Set TimeHasp time */
	virtual void TimeHASP_SetTime(int Hour, int Minute, int Second);
	/** Set TimeHasp date */
	virtual void TimeHASP_SetDate(int Year, int Month, int Day);
	/** Get TimeHasp time */
	virtual void TimeHASP_GetTime(int *Hour, int *Minute, int *Second);
	/** Get TimeHasp date */
	virtual void TimeHASP_GetDate(int *Year, int *Month, int *Day);
	/*@}*/

	/**@name NetHASP services/functions */
	/*@{*/
	/** Status of the last NetHASP operation. */
	virtual void NetHASP_LastStatus();
	/** Perform NetHASP login. */
	virtual void NetHASP_Login();
	/** Perform NetHASP logout. */
	virtual void NetHASP_Logout();
	/** Set NetHASP Idle Time value. */
	virtual void NetHASP_IdleTime(int IdleMinutes);
	/** Set NetHASP Idle Time value. */
	virtual void NetHASP_SetDefaultConfig();
	/** Specify name of the NetHASP License Manager to communicate with. */
	virtual void NetHASP_SetServerByName(const char DATAFAR_* server);
	/** Set NetHASP configuration file name. */
	virtual void NetHASP_SetConfigFilename(const char DATAFAR_* filename);
	/** Queries current license attributes. */
	virtual void NetHASP_QueryLicense(unsigned int ProgNum, int *LicActive = 0, int *LicMax = 0, int *KeyType = 0, int *ActRemain = 0);
	/** Sets NetHasp License Manager attributes from given CNethaspProtocol object. */
	virtual void NetHASP_SetProtocol(const CNethaspProtocol& prot);
	/** Gets actual NetHasp License Manager attributes. */
	virtual void NetHASP_GetProtocol(CNethaspProtocol& prot);
	/*@}*/

private:
	/**@name Utility methods */
	/*@{*/
	/** Call actual HASP service with actual parameters. */
	void CallHasp();
	/** Call given HASP service with actual parameters. */
	void CallHasp(unsigned int Service);
	/** Call actual HASP memory block service with actual parameters. */
	void BlockOperation(const void *Block, unsigned int Index, unsigned int Size);
	/** Call given HASP memory block service with actual parameters. */
	void BlockOperation(unsigned int Service, const void *Block, unsigned int Index, unsigned int Size);
	/*@}*/


	// the service number passed to the hasp() routine. 
	//
	unsigned int m_Service;

	// the seed code passed to the hasp() routine.
	//
	unsigned int m_SeedCode;

	// for local HASP's lpt_number is used. For NetHASP this variable will
	// contain the program number.
	//
	unsigned int m_Lpt;

	// passwords passed to hasp().
	//
	struct HaspPasswd m_Pass;

protected:

	/**@name Methods used internally. */
	/*@{*/
	/** Initialize CHasp properties.*/
	virtual void Init();
	/** Set properties for NetHasp if found.*/
	virtual void SetNetHaspProperties();
	/** Set properties for any HASP if found no NetHasp.*/
	virtual void SetHaspProperties();
	/** Set Description string.*/
	virtual void SetDescription();
	/** Check for Hasp4.*/
	virtual void CheckHasp4();
	/*@}*/

	
	static char Descriptions[][12];

	// the four return parameters. their addresses are passed to hasp().
	//
	int m_p1;
	int m_p2;
	int m_p3;
	int m_p4;

	// what am I? (not used yet)
	int m_HaspType;
	char m_Description[20];

	int m_IsHasp;
	int m_IsDemo;
	int m_IsMemory;
	int m_IsHasp4;
	int m_IsTime;
	int m_IsRemote;
	unsigned int m_MemorySize;

	int DemoPassCount;
	struct HaspPasswd *pDemoPass;
};

