

#ifndef _dkutilLog__h__
#define _dkutilLog__h__


#include <dkutil/dktl/map_ex.hpp>
#include <dkutil/filesystem/utility.hpp>
#include <dkutil/filesystem/std_filestream.hpp>
//#include <dkutil/parser/general_purpose_data.hpp>

//#include <dkutil/dktl/array_onebyone.hpp>
#include <dkutil/math/utility.hpp>

namespace dkutil{


//extern bool dInitLog( const char *filename );

//extern bool dAddLog( const char *filename,const char *str , ... );


///エラーログ(ファイル)を初期化する @param filename[in] ファイルの名前
inline bool dInitLog( const char *filename )
{
	FILE *fp;
	// エラーログファイルを開く(初期化)
	if(NULL==(fp = fopen( filename , "wt" ))){
		return false;
	}
	fclose( fp ) ;
	
	return true;
}
///ログを吐く @param filename[in] ファイルネーム @param str[in] 吐く文字列
inline bool dAddLog( const char *filename,const char *str , ... ){
	FILE *fp=NULL;
	char s[2048]="";
	SET_VA_LIST_INSERT_YEN_N(s,2048,str);
	
	//ファイルをオープン
	if(NULL == (fp = fopen( filename , "at" )))
		return false;
	// エラーログファイルに書き出す
	fputs( s , fp ) ;
	fclose( fp ) ;
	return true;
}


inline bool dump(parm_string filename,const void *ptr,size_t size,bool rewrite=false)
{
	if(false==rewrite && true==FileExist(filename)){
		return false;
	}
	std_filestream stream;
	stream.reset(filename,write_mode | binary_mode);
	if(false==stream.open())
	{
		return false;
	}
	stream.responsible_write(ptr,size);
	return true;
}



#if 0

//プロトタイプ宣言
class dumper;
class outputer;

///追記専用std::string... logger,outputerクラスが使う。
template<class STRING_=std::string>
class postscript_string_base : public STRING_{
	void add_str_logic(const char *s){
		STRING_TYPE(*this) + s;//operator+(s);
		char mys[2]={'\n','\0'};
		STRING_TYPE(*this) + mys;
	}
public:
	friend class dumper;
	friend class outputer;
	typedef STRING_ STRING_TYPE;
	postscript_string_base(const STRING_TYPE &s) : STRING_TYPE(s){

	}
	postscript_string_base(const char *str) : STRING_TYPE(str){}

	postscript_string_base(){}
	//virtual ~postscript_string_base(){}

	void add_str(const char *s){
		add_str_logic(s);
	}
	void add_str(const std::string &s){
		add_str_logic(s.c_str());
	}
	void add_str(char *str,...){
		char s[2048]="";
		SET_VA_LIST(s,sizeof(s),str);
		add_str_logic(s);
	}



};

typedef postscript_string_base<> postscript_string ;

///なんだよ！outputerッてダサイ名前は･･･
class outputer{
public:
	struct output_interface{
	protected:
		///各自実装してね。そしてregistする前に必要であれば、この関数を呼んでおくこと。
		virtual bool setFileName(const char *) = 0;
	public:
		///委譲する関数
		virtual bool output(const char *,...) = 0;
		virtual bool output(const std::string &) = 0;
	};

private:
	typedef dkutil::map_ex<int,output_interface *> MAP_TYPE;
	MAP_TYPE mMap;
	ansi_rand mARand;
	///まだ書き込んでない文字列
	postscript_string mOutStr;
	///すでに書きこんだ文字列
	postscript_string mOutedStr;
	void add_str(const char *s){
		/*size_t len = strlen(s);
		if('\n' == s[len]){
			s[len] = '\0';
		}*/
		mOutStr.add_str(s);
	}
	void ClearOutedStr(){mOutedStr.clear();}

protected:
	postscript_string &getOutedStr(){return mOutedStr;}
public:
	outputer(){}
	virtual ~outputer(){}
	
	
	bool regist(output_interface *ptr){
		bool flag = false;
		for(int i=0;i<INT_MAX;i++){
			if(true==mMap.SetData(mARand.rand(),ptr)){
				break;
				flag = true;
			}
		}
		return flag;
	}
	bool regist(int priority,output_interface *ptr){
		return mMap.SetData(priority,ptr);
	}
	void put(const char *s){
		add_str(s);	
	}
	///今まで内部で保持していた文字列をiterate_outで出力する。
	void out();
	///今まで登録(regist)してある出力関数に文字列を出力する。
	void iterate_out(const std::string &s){
		MAP_TYPE::iterator it = mMap.begin();
		for(;it != mMap.end();it++)
		{
			(*it).second->output(s);
		}
	}
	void iterate_out(const char *s){
		MAP_TYPE::iterator it = mMap.begin();
		for(;it != mMap.end();it++)
		{
			(*it).second->output(s);
		}
	}
	friend dumper;
};

///俗：吐く者、糞をする者　コンピュータ：（メモリ）ダンプ
class dumper{
private:
	std::string mFileName;
public:
	dumper(const char *filename=NULL){
		//mFileName = filename;
		setFileName(filename);
	}
	virtual ~dumper(){}
	void setFileName(const char *filename){
		if(!filename) return;
		mFileName = filename;
	}

	///@return 上手く、すべてを書きこめた時はTRUE
	virtual bool ToTextFile(const std::string &my);
	///@see ToTextFile(const std::string &my)
	virtual bool ToTextFile(outputer &ou){
		return ToTextFile(ou.getOutedStr());
	}
	//@see Windowに出力
	/*virtual bool ToWindow(const std::string &){

	}*/



};


namespace policy{

class console : public outputer::output_interface{
};
class ods: public outputer::output_interface{
};
class debug_window: public outputer::output_interface{
};


}//end of policy namespace


class HTMLLog{
protected:
	std::string m_name;
	int m_exSize;

	/**	ログ開始
		ログ出力の開始処理をします。
	*/
	bool LogoutStart(char *titlename)
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return false;

		fprintf( fp,
			"<HTML>\n"
			"<HEAD>\n"
			"<META http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\">\n"
			"<TITLE>%s</TITLE>\n"
			"<STYLE type=\"text/css\">\n"
			"<!--\n"
			"BODY{\n"
			"  font-size : 12px;\n"
			"  font-family : \"ＭＳ ゴシック\";\n"
			"}\n"
			"-->\n"
			"</STYLE>\n"
			"</HEAD>\n"
			"<BODY bgcolor=\"#ffffff\" text=\"#000000\" link=\"#444444\" vlink=\"#444444\" alink=\"#444444\">\n",
			titlename );

		fclose( fp );
		return true;
	}

	/**	ログ終了
		ログ出力の終了処理をします。
	*/

	bool LogoutEnd()
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return false;

		fprintf( fp,
			"</BODY>\n"
			"</HTML>\n" );

		fclose( fp );
		return true;
	}

public:
	///@param logfiletitle[in] HTMLログファイルのタイトルを指定してください。
	///@param fullpathname[in] ファイルパスはフルパス指定で御願いします。
	HTMLLog(char *logfiletitle="DebugLog",char *fullpathname = "debuglog.html")
	{
		m_name = fullpathname;
		m_exSize = MAX_PATH;
		LogoutStart(logfiletitle);
	}
	virtual ~HTMLLog()
	{
		LogoutEnd();
	}
	//各、拡張可能引数の文字列をどうするか。（まだ実装してない。
	void SetExtensionStringSize(int size){
		m_exSize = size;
	}

	///@param name[in] ファイル名は振るパス指定で御願いします。
	void SetLogFileName(char *name){		m_name = name;	}
	char *GetLogFileName(){return const_cast<char *>(m_name.c_str());}

	/**	ログ出力カテゴリー
		ログ出力をカテゴリー用の色で処理をします。

		@param pStr		[in] 描画文字列（printf()と同様の書式）
	*/
	void LogoutMainCategory( char *pStr )
	{


		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;

		fprintf( fp,
			"<TABLE width=\"100%%\" bgcolor=\"#000000\">\n"
			"  <TBODY>\n"
			"    <TR>\n"
			"      <TD align=\"center\">\n"
			"        <B>\n"
			"          <FONT color=\"WHITE\">" );

		vfprintf( fp, pStr, (char*)(&pStr + 1) );

		fprintf( fp,
			"</FONT>\n"
			"        </B>\n"
			"      </TD>\n"
			"    </TR>\n"
			"  </TBODY>\n"
			"</TABLE>\n" );

		fclose( fp );
	}
	/**	ログ出力キーワード
		ログ出力をキーワード用の色で処理をします。

		@param pStr		[in] 描画文字列（printf()と同様の書式）
	*/
	void LogoutKeyword( char *pStr,... )
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;

		fprintf( fp, "<B><FONT color=\"BLUE\">" );
		vfprintf( fp, pStr, (char*)(&pStr + 1) );
		fprintf( fp, "</FONT></B>" );

		fclose( fp );
	}
	/**	ログ出力エラー
		ログ出力をエラー用の色で処理をします。

		@param pStr		[in] 描画文字列（printf()と同様の書式）
	*/
	void LogoutError( char *pStr,... )
	{
		
		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;
		//bool f;
		//char *str;
		//BEGIN_GET_MANY_ARG(f,str,m_exSize,pStr);
		//if(f==false) return;
		fprintf( fp, "<B><FONT color=\"RED\">" );
		//fprintf( fp, str);
		vfprintf( fp, pStr, (char*)(&pStr + 1) );
		fprintf( fp, "</FONT></B>" );
		//END_GET_MANY_ARG(str);
		fclose( fp );
	}

	/**	ログ出力ＯＫ
		ログ出力をＯＫ用の色で処理をします。

		@param pStr		[in] 描画文字列（printf()と同様の書式）
	*/
	void LogoutOK( char *pStr,... )
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;

		fprintf( fp, "<B><FONT color=\"GREEN\">" );
		vfprintf( fp, pStr, (char*)(&pStr + 1) );
		fprintf( fp, "</FONT></B>" );

		fclose( fp );
	}

	/**	ログ出力太字
		ログ出力を太字で行います。
		@param pStr		[in] 描画文字列（printf()と同様の書式）
	*/
	void LogoutStrong( char *pStr,... )
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;

		fprintf( fp, "<B>" );
		vfprintf( fp, pStr, (char*)(&pStr + 1) );
		fprintf( fp, "</B>" );

		fclose( fp );
	}

	/*!	ログ出力<BR>
		ログ出力をします。

		@param pStr		[in] 描画文字列（printf()と同様の書式）
	*/
	void Logout( char *pStr,... )
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;

		vfprintf( fp, pStr, (char*)(&pStr + 1) );

		fclose( fp );
	}
	/*!	ログ改行<BR>
		ログ出力の改行処理をします。
	*/
	void LogoutNextLine( void )
	{

		FILE *fp = fopen( GetLogFileName(), "at" );
		if ( fp == NULL ) return;

		fprintf( fp, "<BR>\n" );

		fclose( fp );
	}

};
#if !defined(__GNUG__)
class HTMLLogFactory{
public:
	typedef array_onebyone_ex<HTMLLog> CONTAINER_TYPE;
	typedef CONTAINER_TYPE::handle handle;
	typedef CONTAINER_TYPE::size_type size_type;
	typedef CONTAINER_TYPE::reference reference_type;
protected:
	CONTAINER_TYPE m_c;
public:
	HTMLLogFactory(){}
	virtual ~HTMLLogFactory(){}
	handle Construct(char *title,char *filefullpath){ 
		return m_c.push(HTMLLog(title,filefullpath));
	}
	void Destroy(handle h){
		m_c.pop(h);
	}
	HTMLLog &Reference(handle h){
		return m_c.at(h);
	}
	size_type size(){	return m_c.size();}
};
#endif

void outputer::out(){
	PARSE_STRING_CONTAINER c;
	const char sep[]={'\n','\0'};
	ParseString(c,sep,mOutStr.c_str(),mOutStr.size(),true);
	PARSE_STRING_CONTAINER::iterator it=c.begin();
	for(;it != c.end();it++){
		iterate_out((*it));
	}
	//アウトプットした物を保存。
	mOutedStr.add_str(mOutStr);
	//アウトプットしたからあとはクリア〜
	mOutStr.clear();
}


bool dumper::ToTextFile(const std::string &my)
{
	if(mFileName.empty()) return false;
	file_operator file(mFileName.c_str(),
		"at");
	size_t tmp = 0;
	file.open();
	tmp = file.write(my.c_str(),my.size());
	file.close();
	return (tmp == my.size());
}
/*
void HTMLLogTest(){
#	ifdef USE_DKINGYO_OBJECT_TEST
	HTMLLogFactory f;
	char *titlename="HTMLLogTest Debug";
	char *filefullpath="HTMLLogTestReport.html";
	typedef HTMLLogFactory::handle handle;
	typedef HTMLLogFactory::reference_type r_type;
	//生成する。
	handle h = f.Construct(titlename,filefullpath);
	//こう参照しても良いが、
	f.Reference(h).LogoutMainCategory("HTMLLogTest");
	
	//このようにリファレンスを取得しておくと面倒な文が減る
	r_type ref = f.Reference(h);
	ref.Logout("Directory of Windows is %s",GetWindowsDirReturnCharPtr());

	ref.LogoutStrong("太字もできます＾＾");
	ref.LogoutStrong("<font size=10>改行する時はLogoutNextLine();を呼び出してくださいね＾＾</font>");
	ref.LogoutNextLine();
	ref.LogoutError("エラーの時　色");
	ref.LogoutOK("OKな時　色");

	ref.LogoutKeyword("Keyword色");
	ref.LogoutNextLine();
	ref.Logout("もち、ログを出力する時はタグもOKですよ＾＾でぁ〜〜（では、さようならの略）");
	//別に後始末しなくてもOK HTMLLogFactory側で終了時に開放してくれるので
	f.Destroy(h);
#	else
	ODS("Please use USE_DKINGYO_OBJECT_TEST \n");
#endif
}*/
//extern void HTMLLogTest();

/*	
inline bool GetVersionInfoForProgrammer(std::string &s){
	char buff[1024]="";
	GetVersionInfo v;

	const int num = 
	const char *dllname[num]={
		"KERNEL32.DLL",
		"AVIFIL32.DLL",
		"MSVFW32.DLL",
		"COMCTL32.DLL",
		"MSVCRT.dll",
		"OLEPRO32.dll",
		"OLEAUT32.dll",
		"MSHTML.dll",
	}
	s += 

}
*/

#endif //end of if 0

}//end of dkutil namespace



#endif //end of include once

	
