/**
@author d金魚
@brief ファイルの拡張子に関する事
@since 2004/12/02
*/
#ifndef DKUTIL_FILESYSTEM_PATH_STRING_HPP
#define DKUTIL_FILESYSTEM_PATH_STRING_HPP

//#include <dkutil_c/dkc.h>
#include <string>
#include <dkutil_c/dkc.h>
#include <dkutil/boost/parm_string.hpp>
#include <dkutil/parser/char_util.hpp>
//#include <dkutil/filesystem/interface.hpp>
//#include <dkutil/filesystem/utility.hpp>

namespace dkutil{
	
#if 0
/*!
@todo insert erase系のバグをなくす･･･。
といいますか、std::stringをWrapした形に直しちゃおうかしら？
*/
class path_string{
public:
	// type definitions
	typedef std::string STRING_TYPE;
	typedef char CHAR_TYPE;
  typedef CHAR_TYPE           value_type;
  typedef CHAR_TYPE*          iterator;
  typedef const CHAR_TYPE*    const_iterator;
  typedef CHAR_TYPE&          reference;
  typedef const CHAR_TYPE&    const_reference;
  typedef std::size_t    size_type;
  typedef std::ptrdiff_t difference_type;
private:
	DKC_PATHSTRING *mpPath;

	void check_obj()const{
		if(NULL==mpPath){
			DKUTIL_THROW_OR_NOTICE(filesystem_error("path_string / オブジェクトの初期化が出来ていない"));
		}
	}
	void destract__()
	{
		dkcFreePathString(&mpPath);
	}
	void construct__(const char *str)
	{
		if(mpPath){
			destract__();
		}
		printf("...\n");
		printf(str);
		mpPath = dkcAllocPathString(str);
		
		
		dkcmNOT_ASSERT(NULL==mpPath);//ワイルドカードの可能性
		printf(dkcPathStringPointer(mpPath));
	}
	struct end_element__{
		end_element__(){}
		int ok;
	};

	


public:
	path_string(){
		mpPath = NULL;
		construct__(NULL);
	}

	path_string(parm_string str){
		mpPath = NULL;
		printf(str.c_str());

		construct__(str.c_str());
	}
	virtual ~path_string(){
		destract__();
	}
	  // iterator support
  iterator begin() {
		check_obj();
		return (CHAR_TYPE *)mpPath->mString->mStream->mBuffer;
	}
  const_iterator begin() const {
		return c_str(); 
	}
  iterator end() {
		check_obj();
		return ((CHAR_TYPE *)mpPath->mString->mStream->mBuffer) + size(); 
	}
  const_iterator end() const {
		return c_str() + size(); 
	}

	///data reference
	const CHAR_TYPE *c_str()const{
		check_obj();
		return dkcPathStringPointer(mpPath);
	}
	const CHAR_TYPE *c_str(){
		check_obj();
		return dkcPathStringPointer(mpPath);
		//return (CHAR_TYPE *)mpPath->mString->mStream->mBuffer;
	}
	///@see c_str()
	const CHAR_TYPE *data()const{	return c_str();}
	
	///size reference
	size_type size()const{
		return dkcPathStringSize(mpPath);
	}
	///@see size()
	size_type length()const{return size();}
	///空だとTRUE
	bool empty()const{
		return size()==0;
	}
	/*size_type capacity()const{
	}
	//resize 
	void reserve(size_type reg_arg = 10){

	}
	void resize(size_type size,char c){
	}*/


	//copy concatenate... 
	
	///パス文字列で初期化
	path_string &assign(const char *s){
		return (*this) = s;
	}
	path_string &assign(const STRING_TYPE &s){
		return (*this) = s;
	}
	path_string &assign(const path_string &s){
		return (*this) = s;
	}
	///パス文字列追加
	path_string &append(const char *s){
		return (*this) += s;
	}
	path_string &append(const path_string &s){
		return (*this) += s;
	}	
	path_string &append(const STRING_TYPE &s){
		return (*this) += s;
	}

	//operators
	path_string &operator +=(const char xx){
		char x[]={xx,'\0'};
		return append(x);
	}
	path_string &operator +=(const char *x){	
		if(DKUTIL_FAILED(dkcPathStringConcatenate(mpPath,x,strlen(x)))){
			throw std::invalid_argument("path_string:path string invalid error");
		}
		return (*this);
	}
	path_string &operator +=(const STRING_TYPE &x){	
		if(DKUTIL_FAILED(dkcPathStringConcatenate(mpPath,x.c_str(),x.size()))){
			throw std::invalid_argument("path_string:path string invalid error");
		}
		return (*this);
	}
	path_string &operator +=(const path_string &x){	
		if(DKUTIL_FAILED(dkcPathStringConcatenate(mpPath,x.c_str(),x.size()))){
			throw std::invalid_argument("path_string:path string invalid error");
		}
		return (*this);
	}

	path_string &operator =(const char *x){
		if(DKUTIL_FAILED(dkcPathStringCopy(mpPath,x,strlen(x)))){
			throw std::invalid_argument("path_string:path string invalid error");
		}
		return *this;
	}	
	path_string &operator =(const STRING_TYPE &x){
		if(DKUTIL_FAILED(dkcPathStringCopy(mpPath,x.c_str(),x.size()))){
			throw std::invalid_argument("path_string:path string invalid error");
		}
		return *this;
	}
	path_string &operator =(const path_string &x){
		if(DKUTIL_FAILED(dkcPathStringCopy(mpPath,x.c_str(),x.size()))){
			throw std::invalid_argument("path_string:path string invalid error");
		}
		return *this;
	}

	//取得系

	///driveへの文字列定数
	int drive()const{
		int t = 0;
		check_obj();
		dkcPathStringGetDrive(mpPath,(char *)&t,sizeof(t));
		return t;
	}
	const STRING_TYPE drive_str()const{
		int t = drive();
		if(t > CHAR_MAX){
			throw std::runtime_error("drive_str()ありえないエラー");
		}
		char b[4];
		b[0] = (char)t;
		b[1] = ':';
		b[2] = '\\';
		b[3] = '\0';
		return STRING_TYPE(b);
	}
	static inline relative(parm_string str){
		return dkcIsRelativityPath(str.c_str());
	}
	static inline absolute(parm_string str){
		return dkcIsAbsolutelyPath(str.c_str());
	}

		


	///MAX_PATHをゲット。
	int max_path()const{
		return dkcdMAXPATH;
	}
	/*path_string &prev(){


	}
	path_string &next(){


	}*/
	///ファイルパスを格納するバッファのサイズをゲット
	int max_path_buffer()const{
		return dkcdMAXPATH_BUFFER;
	}
	const STRING_TYPE filename()const{
		char buff[dkcdMAXPATH_BUFFER]="";
		check_obj();
		if(DKUTIL_FAILED(
			dkcPathStringGetFileName(mpPath,buff,sizeof(buff))
			)){
			DKUTIL_THROW_OR_NOTICE(filesystem_error("dkcPathStringGetFileName Error"));
		}
		return STRING_TYPE(buff);
	}
	const STRING_TYPE directory()const{
		char buff[dkcdMAXPATH_BUFFER]="";
		check_obj();
		if(DKUTIL_FAILED(
			dkcPathStringGetDirectory(mpPath,buff,sizeof(buff))
			)){
			DKUTIL_THROW_OR_NOTICE(filesystem_error("dkcPathStringGetDirectory Error"));
		}
		return STRING_TYPE(buff);
	}
	///ファイルの拡張子を得る。（無い場合はSTRING_TYPEはemptyになる（と思う･･･
	const STRING_TYPE extention()const{
		char buff[dkcdMAXPATH_BUFFER]="";
		check_obj();
		if(DKUTIL_FAILED(
			dkcPathStringGetFileExtension(mpPath,buff,sizeof(buff))
			)){
			DKUTIL_THROW_OR_NOTICE(filesystem_error("dkcPathStringGetFileExtension Error"));
		}
		return STRING_TYPE(buff);
	}
	///ファイルパスが存在するかどうか
	bool exist()const{
		return FileAndFolderExist(c_str());
	}
				
		


};

	/*
	path_element_iterator begin_pe(){
		return path_element_iterator(this);
	}
	path_element_iterator end_pe(){
		return path_element_iterator(this,end_element__());
	}


	//挿入 
	///path_element_iteratorの次に文字列が挿入される。
	///@return 挿入した文字列の次へのpath_element_iteratorを返す。
	path_element_iterator insert(path_element_iterator it,const char *src)
	{
		if(DKUTIL_FAILED(
			dkcPathStringElementInsert_Logic(mpPath,it.count(),src,strlen(src))
			)){
			throw std::invalid_argument("path_string::replace src invalid error");
		}
		int point = dkcSJIS_SearchPathSep(&c_str()[it.count()]);
		it.mCount += (size_t)point + 1;//\\の見つかった位置だから＋１
		return it;
	}
	///path_element_iteratorが指している部分をすべてsrcで置換
	path_element_iterator replace(path_element_iterator it,const char *src)
	{
		if(DKUTIL_FAILED(
			dkcPathStringElementReplace_Logic(mpPath,it.count(),src,strlen(src))
			)){
			throw std::invalid_argument("path_string::replace src invalid error");
		}

		int point = dkcSJIS_SearchPathSep(&c_str()[it.count()]);
		it.mCount += (size_t)point + 1;
		return it;
	}
	//削除 
	
	///ファイルパスの要素の文字列を削除

	path_element_iterator erase(path_element_iterator it)
	{
		if(it.mCount == 0)
		{//この時は消せない。
			return it.next();
		}
		dkcPathStringElementErase_Logic(	mpPath,it.count());
		return it;
	}
	*/

	/*class path_element_iterator{
		friend path_string;

		path_string *mPath;
		size_t mCount;
		STRING_TYPE mStr;
		int mEnd;
		 DKUTIL_CONST_STATIC_DEFINE(int,eEnd,1);

		void init(path_string *Path=NULL,bool isEnd=false){
			mCount = 0;
			mStr.clear();
			mEnd = 0;
			if(!Path){
				mPath = NULL;
				return;
			}
			mPath = Path;
			

			char buff[dkcdMAXPATH]="";//""はmStrに入れる時のもしもの時の
		
			dkcPathStringDevideBegin_Logic(mPath->mpPath,&mCount,buff,sizeof(buff));
		
			mStr = buff;
			
			if(true==isEnd)
			{//終了用iteratorの時は
				mCount = dkcPathStringSize(mPath->mpPath);
				mEnd = 2;
			}
		}
		///insertやreplaceする時に使う。
		size_type count()const{
			return mCount;
		}
		const char *c_str()const{
			dkcmNOT_ASSERT(!mPath);
			return mStr.c_str();
		}
		size_type size()const{
			dkcmNOT_ASSERT(!mPath);
			return mStr.size();
		}
	public:
		typedef path_element_iterator self_type;
	

		path_element_iterator(path_string *Path=NULL)
		{
			mPath = NULL;//これがないとinit()はバグる。
			init(Path);
		}
		path_element_iterator(path_string *Path,end_element__ x){
			mPath = NULL;
			init(Path,true);
		}

		~path_element_iterator(){
			mPath = NULL;
		}


	
		self_type next(){
			dkcmNOT_ASSERT(!mPath);
			{
				char buff[dkcdMAXPATH]="";
				if(edk_EndProcess==
					dkcPathStringDevideNext_Logic(mPath->mpPath,&mCount,buff,sizeof(buff))
					){
					if(mEnd <= eEnd){
						mEnd++;//こういうフラグ的な仕様は控えたいのだが･･･。

					}
				}

				mStr = buff;
			}
			return (*this);
		}
		self_type operator++(){
			return next();
		}
		self_type operator++(int){
			++(*this);
			return (*this);
		}
		self_type &operator=(const self_type &x){
			init(x.mPath);
			return (*this);
		}
		std::string &operator*(){
			return mStr;
		}
		std::string *operator->(){
			return &mStr;
		}
		friend bool operator==(const self_type &x,const self_type &y){
			dkcmNOT_ASSERT(x.mPath == NULL || y.mPath == NULL);
			if(( (x.mEnd >=eEnd) && (y.mEnd >= eEnd) )){//この条件は余り良くないな･･･。
				return true;
			}
			return (x.mCount==y.mCount
				&& strcmp(x.c_str(),y.c_str()) == 0
				);
		}
		friend bool operator!=(const self_type &x,const self_type &y){
			return !(x == y);
		}

	};//end of path_element_iterator
	friend path_element_iterator;//二重friend... ｳﾜｧｧｧﾝヽ(｀Д´)ノ

	typedef const path_element_iterator const_path_element_iterator;
	*/
	/*path_string(const char *str=NULL){
		mpPath = NULL;
		construct__(str);
	}*/
#else

typedef parm_string path_string_ref;
#endif
}//end of dkutil namespace



#endif
