#ifndef DKUTIL_GENERAL_PURPOSE_DATA_HPP
#define DKUTIL_GENERAL_PURPOSE_DATA_HPP


#include <string>
#include <dkutil/output/console_output.hpp>
#include <dkutil/parser/interface.hpp>
#include <dkutil/macro.hpp>
#include <dkutil/parser/string_printf.hpp>
#include <dkutil/parser/to_string.hpp>

namespace dkutil{


union FourByteUnion{
	int i;
	UINT ui;
	//float f;(最適化による･･･
	short s2[2];
	char c4[4];
	BYTE byte4[4];
};



/*!
基本的な型は何でも入れることの出来る変数みたいなもの。
文字列をパーシングしたときなどに使用。
*/	
class GeneralPurposeVariable{
public:
	union UNION_TYPE{
		int i;
		UINT ui;
		LONGLONG ll;
		ULONGLONG ull;
		double d;
	};
private:
	int mType;
	UNION_TYPE mUni;
	std::string mStr;
public:
	GeneralPurposeVariable(){
		clear();
	}

	GeneralPurposeVariable(int i){
		clear();
		insert(i);
		//mStr.clear();
	}
	GeneralPurposeVariable(UINT ui){
		clear();
		insert(ui);
	}
	GeneralPurposeVariable(LONGLONG ll){
		clear();
		insert(ll);
	}
	GeneralPurposeVariable(ULONGLONG ull){
		clear();
		insert(ull);
	}
	GeneralPurposeVariable(double d){
		clear();
		insert(d);
	}
	GeneralPurposeVariable(const char* ca){
		clear();
		insert(ca);
	}
	GeneralPurposeVariable(std::string s){
		clear();
		insert(s);
	}
	GeneralPurposeVariable(const GeneralPurposeVariable &one){
		mType = one.mType;
		mUni = one.mUni;
		mStr = one.mStr;
	}
	~GeneralPurposeVariable(){
	
	}
	const UNION_TYPE &GetUnionData()const{return mUni;}
	const char *c_str()const{return mStr.c_str();}
	std::string &GetString(){return mStr;}

	void insert(int ig){
		mStr.clear();
		mUni.i = ig;
		mType = edkInt;
	}
	void insert(UINT uig){
		mStr.clear();
		mUni.ui = uig;
		mType = edkUInt;
	}
	void insert(LONGLONG llg){
		mStr.clear();
		mUni.ll=llg;
		mType = edkLongLong;
	}
	void insert(ULONGLONG ullg){
		mStr.clear();
		mUni.ull=ullg;
		mType = edkULongLong;
	}
	void insert(double dg){
		mStr.clear();
		mUni.d=dg;
		mType = edkDouble;
	}
	void insert(const char *s){
		mStr = s;
		mType = edkString;
	}
	void insert(const std::string &s){
		mStr = s;
		mType = edkString;
	}
	bool isIntMinus()const{
		if(isInt())
		{
			if(mUni.i < 0){
				return true;
			}
		}
		if(isLongLong()){
			if(mUni.ll < 0){
				return true;
			}
		}

		return false;
	}

	template<typename INT_T>
	bool getInt(INT_T &dest){
		switch(type()){
		case edkInt:
			dest = mUni.i;
			break;
		case edkUInt:
			dest = mUni.ui;
			break;
		case edkLongLong:
			dest = mUni.ll;
			break;
		case edkULongLong:
			dest = mUni.ull;
			break;
		default:
			return false;
		}
		return true;
	}
	bool getForceBool(bool &dest){
		if(isString())
		{
			const char *t[]={"false","true"};

			for(size_t i=0;i<2;i++){
				std::string::size_type pos = mStr.find(t[i]);
				if(std::string::npos != pos){
					if(i == 0){
						dest = false;
					}else{
						dest = true;
					}
					return true;
				}
			}
			return false;
		}
		//int
		{
			LONGLONG ll;
			ULONGLONG ull;
			if(getForceInteger(ll,edkLongLong)){
				if(ll == 1){
					dest = true;
				}else if(ll == 0){
					dest = false;
				}else{
					return false;
				}
				return true;
			}
			if(getForceInteger(ull,edkULongLong)){
				if(ull == 1){
					dest = true;
				}else if(ull == 0){
					dest = false;
				}else{
					return false;
				}
				return true;
			}
		}
		return false;
	}
		
	template<typename INT_T>
	bool getForceInteger(INT_T &dest,int atype)
	{
		switch(atype){
		case edkInt:
			if(false==isInt()){
				return false;
			}

			break;
		case edkUInt:
			if(isIntMinus()){
				return false;
			}
			if(isLongLong() || isULongLong()){
				return false;
			}

			break;
		case edkLongLong:
			if(isULongLong()){
				return false;
			}

			break;
		case edkULongLong:
			if(isIntMinus()){
				return false;
			}

			break;
		default:
			return false;
		}
		getInt(dest);
		return true;
	}



	int type()const{return mType;}
	bool isDouble()const{	return (edkDouble == mType);}
	bool isInt()const{return (edkInt == mType);}
	bool isUInt()const{return (edkUInt == mType);}
	bool isLongLong()const{return (edkLongLong == mType);}
	bool isULongLong()const{return (edkULongLong == mType);}
	bool isString()const{return (false==mStr.empty());}
	bool empty()const{
		return (false == (isDouble() || isInt() || isUInt() || isLongLong() || isULongLong() || isString()));
	}
	int getForceInt()const{
		int r;
		if(isUInt()){
			if(INT_MAX < mUni.ui){
				DKUTIL_THROW_OR_NOTICE(parser_error("GeneralPurposeVariable::getForceInt() convert error"));
			}
			r = (int)mUni.ui;
		}else if(isInt()){
			r = mUni.i;
		}else{
			DKUTIL_THROW_OR_NOTICE(parser_error("GeneralPurposeVariable::getForceInt() convert error"));
		}
		return r;
	}
	const char *getForceString(){
		if(!isString()){
			//DKUTIL_THROW_OR_NOTICE(parser_error("GeneralPurposeVariable::getForceString() convert error"));
			mStr = to_string();
			mType = edkString;
		}
		return c_str();
	}




	///初期化する。
	void clear(){
		mType = edkVariableUnknown;
		DKUTIL_STRUCTURE_INIT(mUni);
		mStr.clear();
	}

	///文字列を優先的にprintfする
	bool print()const{
		switch(type()){
		case edkInt:
			SuperODS("%d",mUni.i);
			break;
		case edkUInt:
			SuperODS("%u",mUni.ui);
			break;
		case edkLongLong:
			SuperODS("%d",mUni.ll);
			break;
		case edkULongLong:
			SuperODS("%u",mUni.ull);
			break;
		case edkDouble:
			SuperODS("%f",mUni.d);
			break;
		case edkString:
			dkutil::SuperODS("%s",mStr.c_str());
			break;
		default:
			return false;
		}
		return true;
	}
	///@return 帰ってきたstd::stringがempty()だったらERROR
	std::string to_string()const{
		std::string x;
		switch(type())
		{
		case edkInt:
			x = to_string_int32(mUni.i);
			break;
		case edkUInt:
			x = to_string_uint32( mUni.ui );
			break;
		case edkLongLong:
			x = to_string_int64(mUni.ll);
			break;
		case edkULongLong:
			x = to_string_uint64(mUni.ull);
			break;
		case edkDouble:
			x = to_string_double(mUni.d);
			break;
		case edkString:
			return mStr;
			break;
		default:
			break;
		}
		return x;

	}
	///自分自身のデータを文字列化して自分自身に入れなおす
	void to_string_self(){
		std::string s = to_string();
		if(s.empty()){
			DKUTIL_THROW_OR_NOTICE(parser_error("GeneralPurposeVariable::to_string_self() convert error"));
			return;
		}
		insert(s);
	}
	std::ostream &operator<<(std::ostream &x)const
	{
		
	
		return x;
	}

	friend bool operator ==(const GeneralPurposeVariable &one,const char *str){
		if(!one.isString()) return false;
		return (one.mStr == str);
	}
	friend bool operator ==(const GeneralPurposeVariable &one,std::string str){
		if(!one.isString()) return false;
		return (one.mStr == str);
	}
	friend bool operator ==(const GeneralPurposeVariable &one,int two){
		if(!one.isInt()) return false;
		return (one.mUni.i == two);
	}
	friend bool operator ==(const GeneralPurposeVariable &one,LONGLONG two){
		if(!one.isLongLong()) return false;
		return (one.mUni.ll == two);
	}
	friend bool operator ==(const GeneralPurposeVariable &one,ULONGLONG two){
		if(!one.isULongLong()) return false;
		return (one.mUni.ull == two);
	}
	friend bool operator ==(const GeneralPurposeVariable &one,float d){
		if(!one.isDouble()) return false;
		return (one.mUni.d == d);
	}
	friend bool operator ==(const GeneralPurposeVariable &one,double d){
		if(!one.isDouble()) return false;
		return (one.mUni.d == d);
	}
		
	friend bool operator ==(const GeneralPurposeVariable &one,const GeneralPurposeVariable &two)
	{
		if(one.type() != two.type()) return false;
		bool result = false;
		switch(one.type()){
		case edkInt:
			result = (one.mUni.i == two.mUni.i);
			break;
		case edkUInt:
			result = (one.mUni.ui == two.mUni.ui);
			break;
		case edkLongLong:
			result = (one.mUni.ll == two.mUni.ll);
			break;
		case edkULongLong:
			result = (one.mUni.ull == two.mUni.ull);
			break;
		case edkDouble:
			result = (one.mUni.d == two.mUni.d);
			break;
		case edkString:
			result = (one.mStr == two.mStr);
			break;
		default:
			return false;
		}
		return result;
	}




};


}//end of dkutil namespace

#endif//end of include once
