
#ifndef DKUTIL_SUSIE_HPP
#define DKUTIL_SUSIE_HPP

#include <dkutil/utility.hpp>
#include <dkutil/dll.hpp>

namespace dkutil{



class SusieManager{
public:
	///画像情報
	struct PictureInfo
	{
		long left,top;			/* 画像を展開する位置 */
		long width;				/* 画像の幅(pixel) */
		long height;			/* 画像の高さ(pixel) */
		WORD x_density;			/* 画素の水平方向密度 */
		WORD y_density;			/* 画素の垂直方向密度 */
		short colorDepth;		/* 画素当たりのbit数 */
		HLOCAL hInfo;			/* 画像内のテキスト情報[呼び出し側が解放] */
	};
	///ファイル情報
	struct fileInfo
	{
		unsigned char method[8];	/* 圧縮法の種類 */
		unsigned long position;		/* ファイル上での位置 */
		unsigned long compsize;		/* 圧縮されたサイズ */
		unsigned long filesize;		/* 元のファイルサイズ */
		time_t timestamp;			/* ファイルの更新日時 */
		char path[200];				/* 相対パス */
		char filename[200];			/* ファイルネーム */
		unsigned long crc;			/* CRC */
	} ;

	///Plug-inの設定ダイアログ用
	enum SusieConfigDialogParam{
		SUSIE_CONFIGDLG_ABOUT= 0,
		SUSIE_CONFIGDLG_SETTING,
		SUSIE_CONFIGDLG_RESERVED
	};

	// Common
	typedef int (PASCAL *GetPluginInfoType)(int, LPSTR ,int );
	typedef int (PASCAL *IsSupportedType) (LPSTR,DWORD);


	// '00IN'の関数 
	typedef int (PASCAL *GetPictureInfoType) (LPSTR ,long ,unsigned int , PictureInfo *);
	typedef int (PASCAL *GetPictureType) (LPSTR ,long ,unsigned int , HANDLE *,HANDLE *,
									FARPROC ,long );
	typedef int (PASCAL *GetPreviewType) (LPSTR ,long ,unsigned int , HANDLE *,HANDLE *,
									FARPROC ,long );

	// '00AM'の関数 
	typedef int  (PASCAL *GetArchiveInfoType) (LPSTR buf, long len, unsigned int flag, HLOCAL *lphInf);
	typedef int  (PASCAL *GetFileInfoType) (LPSTR buf,long len, LPSTR filename, unsigned int flag, fileInfo *lpInfo);
	typedef int  (PASCAL *GetFileType) (LPSTR src,long len, LPSTR dest,unsigned int flag, FARPROC prgressCallback,long lData);

	typedef int  (PASCAL *ConfigurationDlgType)(HWND parent,int fnc);

	///@return Import Filter だったら true
	bool isImportFilter(){
		check_instance();
		return (mPluginInfo[2] == 'I' || mPluginInfo[2] == 'i');
	}
	///@return Export Filter だったら true
	bool isExportFilter(){
		check_instance();
		return (mPluginInfo[2] == 'X' || mPluginInfo[2] == 'x');
	}
	///@return Archive Extractor だったら true
	bool isArchiveExtractor(){
		check_instance();
		return (mPluginInfo[2] == 'A' || mPluginInfo[2] == 'a');
	}
	///@return フィルターが分からなければ true
	bool isUnknownFilter(){
		return (!isImportFilter() && !isExportFilter() && !isArchiveExtractor());
	}
	bool isNormal(){
		check_instance();
		return (mPluginInfo[3] == 'N' || mPluginInfo[3] == 'n');
	}
	bool isMultiPicture(){
		check_instance();
		return (mPluginInfo[3] == 'M' || mPluginInfo[3] == 'm');
	}
	///@return 00INタイプだったら true
	bool isIN(){	return (isNormal() && isImportFilter());}
	///@return 00AMタイプだったら true
	bool isAM(){	return (isMultiPicture() && isArchiveExtractor());}
	///@return char[2]を無理やりshortに変換したものを返す。
	short GetVersionForceShort(){
		check_instance();
		short *tmp = (short *)&mPluginInfo[0];
		return (*tmp);
	}
	///@return char[2]をatoi()したものを返す。
	short GetVersion(){
		check_instance();
		char buff[3]="";
		strncpy(buff,mPluginInfo,2);
		return atoi(buff);
	}
	/*!
	@param buff[out] バッファへのポインタ
	@param size[in] バッファのサイズ
	@return trueなら成功
	*/
	bool GetVersionStr(char *buff,size_t size){
		check_instance();
		if(size < 2) return false;
		buff[0] = mPluginInfo[0];
		buff[1] = mPluginInfo[1];
		return true;
	}

protected:
#	define DKUTIL_CAST_SUSIE(v,f) v exe = (v)mDLL.find(f);\
	if(exe==NULL)return -1

	// Common Function 
	int  GetPluginInfo (int infono, LPSTR buf,int buflen){
		check_instance();
		DKUTIL_CAST_SUSIE(GetPluginInfoType,"GetPluginInfo");
		return exe(infono,buf,buflen);
	}

	int  IsSupported (LPSTR filename,DWORD dw){
		check_instance();
		DKUTIL_CAST_SUSIE(IsSupportedType,"IsSupported");
		return exe(filename,dw);
	}


	//'00IN'の関数 
	int  GetPictureInfo (LPSTR buf,long len,unsigned int flag, PictureInfo *lpInfo){
		check_instance();
		DKUTIL_CAST_SUSIE(GetPictureInfoType,"GetPictureInfo");
		return exe(buf,len,flag,lpInfo);
	}
	/*
	面倒だから後は各自で実装！（爆
	int  GetPicture (LPSTR buf,long len,unsigned int flag, HANDLE *pHBInfo,HANDLE *pHBm,
									FARPROC lpPrgressCallback,long lData);
	int  GetPreview (LPSTR buf,long len,unsigned int flag, HANDLE *pHBInfo,HANDLE *pHBm,
									FARPROC lpPrgressCallback,long lData);

	// '00AM'の関数 
	int  GetArchiveInfo (LPSTR buf, long len, unsigned int flag, HLOCAL *lphInf);
	int  GetFileInfo (LPSTR buf,long len, LPSTR filename, unsigned int flag, fileInfo *lpInfo);
	int  GetFile (LPSTR src,long len, LPSTR dest,unsigned int flag, FARPROC prgressCallback,long lData);

	int  ConfigurationDlg(HWND parent,int fnc);
	*/

protected:


private:
	static int	PASCAL	DummyCallback__( int , int, long )
	{
		return( 0 );		// always continue
	}

	void check_instance(){
		if(mDLL.empty()){
			DKUTIL_THROW_OR_NOTICE(std::logic_error("not loaded susie plugin"));
		}
	}
	DLLManager mDLL;
	///余分なバッファがあるが、これは安全のため。
	char mPluginInfo[4 + 5];
	int LoadSusie(){
		//load common
		
		GetPluginInfoType Info =
			(GetPluginInfoType ) mDLL.find("GetPluginInfo");
		if(Info == NULL ) return edk_FAILED;
		NULL_CHAR_ARRAY(mPluginInfo);

		
		mDLL.load_function("IsSupported");
		mDLL.load_function("ConfigurationDlg");
		
		//無条件読み込みします。(≦(._.)≧ ペコ
		mDLL.load_function("GetPictureInfo");
		mDLL.load_function("GetPicture");
		mDLL.load_function("GetPreview");
		mDLL.load_function("GetArchiveInfo");
		mDLL.load_function("GetFileInfo");
		mDLL.load_function("GetFile");

		//Plug-in APIバージョン をゲット
		Info(0,mPluginInfo,5);
		//unknown filter
		if(isUnknownFilter()) return edk_FAILED;
		/*
		//ここらへんのロード条件･･･　カナリ怪しい。
		if(isImportFilter())
		{
			mDLL.load("GetPictureInfo");
			mDLL.load("GetPicture");
			mDLL.load("GetPreview");
		}else if(isExportFilter()){
			mDLL.load("GetPictureInfo");
			mDLL.load("GetPicture");
			mDLL.load("GetPreview");
		}else if(isArchiveExtractor()){
			mDLL.load("GetArchiveInfo");
			mDLL.load("GetFileInfo");
			mDLL.load("GetFile");
		}
		*/
		return edk_SUCCEEDED;
	}

/*
//関数 説明 
GetPluginInfo Plug-inに関する情報を得る 
IsSupported 展開可能な(対応している)ファイル形式か調べる 
GetPictureInfo 画像ファイルに関する情報を得る 
GetPicture 画像を展開する 
GetPreview プレビュー・カタログ表示用画像縮小展開ルーティン 
ConfigurationDlg Plug-in設定ダイアログ表示 



00AM Plug-in 関数 説明 
GetPluginInfo Plug-inに関する情報を得る 
IsSupported 展開可能な(対応している)ファイル形式か調べる 
GetArchiveInfo アーカイブ内のすべてのファイルの情報を取得する 
GetFileInfo アーカイブ内の指定したファイルの情報を取得する 
GetFile アーカイブ内のファイルを取得する 
ConfigurationDlg Plug-in設定ダイアログ表示 

*/
	

public:
	SusieManager(const char *plugin_name=NULL){
		NULL_CHAR_ARRAY(mPluginInfo);
		if(plugin_name){
			reset(plugin_name);
		}
	}
	virtual ~SusieManager(){}

	bool reset(const char *plugin_name){
		if(!plugin_name) return false;
		//何処にあるか分からないからこれでいいや！！
		//if(false==FileExist(plugin_name)) return false;
		mDLL.reset(plugin_name);
		return DKUTIL_SUCCEEDED(LoadSusie());
	}
	bool empty(){return mDLL.empty();}

};


}//end of dkutil namespace



#endif