#ifndef _COMMON_RESDATA_HPP_
#define _COMMON_RESDATA_HPP_
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_STRING_HPP_
#include <common/string.hpp>
#endif

class ResType
{
public:
  enum Resource{RtAccelerator=RT_ACCELERATOR,RtBitmap=RT_BITMAP,RtDialog=RT_DIALOG,
	       RtFont=RT_FONT,RtFontDir=RT_FONTDIR,RtMenu=RT_MENU,RtData=RT_RCDATA,
				 RtString=RT_STRING,RtMessageTable=RT_MESSAGETABLE,RtCursor=RT_CURSOR,
				 RtGroupCursor=RT_GROUP_CURSOR,RtIcon=RT_ICON,RtGroupIcon=RT_GROUP_ICON,
				 RtVersion=RT_VERSION};
};

class ResDisposition
{
public:
  enum Disposition{Assume,Delete,Invalid};
};

template <class T>
class ResData
{
public:
  ResData(void);
	ResData(const ResData &someResData);
	ResData(const String &resName,ResType::Resource resType=ResType::RtData,HMODULE hResModule=GetModuleHandle(0));
  virtual ~ResData();
	ResData &operator=(const ResData &someResData);
	ResData &operator=(const String &resName);
	operator T*(void)const;
	WORD isOkay(void)const;
private:
	void create(const String &resName,ResType::Resource resType=ResType::RtData,HMODULE hResModule=::GetModuleHandle(0));
  void destroy(void);
	HRSRC resHandle(void)const;
	void resHandle(HRSRC resHandle);
	HGLOBAL resData(void)const;
	void resData(HGLOBAL resData);
	ResDisposition::Disposition resDisp(void)const;
	void resDisp(ResDisposition::Disposition resDisp);

  HRSRC mhResHandle;
	HGLOBAL mhResData;
	ResDisposition::Disposition mDisposition;
};

template <class T>
inline
ResData<T>::ResData(void)
: mhResHandle(0), mhResData(0), mDisposition(ResDisposition::Invalid)
{
}

template <class T>
inline
ResData<T>::ResData(const ResData &someResData)
: mhResHandle(0), mhResData(0), mDisposition(ResDisposition::Invalid)
{
  *this=someResData;
}

template <class T>
inline
ResData<T>::ResData(const String &resName,ResType::Resource resType,HMODULE hResModule)
: mhResHandle(0), mhResData(0), mDisposition(ResDisposition::Delete)
{
  create(resName,resType,hResModule);
}

template <class T>
inline
ResData<T>::~ResData()
{
  destroy();
}

template <class T>
inline
ResData<T> &ResData<T>::operator=(const ResData &someResData)
{
	if(!someResData.isOkay())return *this;
  destroy();
	resData(someResData.resData());
	resHandle(someResData.resHandle());
	resDisp(ResDisposition::Assume);
	return *this;
}

template <class T>
inline
ResData<T> &ResData<T>::operator=(const String &resName)
{
  if(resName.isNull())return *this;
	destroy();
	create(resName);
	return *this;
}

template <class T>
inline
ResData<T>::operator T*(void)const
{
  return (T*)mhResData;
}

template <class T>
inline
void ResData<T>::create(const String &resName,ResType::Resource resType,HMODULE hResModule)
{
  destroy();
	resHandle(::FindResource(hResModule,resName,(const char*)resType));
	if(!resHandle())return;
	resData(::LoadResource(hResModule,mhResHandle));
	resDisp(ResDisposition::Delete);
}

template <class T>
inline
void ResData<T>::destroy(void)
{
  if(!resData()||ResDisposition::Assume==resDisp())return;
	::FreeResource(resData());
	resData(0);
	resHandle(0);
	resDisp(ResDisposition::Invalid);
}

template <class T>
inline
HRSRC ResData<T>::resHandle(void)const
{
  return mhResHandle;
}

template <class T>
inline
void ResData<T>::resHandle(HRSRC resHandle)
{
  mhResHandle=resHandle;
}

template <class T>
inline
HGLOBAL ResData<T>::resData(void)const
{
  return mhResData;
}

template <class T>
inline
void ResData<T>::resData(HGLOBAL resData)
{
  mhResData=resData;
}

template <class T>
inline
ResDisposition::Disposition ResData<T>::resDisp(void)const
{
  return mDisposition;
}

template <class T>
inline
void ResData<T>::resDisp(ResDisposition::Disposition resDisp)
{
  mDisposition=resDisp;
}

template <class T>
inline
WORD ResData<T>::isOkay(void)const
{
  return (resData()&&resHandle());
}
#endif
