/**
@file ini.hpp
@author d金魚
@note
bisonの使用方法参考サイト
 http://www1.kcn.ne.jp/~robe/pf/pf012.html
*/



/*!
@author d金魚

*/

#ifndef DKUTIL_PARSER_INI_HPP
#define DKUTIL_PARSER_INI_HPP


#include <dkutil/parser/general_purpose_data.hpp>
#include <dkutil_c/dkcDefined.h>
#include <dkutil/parser/interface.hpp>

/*
typedef struct dkcINIParser{
	void *obj;
}DKC_INI_PARSER;

enum{
	edkc_
};
DKC_INI_PARSER *WINAPI dkcAllocINIParser(const char *filename);
int WINAPI dkcFreeINIParser(DKC_INI_PARSER **p);

int WINAPI dkcINIParserLoad(DKC_INI_PARSRE *p)
BOOL WINAPI dkcINIParserExist(DKC_INI_PARSRE *p,const char *section,const char *key);
BOOL WINAPI dkcINIParserExistSection(DKC_INI_PARSRE *p,const char *section);

int WINAPI dkcINIParserVariableType(DKC_INI_PARSRE *p,const char *section,const char *key);

int WINAPI dkcINIParserGetULONGLONG(DKC_INI_PARSRE *p,
*/
namespace dkutil{



#ifdef _MSC_VER
#	if defined(DEBUG) || defined(_DEBUG)
#		if defined(dkcdMultiThread) || defined(_MT)
//#			pragma message("import dkutil_cMTd")
#			pragma comment(lib,"dkutil_parserMTd")
#		else
//#			pragma message("import dkutil_cd")
#			pragma comment(lib,"dkutil_parserd")
#		endif
#	else
#		if defined(dkcdMultiThread) || defined(_MT)
//#			pragma message("import dkutil_cMT")
#			pragma comment(lib,"dkutil_parserMT")
#		else
//#			pragma message("import dkutil_c")
#			pragma comment(lib,"dkutil_parser")
#		endif
#	endif
#endif

/**
*.ini用パーサー
@note
GetPrivate系のWin32APIはWin9x系だとイロイロと制限が多いのでこう言うクラスを用意した。
*/
class CINIParser{
	void *mObj;
	
public:


	CINIParser(const char *filename=NULL);
	~CINIParser();
	enum{
		error = edk_FAILED,
		///見つかった
		found = edk_SUCCEEDED,
		///いわいる　見つからない
		not_found,
		///セクションが見つからない
		not_found_section = not_found,
		///キーが見つからない
		not_found_key,
		

	
	};
	static bool is_error(int error_code){
		return found != error_code;
	}
	bool reset(const char *filename);
	void clear();
	bool good()const;
	int find_ex(const char *section,const char *key,GeneralPurposeVariable *value,
		UINT option);
	int find(const char *section,const char *key,GeneralPurposeVariable *value);
	
	inline void find_exception(parm_string section,parm_string key,GeneralPurposeVariable *value)
	{
		if(found != find(section,key,value)){
			std::string s = "not found | ";
			s += section.c_str();
			s += " | ";
			s += key.c_str();
			throw parser_error(s.c_str());
		}


	}

};

#if 0
/*!
@note
<b>GetPrivateProfileSection</b><br>
Windows 95:<br>
セクションのサイズは32KBを超えてはいけません。<br>
Windows NT:<br>
セクションのサイズに制限はありません。<br>
*/
class inifile_operator{
//#	define ini_exception(s) std::runtime_error("ini_operator::" + s);

	std::string mFileName;
	///なんらかのエラーをチェックする。
	void CheckException(){
		if(mFileName.empty())
		{
			//あー、ファイル名が指定されてねぇなぁ
			throw std::runtime_error("ini_operator::... error / not defined filename");
		}
	}
	///Windows95はタブを扱えないため。
	bool search_tab(const char* str){
		char c=1;
		bool result=false;
		for(size_t i=0;c!=UINT_MAX || c=='\0';i++){
			
			if(str[i]=='\0' && '\0'==c){
				break;
			}else if(str[i]=='\t'){
				result = true;
				break;
			}
			c = str[i];
		}
		return result;
	}

		

public:
	inifile_operator(const char *filename){
		if(filename){
			reset(filename);
		}
	}
	virtual ~inifile_operator(){}
	bool reset(const char *filename){
		/*if(false==CheckWin9x(filename)){
			return false;
		}*/
		mFileName = filename;
	}
	/*!
	@param data[in] データの入れ方はMSDNでWritePrivateProfileSectionの第二引数の説明を見てください。
	@return dkutil::edkResult 
	成功：edk_SUCCEEDED / 失敗：edk_FAILED / edk_ArgumentException : 引数が合わない。
	*/
	int write_section(LPCTSTR section_name,LPCTSTR data){
		CheckException();
		if(isOS9x()){
			//MSDNには書いていないけど、信用できないのでいちおうチェック。
			if(true==search_tab(data)){
				return edk_ArgumentException;
			}
		}
		if(false==(0 != WritePrivateProfileSection(
			section_name,// セクション名へのポインタ
			data,// 書き込むデータへのポインタ
			mFileName.c_str()// ファイル名へのポインタ
			))){
			return edk_FAILED;
		}
		return edk_SUCCEEDED;
	}
	int write_string(LPCTSTR section_name,LPCTSTR key_name,LPCTSTR str){
		CheckException();
		if(isOS9x()){
			if(true==search_tab(str)){
				return edk_ArgumentException;
			}
		}
		if(0==WriteProfileString(
			section_name,// セクション名へのポインタ
			key_name,// キー名へのポインタ
			str// 書き込むデータへのポインタ
			)){
			return edk_FAILED;
		}
		return edk_SUCCEEDED;
	}




  ///ini ファイルからセクション全体を削除する
	bool delete_section( const char *SectionName )
	{
		CheckException();
		return ( 0 != WritePrivateProfileString( SectionName, NULL, NULL, mFileName.c_str() ));
	}
	///  ini ファイルからキーを削除する
	bool delete_key( const char *SectionName, const char *KeyName)
	{	
		CheckException();
		return (0 != WritePrivateProfileString( SectionName, KeyName,
			NULL, mFileName.c_str() ));
	}
	/// キーが ini ファイルに存在するかどうかを確かめる。
	bool exist( const char *SectionName, const char *KeyName )
	{
		CheckException(); ;
		// 指定したキーが見つからない場合、
		//関数 GetPrivateProfileInt() は１回目の呼び出しで０を、
		//２回目の呼び出しで１を返す。
		return (
			GetPrivateProfileInt(
				SectionName, KeyName, 0, mFileName.c_str() 
				) == 	GetPrivateProfileInt(
			SectionName, KeyName, 1, mFileName.c_str())
			);
	}
	/*!
	@param SectionName[in] セクション名へのポインタ
	@param Buffer[out] バッファへのポインタ
	@param Size[in] バッファのサイズ
	@param FileName[in] ファイルの名前
	@return 成功：edk_SUCCEEDED / バッファが足らない：edk_BufferOverFlow;
	Windows9x系だと、安全のためedk_FAILEDを返す。
	*/
	static int LoadSectionLogic(LPCTSTR SectionName,
						LPTSTR Buffer,DWORD Size,
						LPCTSTR FileName)
	{
		DWORD r;
		if(false==isOS9x()){ return edk_FAILED;}
		r = GetPrivateProfileSection(SectionName,Buffer,Size,FileName);
		if(r == Size - 2){	return edk_BufferOverFlow;}		
		return edk_SUCCEEDED;
	}
//#	undef ini_exception
};
#endif

}//end of dkutil namespace


#endif//end of include once

