

#ifndef _dkutilParser__
#define _dkutilParser__

#include "dkutilString.h"
#include "dkutilDefined.h"
#include "dkutilStdio.h"

namespace dkutil{

///dkutilParser内で使うパースした文字列コンテナのタイプstd::list<std::string>らしいです。
typedef std::list<std::string> PARSE_STRING_CONTAINER;

/*!
@param c[out] PARSE_STRING_CONTAINER型の参照を入れる。
@param str[in] 終端に二つのNULLが現れるような文字列
@param permitsize[in] str文字列バッファがどこまでアクセスして良いか
@return falseだったら一つもパースしてない。
@note
GetLogicalDriveStringsとか
GetPrivateProfileStringとかとのコンボが考えられます。
これらの関数で取得した文字列をパースするのに最適です＾＾
a:\<NULL>c:\<NULL>d:\<NULL>e:\<NULL><NULL> みたいな・・・
*/
///終端に二つのNULLが現れるまで、strに入れた文字列をNULLで区切って引数cにぶち込みます。
inline bool ParseStringUpToDoubleNull(PARSE_STRING_CONTAINER &c,
																const char *str,
																size_t permitsize)
{
	bool isPush=false;
	std::string buff;
	if(permitsize == 0){return false;}
	permitsize--;//-1にしておく
	for(size_t i=0;i<permitsize/*permitsize - 1*/;i++)
	{
		if(str[i] != NULL){
			buff.push_back(str[i]);
		}else{
			if(!buff.empty()){
				c.push_back(buff);
				buff.clear();
				isPush = true;
			}
			if(str[i + 1] == NULL){
				
				break;
			}
		}
	}
	return isPush;

}
/*!
@note
C:\Windows\core.exeだったら
C:　Windows　core.exe にパースされる。
*/
///ディレクトリとかふぃいるパスとかをパースする。	
inline bool ParseStringDirectoryName(PARSE_STRING_CONTAINER &c,
																		 const char *directory,
																		 size_t length
																		 )
{
	bool isPush =false;
	std::string buff;
	if(length == 0){return false;}
		
	for(size_t i=0;i<length;i++)
	{
		if(directory[i] != '\\'){
			buff.push_back(directory[i]);
		}else{
			if(!buff.empty()){
				c.push_back(buff);
				buff.clear();
				isPush = true;
			}
		}
	}
	return isPush;
}
	




namespace private_{





class counter{
	int mc;
	void check(){
		DK_TRUE_ASSERT_OR_THROW(
			mc <= 0,
			std::logic_error("private_::counter decrement error");
		);
	}
public:
	counter(){mc=0;}
	~counter(){check();}
	int operator++(){
		mc++;
	}
	int operator--(){
		check();
	
		mc--;
	}
	int get(){return mc;}
};


///パーシングした文字列のタイプをゲットする
extern int GetParsedStringType(const char *s);
/*!
@param s[in] Parsingした文字列(例えば、"0xaaff"とか"aho"とか"abj0x"とか
@param v[out] GeneralPurposeVariable型の変数
@return falseだと失敗
*/
///文字列をGeneralPurposeVariable型に変換
extern bool ParsedStringToGeneralPurposeVariable(const char *s,GeneralPurposeVariable *v);





class CommandLineParser{
public:
	typedef std::string::size_type size_type;
	struct DATA_TYPE{
		std::string str;//コマンドラインの文字列
		std::string sig;//シグネチャ
	};
	typedef std::list<DATA_TYPE> CONTAINER_TYPE;
	//typedef CONTAINER_TYPE::iterator iterator;
	typedef CONTAINER_TYPE::const_iterator const_iterator;

	
		
private:
	std::string mbuf;
	int mNum;//コマンドラインにぶち込んだ数。
	CONTAINER_TYPE mList;
	
	std::string::const_iterator ParsingOption(
		std::string::const_iterator ch,const std::string &buf,
		int num,CONTAINER_TYPE &c)
	{

		if( ch == buf.end() || *ch=='\0'){ return ch;}
		DATA_TYPE data;
		//search logic
		{
			
			//search signature
			for(;ch != buf.end();ch++){
				if(*ch==' ' || *ch=='\0' || *ch=='"'){
					break;
				}else 
				data.sig += (*ch);
			}
			if( ch == buf.end()){ goto end;}
			if(*ch=='-' || *ch=='/'){
				ch--;
				goto end;
			}
			ch++;
			if( ch == buf.end()){ goto end;}
			if(*ch=='-' || *ch=='/'){
				ch--;
				goto end;
			}
			//search data
			for(;ch != buf.end();ch++){
				if(//*ch==' ' ||
					*ch=='\0' || *ch=='"'){
					break;
				}
				data.str += (*ch);
			}
			
		}
	end:
		c.push_back(data);
		//元に戻す
		return ch;
	}
	std::string::const_iterator ParsingNormal(
		std::string::const_iterator ch,const std::string &buf,
		int num,CONTAINER_TYPE &c)
	{
		if(*ch=='\0') return ch;
		DATA_TYPE data;
		for(;ch != buf.end();ch++)
		{
			if(*ch==' '){
					break;
			}
			data.str += (*ch);
		}
		c.push_back(data);
		return ch;
	}

	void Parsing(const std::string &buf,int num,CONTAINER_TYPE &c){
		typedef std::string::const_iterator it_type;
		for(it_type it=buf.begin();it != buf.end();it++)
		{
			if( (*it) == '\0') break;
			if( isSpace((*it)) ) continue;
			if( (*it) == '-' || (*it) == '/'){
				it++;
				//指定して、サーチ後のイテレータを貰う
				it = ParsingOption(it,buf,num,c);

			}else{
				it = ParsingNormal(it,buf,num,c);
			}
			if(it == buf.end() || (*it) == '\0') break;
		}

	}
	
public:
	CommandLineParser(const char *str=NULL,int num=0){
		if(str==NULL && num==0){return;}
			reset(str,num);
		
	}
	virtual ~CommandLineParser(){}
	void reset(const char *str,int num){
		mbuf = str;
		mNum = num;
		mList.clear();
		Parsing(mbuf,mNum,mList);
	}
	const_iterator begin()const{return mList.begin();}
	const_iterator end()const{return mList.end();}
	void clear(){mbuf.clear();mList.clear();}
};

inline bool is0x(const char *s){
	if(s[0]=='0' && s[1]=='x'){
		return true;
	}
	return false;
}

inline bool ParsedStringToBoostAny(const char *s,boost::any *Any)
{
	radix_convert conv;
	int r=GetParsedStringType( s );
	
	switch(r)
	{
	case enuDU2CSV_STRING:
	case enuDU2CSV_STRING_32MORE:
		*Any = s;
		break;
	case enuDU2CSV_DOUBLE:
		//DOUBLE（浮動小数点)だった
		double d;
		d = ::atof( s );
		*Any = d;
		break;
	case enuDU2CSV_INT:
		{//INTだった
			int t;
			if(is0x(s)){
				t = conv.a16toi(s);
			}else{
				t = ::atoi(s);
			}
			*Any = t;
			break;
		}
	case enuDU2CSV_LONGLONG:
		{//LONGLONGだった
			LONGLONG t;
			if(is0x(s )){
				t = conv.a16toll(s) ;
			}else{
				t =  ::_atoi64(s);
			}
			*Any = t;
			break;
		}
	case enuDU2CSV_ULONGLONG:
		{//ULONGLONGだった
			ULONGLONG t;
			if(is0x(s)){
				t = conv.a16toull( s );
			}else{
				t = atoull( s ) ;
			}
			*Any = t;
			break;
		}
	default:
		return false;
	}//end of switch
	return true;
}





class CSVParser{
public:
	typedef std::string::size_type size_type;
	struct DATA_TYPE{
		std::string str;
	};
	typedef std::deque<DATA_TYPE> CONTAINER_TYPE;
	typedef CONTAINER_TYPE::const_iterator const_iterator;
private:
	CONTAINER_TYPE mC;
	std::string mbuf;

	bool CheckEnd(std::string::iterator &it,std::string &buf){
		if(buf.end() != it) return false;
		return true;
	}
	bool CheckBegin(std::string::iterator &it,std::string &buf){
		if(buf.begin() != it) return false;
		return true;
	}
	bool CheckChar(std::string::iterator it,char d){
		if((*it) != d) return false;
		return true;
	}
	bool CheckBreak(std::string::iterator &it,std::string &buf){
		if((*it) == '\0' || it == buf.end() ) return true;
		return false;
	}
	void Parsing(std::string &buf,CONTAINER_TYPE &container){
		typedef std::string::iterator it_type;

		it_type it = buf.begin();

		//これでパーシングミスのチェックをする。
		//counter c;
		DATA_TYPE data;
		
		for(;it != buf.end();it++)
		{
			if(CheckBreak(it,buf))
			{
				break; 
			}else if(CheckChar(it,',') || CheckChar(it,'\n'))
			{
				if(data.str.empty()){
					//if(CheckBegin(it,buf)){ continue;}
					continue;
				}
				container.push_back(data);
				data.str.clear();
				continue;
			}else
			{
				if(CheckBegin(it,buf)){
				}else{
					if(CheckChar(it - 1,'\n') && CheckChar(it,',')){ continue;}
				}
				if((*it) != '\n'){
					data.str += (*it);
				}
			}
		}
		if(!data.str.empty()){
			container.push_back(data);
		}
	}

public:
	CSVParser(const char *str=NULL){
		if(str){
			reset(str);
		}
	}
	virtual ~CSVParser(){}
	void reset(const char *str){
		mbuf = str;
		Parsing(mbuf,mC);
	}
	void clear(){mbuf.clear();mC.clear();}
	const_iterator begin()const{return mC.begin();}
	const_iterator end()const{return mC.end();}

};


/*!
CSVParserでパースした文字列を解析して、文字列なら文字列、数字なら数字データにします。
対応しているのは、
DKINGYO_LONGLONG_MINからDKINGYO_ULONGLONG_MAXまでの整数（10進16進）
doubleな小数
std::stringな文字列です。

@note
<b>Sample Code</b><br>
<PRE>
int main(int argc,char **argv){

	static char *target="123,StudioKingyo,Parsing,\n0x001111,okok!!!,ahoaho,\ndot,0x01sdf";
	CSVParser a;
	a.clear();
	a.reset(target);
	{
		CSVParser::const_iterator it=a.begin();
		for(;it != a.end();it++){
			std::cout << (*it).str.c_str() << std::endl;
		}
	}
	CSVAnalyzer s;
	s.reset(a);
	{
		printf("//**********BEGIN\n");
		CSVAnalyzer::const_iterator it=s.begin();
		for(;it != s.end();it++){
			(*it).print();
			printf("\n");
		}
		printf("//**********END\n");
	}
	return 0;
}
</PRE>
*/
class CSVAnalyzer{
public:
	typedef dkutil::GeneralPurposeVariable DATA_TYPE;
	typedef std::deque<DATA_TYPE> CONTAINER_TYPE;
	typedef CONTAINER_TYPE::const_iterator const_iterator;
	typedef CONTAINER_TYPE::const_reverse_iterator const_reverse_iterator;
	explicit CSVAnalyzer(const CSVParser &parser){
		reset(parser);
	}
	CSVAnalyzer(){}
	void reset(const CSVParser &parser){
		reset(parser.begin(),parser.end());
	}
	void reset(CSVParser::const_iterator be,
		CSVParser::const_iterator en){

		Analyzing(mc,be,en);

	}
	const_iterator begin()const{	return mc.begin();}
	const_iterator end()const{return mc.end();}
	const_reverse_iterator rbegin()const{return mc.rbegin();}
	const_reverse_iterator rend()const{return mc.rend();}



protected:


	static void Analyzing(CONTAINER_TYPE &container,
		CSVParser::const_iterator be,CSVParser::const_iterator en)

	{
		CSVParser::const_iterator it=be;
		//radix_convert conv;
		//スレッドロックする
		for(;it != en;it++)
		{
			DATA_TYPE data;
			if(false==ParsedStringToGeneralPurposeVariable(
				(*it).str.c_str(),
				&data)
				)
			{
				throw std::logic_error("Analizingでエラりました!!");
			}
			/*
			int r=GetParsedStringType( (*it).str.c_str() );
			
			switch(r)
			{
			case enuDU2CSV_STRING:
			case enuDU2CSV_STRING_32MORE:
				data.insert((*it).str);
				break;
			case enuDU2CSV_DOUBLE:
				//DOUBLE（浮動小数点)だった
				data.insert( ::atof( (*it).str.c_str() ) );
				break;
			case enuDU2CSV_INT:
				{//INTだった
					if(private_::is0x((*it).str.c_str())){
						data.insert(  conv.a16toi((*it).str.c_str()) );
					}else{
						data.insert(  ::atoi((*it).str.c_str()) );
					}
					break;
				}
			case enuDU2CSV_LONGLONG:
				{//LONGLONGだった
					if(private_::is0x((*it).str.c_str())){
						data.insert( conv.a16toll((*it).str.c_str()) );
					}else{
						data.insert( ::_atoi64((*it).str.c_str()) );
					}
					break;
				}
			case enuDU2CSV_ULONGLONG:
				{//ULONGLONGだった
					if(private_::is0x((*it).str.c_str())){
						data.insert( conv.a16toull( (*it).str.c_str() ) );
					}else{
						data.insert( atoull( (*it).str.c_str() ) );
					}
					break;
				}
			default:
				throw std::logic_error("Analizingでエラりました!!");
			}//end of switch
			*/

			container.push_back(data);
		}//end of for
		//ここでアンロック

	}
	CONTAINER_TYPE mc;
};

}//end of private_ namespace

//typedef private_::CommandLineParser CommandLineParser;

//typedef private_::CSVParser CSVParser;

//typedef private_::CSVAnalyzer CSVAnalyzer;

/*
struct GeneralPurposeVariableScanEx : public private_::GeneralPurposeVariable{
	GeneralPurposeVariableEx(boost::any){
	}


};
*/

}//end of namespace

#endif//end of include once