

/*!
  @author d金魚
  @since 2004/09/24
	@note
	licence:BSD Licence
	
*/


#ifndef DKUTIL_UNDO_HPP
#define DKUTIL_UNDO_HPP

#include <dkutil/dktl/traits.hpp>
#include <dkutil/boost/utility.hpp>


namespace dkutil{

namespace policy{

///random_access_iteratorが使える奴に使う（std::vectorやstd::dequeとかかな？
template<class Iterator_Type,typename size_type_t>
struct undo_random_access_iterator_policy{
	typedef size_type_t size_type;
	///ただのiteratorとtypedefするとconstだか生だか分からなくなるので＾＾；
	typedef Iterator_Type iterator_type;
	//果たして｡｡｡
	//BOOST_STATIC_ASSERT(typeid(iterator_type) == typeid(std::random_access_iterator_tag))



	struct data_type{
		size_type index_;
		//iterator_type it_;
		data_type(size_type index,const iterator_type &) :
		index_(index){ }
		friend bool operator==(const data_type &x,const data_type &y){
			return (x.index_ == y.index_);
		}
	};
	static inline void non_index_type(){
		//DKUTIL_THROW_OR_NOTICE(std::logic_error("undo_not_dependence_erase_iterator_policy is not save index"));
	}
	static void non_iterator_type(){
		DKUTIL_THROW_OR_NOTICE(std::logic_error("undo_not_dependence_erase_iterator_policy is not save iterator"));
	}

};

///std::listやstd::setとかに使う
template<class Iterator_Type,typename size_type_t>
struct undo_not_dependence_erase_iterator_policy{
	typedef size_type_t size_type;
	///ただのiteratorとtypedefするとconstだか生だか分からなくなるので＾＾；
	typedef Iterator_Type iterator_type;
	struct data_type{
		//size_type index_;
		iterator_type it_;
		data_type(size_type index,const iterator_type &it) :
		it_(it){ }
		friend bool operator==(const data_type &x,const data_type &y){
			return (x.it_ == y.it_);
		}
	};
	static void non_index_type(){
		DKUTIL_THROW_OR_NOTICE(std::logic_error("undo_not_dependence_erase_iterator_policy is not save index"));
	}
	static inline void non_iterator_type(){
		//DKUTIL_THROW_OR_NOTICE(std::logic_error("undo_not_dependence_erase_iterator_policy is not save index"));
	}
};


///念のため両方記憶しておくヤツ
template<class Iterator_Type,typename size_type_t>
struct undo_both_save_policy
{
	typedef size_type_t size_type;
	///ただのiteratorとtypedefするとconstだか生だか分からなくなるので＾＾；
	typedef Iterator_Type iterator_type;
	struct data_type{
		size_type index_;
		iterator_type it_;
		data_type(size_type index,const iterator_type &it) :
		it_(it) , index_(index){ }

		friend bool operator==(const data_type &x,const data_type &y){
			return ((x.index_ == y.index_) && (x.it_ == y.it_));
		}
		//friend bool operator !=
	};
	static inline void non_index_type(){
	
	}
	static inline void non_iterator_type(){
		
	}
};

}//end of policy namespace


/*!
@code
struct hoge{int i;};

typedef std::vector<hoge> hoge_manager_t;
//typedef std::list<hoge> hoge_manager_t;
undo_dynamic_adapter<
	hoge_manager_t,
	policy::undo_random_access_iterator_policy<
		hoge_manager_t::iterator,
		hoge_manager_t::size_type
	>
> hoge_undo;

@endcode
みたいにして使う。ゴメンネ＾＾；テンプレートスパグェツィで･･･
*/
template<class CONTAINER__,class POLICY__>
class undo_dynamic_adapter{
public:
	typedef CONTAINER__ container_type;
	typedef undo_dynamic_adapter<CONTAINER__, POLICY__> self_type;
	typedef POLICY__ policy_type;

	typedef typename policy_type::size_type size_type;
	typedef typename policy_type::iterator_type d_iterator;

	//typedef typename container_type::size_type size_type;
	typedef typename container_type::allocator_type allocator_type;
	typedef typename container_type::value_type value_type;
	//typedef typename container_type::iterator iterator;
	typedef typename container_type::iterator c_iterator;
	//typedef typename container_type::const_iterator const_iterator;
	
	//undoデータ保存用データ構造
	typedef typename policy_type::data_type operate_memory_data;


	///operate state container  deque or list... umm   list!
	typedef std::list<operate_memory_data> OS_C;
	///operate state
	typedef OS_C::iterator OPERATE_STATE;

	template<class _T,typename Traits,class Boss,class StateIterator,class C_Iterator>
	class iterator_base {//slist
	public:
		friend Boss;

	  typedef _T value_type;
		//typedef typename Traits::value_type value_type;
		typedef typename Traits::pointer    pointer;
		typedef typename Traits::reference  reference;

		typedef iterator_base<
			_T, 
			policy::non_const_traits<_T>
			,Boss,
			StateIterator,
			C_Iterator
		> iterator;
		typedef iterator_base<
			_T, 
			policy::const_traits<_T> ,
			Boss,
			StateIterator,
			C_Iterator
		>    const_iterator;
		typedef iterator_base<
			_T,
			Traits,
			Boss,
			StateIterator,
			C_Iterator
		> self_type;
		


		typedef std::size_t size_type;
		typedef std::ptrdiff_t difference_type;
		
		typedef Boss *boss_pointer;
		typedef Boss &boss_reference;

		//typedef Boss::value_type::operate_memory_data data_type;
		typedef StateIterator state_iterator;
		typedef C_Iterator c_iterator;

		//friend self_type::iterator;
		//friend self_type::const_iterator;
		

		iterator_base(boss_pointer x,state_iterator sit,c_iterator cit){//mediator...?
			mc = cit;
			ms = sit;
			mx = x;
		}
		iterator_base(){
			
			mx = NULL;
		}
		iterator_base(const iterator &x){
			
			mx = x.mx;
		}

		reference operator*()const{
			return (*mc);
		}
		pointer operator->() const {
			return &(operator*()); 
		}
		self_type &operator++(){
			//bool found = false;
			while(1){
				mc++;
				bool a = (mc == mx->getContainer()->end());
				if(a){
					break;
				}

				if(ms->it_ == mc){
					bool b = (ms != (mx->getUndoContainer()->end()));
					if(b){
						ms++;
					}
				}else{
					break;
				}
			}
					
			return (*this);
		}

		///@note 0以下の値はエラーになる。
		self_type &operator+=(size_type x)const{
			/*if(x + ms >= mx->size())
			{//ここは >= か > か？
				DKUTIL_THROW_OR_NOTICE(std::out_of_length("gapbuffer::iterator += out of length"));
			}
			mc += x;
			*/

			//あとはiteratorの実装に任せた＾＾；
			for(size_type i=0;i<x;i++){
				operator++();
			}
			return (*this);
		}

		//使えない。コスト高すぎ！
		self_type operator++(int){
			self_type t = *this;
			operator++();
			return t;
		}

		//ここの引数、self_typeではなく、
		//iteratorにしないとconst_iterator時 に使えない。
		bool operator==(const iterator &x)const{
			return (ms == x.ms && mx == x.mx);
		}
		bool operator!=(const iterator &x)const{
			return !(self_type::operator==(x));
		}
	protected:
		c_iterator getIt(){
			return mc;
		}
	private:
		c_iterator mc;
		
		state_iterator ms;
		
		boss_pointer mx;
		
	};

	typedef iterator_base<
		value_type,
		policy::non_const_traits<value_type>,
		self_type,
		OS_C::iterator,
		container_type::iterator
	> iterator;
	friend iterator;

	//reverse iterator はまた今度＾＾；
	
	/*struct operate_data{
		typedef operate_memory_data self_type;
		size_type point_;
		operate_memory_data(size_type point,size_type length) : 
			point_(point) {}
	};*/

	
private:





	OS_C mOS;
	OPERATE_STATE mState;


	container_type *mpC;

	void push_back_log(){
		mOS.push_back(
			operate_memory_data(
				mpC->size(),
				boost::prior( mpC->end() )
			)
		);
	}
	void push_front_log(){
		mOS.push_back(
			operate_memory_data(
				0,
				mpC->begin()
			)
		);
	}
	void insert_log(size_type index,c_iterator it){
		mOS.push_back(
			operate_memory_data(
				index,
				it
			)
		);
	}

protected:

public:
	OS_C *getUndoContainer(){
		return &mOS;
	}
	iterator begin(){
		return iterator(this,mOS.begin(),mpC->begin());
	}
	iterator end(){
		return iterator(this,mOS.end(),mpC->end());
	}
	undo_dynamic_adapter(	container_type *p){
		if(NULL==p){
			DKUTIL_THROW_OR_NOTICE(
				std::invalid_argument("undo_dynamic_adapter constructor NULL pointer")
			);
		}
		mpC = p;
	}
	void push_back(const value_type &x){
		mpC->push_back(x);
		push_back_log();
	}
	void pop_back(){
		push_back_log();
	}
	void push_front(const value_type &x){
		insert(mpC->begin(),x);
		//mpC->push_front(x);
		push_front_log();
		
	}
	void pop_front(){
		push_front_log();
	}
	
	void insert( c_iterator it,const value_type &x){
		//もし、iterator指定が出来なかったときはthrowがぶっ飛ぶ
		policy_type::non_iterator_type();
		mpC->insert(it,x);
		insert_log(0,it);
	}
	void erase( c_iterator it){
		policy_type::non_iterator_type();
		//mpC->erase(it);
#	error erase用マーカーの作成
		insert_log(0,it);
	}
	void erase( iterator it){
		erase(it.getIt());
	}
	container_type *getContainer(){
		return mpC;
	}
/*	void insert(size_type index,const T &x){
		//もし、index指定が出来なかったときはthrowがぶっ飛ぶ
		policy_type::non_index_type();
		mpC->insert(index,x);
		insert_log(index,mpC->end());
	}
	void erase(size_type index){
		policy_type::non_index_type();
		mpC->erase(index);
		insert_log(index,mpC->end());
	}
*/
};


}//end of dkutil namepsace

#endif //end of include once