/**
@file commandline.hpp
@author d金魚
@brief command line parser
*/

#ifndef DKUTIL_PARSER_COMMANDLINE_HPP
#define DKUTIL_PARSER_COMMANDLINE_HPP

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

namespace dkutil{
	

#if 1
/**
std::vector互換
コマンドライン解析機能付きみたいな？
*/
template<class T>
class CommandLineParser : public std::vector<T>{
public:
	///コマンドライン用コンテナ
	//typedef std::vector<T> commandline_vector;
	typedef std::vector<T> base_type;
	typedef base_type::size_type size_type;
	typedef base_type::const_iterator const_iterator;
	typedef base_type::iterator iterator;

	typedef CommandLineParser self_type;

	///split_winmain compare class
	struct sw_compare{
		sw_compare(){}
		static inline bool isSpace(char t){
			return dkutil::isSpace(t);
		}
		static inline bool isQuotes(char t){
			return t == '\"';
		}
		static inline size_t length(const char *p){
			return strlen(p);
		}

	};

	/**
	@param T 文字一文字のの型 charとか
	@param CompareObj Tの比較関数郡の入ったクラス
	@param ResultSet 結果を返すSTLコンテナ
	*/
	///winmainを分割するファンクター
	template<class T,class CompareObj,class ResultSet>
	class split_winmain
	{
	public:
		typedef T value_type;
		typedef CompareObj compare_type;
		typedef ResultSet result_set;
		bool operator()(const T *ap,ResultSet &r)
		{
			CompareObj f;
			size_t len = f.length(ap);
			size_t i;
			ResultSet::value_type tv;
			
			/**
			0   普通
			1   " "ダブルクォーテーション内
			*/
			int state = 0;
			for(i=0;i<len;i++)
			{
				if(0==state && f.isSpace(ap[i])){
					r.push_back(tv);
					tv.clear();
					continue;
				}
				if(f.isQuotes(ap[i])){
					state = (state == 0) ? 1 : 0;
					continue;
				}
			}
			if(0 != state){
				return false;
			}
			return true;
		}

	};
	typedef split_winmain<char,sw_compare,base_type> split_winmain_char;
private:
	//commandline_vector mC;

public:
	CommandLineParser(int argc,const char *argv[]){
		reset(argc,argv);	
	}
	CommandLineParser(){
		//clear();
	}
	bool reset(int argc,const char *argv[])
	{
		for(int i=0;i<argc;i++){
			base_type::push_back(argv[i]);
		}
		return true;
	}
	bool reset_for_winmain(){
		split_winmain_char obj;
		bool r = obj(GetCommandLine(),*this);
		return r;
	}
	void clear(){
		base_type::clear();
		}
	size_type size()const{
		return base_type::size();
	}


};


#else


/**
@todo
<s>boost::program_optionsが存在するのでこのクラスは廃止予定</s>
program_optionはVC6では使えないのでREWRITEする予定。
@note
デフォルトでWinMain用です。
*/
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;

	typedef CONTAINER_TYPE::size_type size_type;
		
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();
	}
	size_type size()const{
		return mList.size();
	}
	///main()の為のreset()
	void reset_for_main(int ac,const char *av[]){
		if(ac<=1){
			return;
		}
		std::string s;
		for(int i=1;i<ac;i++){
			s += av[i];
		}
		reset(s.c_str(),ac - 1);
	}
};
#endif

}//end of namespace
#endif

