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

#ifndef DKUTIL_PARSER_CSV_HPP
#define DKUTIL_PARSER_CSV_HPP

#include <deque>
#include <string>
#include <dkutil/parser/string_util.hpp>
#include <dkutil/parser/general_purpose_data.hpp>

namespace dkutil{
	

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;
	typedef CONTAINER_TYPE::iterator iterator;
	iterator begin_(){
		return mC.begin();
		}
	iterator end_(){
		return mC.end();
		}

	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(){}
	/*!
	@param CVS文字列へのポインタ
	*/
	///CVSを解析する
	void reset(const char *str){
		mbuf = str;
		Parsing(mbuf,mC);
	}
	bool empty()const{
		return mC.empty();
	}
	template<class T>
	struct remove_func : public std::binary_function<bool, T, T> 
	{
		bool operator()(const T it){
			return isSpace(it);
		}
	};
	void space_erase(){
		iterator it = begin_();
		if(empty()){
			return;
		}
		for(;it != end_();it++)
		{
			std::string::iterator si = (*it).str.begin();
			for(;si != (*it).str.end();si++){
				if(isSpace((*si))){
					//std::string::iterator t = si;
					//t++;
					si = (*it).str.erase(si);
					//si = t;
					if(si==(*it).str.end()){
						break;
					}
				}
				
			}//end of string for
			
			//remove_func<char> fn;
			//std::remove_if(si,(*it).str.end(),fn);
			if((*it).str.empty()){
				iterator t = it;
				t++;
				mC.erase(it);
				it = t;
				if(it == end_()){
					break;
				}
			}
		}//end of for

	}
	size_t size()const{
		return mC.size();
	}
	///クラス内部の解析済み文字列をクリアする。
	void clear(){mbuf.clear();mC.clear();}
	///クラス内部の解析済み文字列にアクセスする。内部のSTLコンテナの仕様は各自ソースを見てください。
	const_iterator begin()const{return mC.begin();}
	///内部のSTLコンテナの番兵を得る。
	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(){}
	size_t size()const{
		return mc.size();
	}
	///@param parser[in] CVSParserクラスをぶち込みます。
	void reset(const CSVParser &parser){
		reset(parser.begin(),parser.end());
	}
	/*!
	@param be[in] CVSParserクラスのconst_iteratorを入れる。
	@param en[in] 同上、しかし、beよりenの方が番兵に近いことが条件
	*/
	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();}
	///STLに使い慣れていましたら、説明は要らないと思います^^；(オイオイ
	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;
			StringToVariable conv;
			bool f = conv.StringToGeneralPurposeVariable(&data,(*it).str.c_str(),(*it).str.size());
			
			if(f==false){
				throw std::logic_error("Analizingでエラりました!!");
			}
			container.push_back(data);
		}//end of for
		//ここでアンロック

	}
	CONTAINER_TYPE mc;
};

}//end of namespace
#endif

