#ifndef __UTIL_H__
#define __UTIL_H__

#include <stdio.h>

#ifndef ENSURE
#define ENSURE			do
#define FAIL			break
#define END_ENSURE		while (FALSE)
#endif

//////////////////////////////////////////////////////////////////
// CPtrArray class

class CPtrArray
{
public:
	CPtrArray();
	virtual ~CPtrArray();

public:
	virtual int GetSize();
	virtual void SetSize(int nNewSize, int nGrowBy = -1);

	virtual int Add(LPVOID pItem);
	virtual void SetAt(int nIndex, LPVOID pItem);
	virtual LPVOID GetAt(int nIndex);
	virtual void Swap(int from, int to);

	virtual void InsertAt(int nIndex, LPVOID pItem);
	virtual void RemoveAt(int nIndex, int nCount = 1);

	virtual void RemoveAll();

	virtual LPVOID *GetData();

	LPVOID operator[](int nIndex);
	LPVOID operator[](int nIndex)const;

protected:
	int m_nAllocated;
	int m_nGrowBy;
	HGLOBAL m_hData;
	LPVOID *m_pData;

	int m_nSize;
};

//////////////////////////////////////////////////////////////////
// CDWordArray class

class CDWordArray : public CPtrArray
{
public:
	CDWordArray() : CPtrArray()	{}
	virtual ~CDWordArray()		{}

public:
	int Add(DWORD dwItem)					{ return CPtrArray::Add((LPVOID)dwItem);	}
	void SetAt(int nIndex, DWORD dwItem)	{ CPtrArray::SetAt(nIndex, (LPVOID)dwItem);	}

	void InsertAt(int nIndex, DWORD dwItem)	{ CPtrArray::InsertAt(nIndex, (LPVOID)dwItem);	}

	DWORD operator[](int nIndex)			{ return (DWORD)CPtrArray::GetAt(nIndex);	}
};

//////////////////////////////////////////////////////////////////
// CStringArray class

class CStringArray : public CPtrArray
{
public:
	CStringArray();
	virtual ~CStringArray();

public:
	int Add(LPCTSTR szItem);
	void SetAt(int nIndex, LPCTSTR szItem);

	void InsertAt(int nIndex, LPCTSTR szItem);
	void RemoveAt(int nIndex, int nCount = 1);

	void RemoveAll();

	LPCTSTR operator[](int nIndex);
};

//////////////////////////////////////////////////////////////////
// CTokens class

class CTokens : public CPtrArray
{
public:
	CTokens(LPCTSTR str, LPCTSTR seps);
	virtual ~CTokens();

public:
	LPCTSTR operator[](int nIndex);

private:
	char string[MAX_PATH];
};

//////////////////////////////////////////////////////////////////
// CTextFile class

class CTextFile
{
public:
	CTextFile(LPCTSTR lpszFilename, UINT nOpenFlags);
	virtual ~CTextFile();

	void WriteString(LPCTSTR lpsz);
	LPTSTR ReadString(LPTSTR lpsz, UINT nMax);

	UINT Read(void* lpBuf, UINT nCount);
	void Write(const void* lpBuf, UINT nCount);
	void Flush();
	void Close();

private:
	HANDLE	m_hFile;
	FILE   *m_pStream;
};

//////////////////////////////////////////////////////////////////
// CMapStringToString class

class CMapStringToString
{
public:
	CMapStringToString();
	virtual ~CMapStringToString();

	int	GetCount() const;
	BOOL IsEmpty() const;
	void SetAt(LPCTSTR key, LPCTSTR newValue);
	BOOL Lookup(LPCTSTR key, LPTSTR &rValue) const;
	BOOL RemoveKey(LPCTSTR key);
	void RemoveAll();

	UINT HashKey(LPCTSTR key) const;
	void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);

protected:
	// Association
	class CAssoc
	{
	public:
		CAssoc(LPCTSTR k, LPCTSTR v);
		virtual ~CAssoc();

		CAssoc* pNext;
		char *key;
		char *value;
	};

protected:
	CAssoc** m_pHashTable;
	UINT m_nHashTableSize;
	int m_nCount;

	CAssoc* GetAssocAt(LPCTSTR key, UINT &nHash) const;
};

//////////////////////////////////////////////////////////////////
// CTemplateFile class

class CTemplateFile
{
public:
	CTemplateFile();
	virtual ~CTemplateFile();

	void AddReplace(LPCTSTR lpsz1, LPCTSTR lpsz2);
	void AddReplace(LPCTSTR lpsz1, int index, LPCTSTR lpsz2);
	void AddReplace(LPCTSTR lpsz, int nNum);
	void AddReplace(LPCTSTR lpsz, int index, int nNum);
	void AddReplace(LPCTSTR lpsz, COLORREF cr);

	BOOL Convert(LPCTSTR lpszOutput, LPCTSTR lpszInput);

private:
	CMapStringToString m_ReplaceMap;
};

#endif /* __UTIL_H__ */
