

/*!
  @author d金魚
  @file text_edit_buffer.h
  @brief text editor用データ構造
  @since 2004/06/06
	@note
	licence:BSD Licence
	note:
	nysl/gapbuffer.hを参考にしました。

	@todo
	削除マーカーを付けておいてundo redoを表現しようと思う。
	結構めんどくさそう･･･。
*/


#ifndef _dkutil_text_edit_buffer
#define _dkutil_text_edit_buffer


#include <nysl/gapbuffer.h>
#include <dkutil/synchronized.hpp>


namespace dkutil{



///@note non thread safe
template<typename T,class POLICY_ = gap_buffer<T> >
class text_edit_buffer : protected POLICY_
{

public:
	typedef POLICY_ policy_type;
	typedef policy_type base_type;
	typedef typename base_type::size_type size_type;
	typedef typename base_type::value_type value_type;
	//typedef T element_type;
	typedef text_edit_buffer<T,POLICY_> self_type;
protected:
	typedef self_type *pointer;
	typedef self_type &reference;
public:
	//undo redoの記憶データ
	struct operate_memory_data{
		typedef operate_memory_data self_type;
		operate_memory_data(size_type min_,size_type max_) : mmin(min_),mmax(max_){}
		size_type mmin;
		size_type mmax;
		bool operator<(const self_type &x){
			return mmin < x.mmin;
		}
	};
	typedef std::list<operate_memory_data> operated_list_type;


	template<class _T,class Traits,class Boss>
	class iterator_base : public std::random_access_iterator_tag {
	public:
		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
		> iterator;
		typedef iterator_base<
			_T, 
			policy::const_traits<_T> ,
			Boss
		>    const_iterator;
		typedef iterator_base<
			_T,
			Traits,
			Boss
		> self_type;

		typedef typename std::random_access_iterator_tag iterator_category;
		typedef std::size_t size_type;
		typedef std::ptrdiff_t difference_type;
		
		typedef typename Boss::pointer  boss_pointer;
		typedef typename Boss::reference boss_reference;
		typedef typename Boss::base_type::iterator boss_base_iterator;
	private:
		typedef typename Boss::operated_list_type list_t;
		///このイテレータを生成したクラスへのポインタ
		boss_pointer mp;
		///カウンター
		size_type mc;
		///ステート所持用イテレータ
		boss_base_iterator mit;

		enum{
			///処理が普通通り行われなかった。エラー
			fFALSE = edk_FAILED,
			///処理は普通通り行われた
			fTRUE = edk_SUCCEEDED,
			///最後の印
			fEND,
			///begin()で--して戻っているのでその印
			fBEGIN_END,
		};

		int check(){
			if(mit == mp->getDisableMarker().end()){
				return fEND;
			}
			if(mit == mp->getDisableMarker().begin()){
				return fBEGIN_END;
			}
			return fTRUE;
		}
		///次の要素へ
		int increment(){
			if(false==mark_update(mit,true)){
				DKUTIL_THROW_OR_NOTICE(std::logic_error("uninitialize iterator"));
				return fFALSE;
			}
		}
		///前の要素へ
		int decrement(){
			if(mit == mp->getDisableMarker().begin()){
				return fEND;
			}
			
			if(false==mark_update(mit,false)){
				DKUTIL_THROW_OR_NOTICE(std::logic_error("uninitialize iterator"));
				return fFALSE;
			}
			

			if(mit == mp->getDisableMarker().begin()){
				return fBEGIN_END;
			}
			return fTRUE;

		}
		///削除済みフィルターへの当たり判定
		bool check_collision(size_type count,const operate_memory_data &x){
			if(x.mmin <= count && x.mmax >= count){
				return true;
			}
			return false;
		}
		///アップデートする。
		bool mark_update(boss_base_iterator &get_it,bool isIncrease)
		{
			if(NULL==mp){
				return false;
			}
			mp->update();

			operated_list_type::iterator it = get_it;
			
			//前の状態を保存
			operate_memory_data t = (*it);
			size_type i = mc;
			//t = (*it);
			//it++;

			if(isIncrease)
			{
				for(;it != mp->getDisableMarker().end();it++,i++)
				{
					
					if(t.mmax + 1 == (*it).mmin)
					{//重複ゾーンのようだ
						t.mmax = (*it).mmax;
						continue;
					}
					if(check_collision(i,(*it))==false)
					{//やっと判定外に出たよ＾＾
						break;
					}
					t = (*it);
					/*if(t.mmin > (*it).mmin){
						t.mmin = (*it).mmin;
					}
					if(t.mmax < (*it).mmax){
						t.mmin = (*it).mmax;
					}*/



				}//end of for
				
				dkcmNOT_ASSERT(t.mmax < mc,"counterがありえない方向に動いている");
				//update
				get_it += t.mmax - mc;
				mc = t.mmax;
			}else{
				while(1){
					if(it == mp->getDisableMarker().begin()){
						break;
					}
					it--;
					i--;

					if(t.mmin - 1 == (*it).mmax){
						t.mmin = (*it).mmin;
						continue;
					}
					if(check_collision(i,(*it))==false)
					{//やっと判定外に出たよ＾＾
						break;
					}

					t = (*it);

					
				}
				dkcmNOT_ASSERT(t.mmin > mc,"counterがありえない方向に動いている");
				//update
				get_it -= mc - t.mmin; 
				mc = t.mmin;
				 
			}

			return true;
		}
	public:
		//friend self_type::iterator;
		//friend self_type::const_iterator;
		

		//iterator_base(size_type c,boss_pointer p){//mediator...?
		iterator_base(boss_pointer p){
			//変更した所をアップデート
			p->update();
			mp = p;
			mc = c;
			mit = p->begin();
			
		}
		iterator_base(){
			mp = NULL;
			mc = 0;
		}
		iterator_base(const iterator &x){
			mp = x.mp;
			mc = x.mc;
			mit = x.mit;
		}

		reference operator*()const{
			return (*mit);
		}
		pointer operator->() const {
			return &(*mit);
		}
		self_type &operator++(){
			increment();
			return (*this);
		}
		self_type &operator--(){
			decrement();
			return (*this);
		}
		//使えない。コスト高すぎ！
		self_type operator++(int){
			self_type t = *this;
			operator++();
			return t;
		}
		self_type operator--(int){
			self_type t = *this;
			operator--();
			return t;
		}

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

		//ボスとは友達＾＾
		friend  Boss;
		

		
	};

	typedef iterator_base<
		,
		policy::non_const_traits<value_type>,
		policy::non_const_traits<operated_list_type> 
	> 		iterator;
	
	typedef iterator_base<
		value_type,
		policy::const_traits<value_type>,
		policy::non_const_traits<operated_list_type> 
		//policy::const_traits<self_type>
	>		const_iterator;

	const_iterator begin()const{
		return const_iterator(0,this);
	}
	const_iterator end()const{
		return const_iterator(size(),this);
	}
	iterator begin(){
		return iterator(0,this);
	}
	iterator end(){
		return iterator(size(),this);
	}
private:
	///undo redo list
	operated_list_type mUndo;
	///undo redo list の内で今、Enableな状態
	operated_list_type::iterator mUndoState;
	///無効マーカーリスト
	operated_list_type mDisableMarker;
	bool mUpdateFlag;
protected:
	///無効マーカーを取得
	operated_list_type &getDisableMarker()const{
		return mDisableMarker;
	}
		///無効マーカーを更新
	void update(){
		//まぁ、いちぉ〜 thread safeッて事で
		synchronized swimming;

		if(false==mUpdateFlag){
			return ;
		}
		//とりあえず、無効マーカーを削除
		mDisableMarker.clear();
		
		//無効マーカーをコピー
		mDisableMarker = mUndo;

		//無効マーカーを作る

		{
			//とりあえずmin値が一版最初になるようにソート
			mDisableMarker.sort();
			operated_list_type::iterator it = mDisableMarker.begin();
			operate_memory_data t = (*it);

			for(;it != mDisableMarker.end();it++)
			{
				if(t.mmax + 1 == (*it).mmin)
				{//重複ゾーンのようだ
					//t.mmax = (*it).mmax;
					(*it).mmin = t.mmin;
					if(it !=  mDisableMarker.begin())
					{//ありえないと思うけど念のため＾＾；
						mDisableMarker.erase(it - 1);
					}
					continue;
				}
			}//end of for
		}
		//とりあえず、アップデートしたからフラグダウン
		mUpdateFlag = false;

		
	}
	void flagup(){
		mUpdateFlag = true;
	}
public:
	text_edit_buffer(){
		flagup();
	}
	~text_edit_buffer(){
	
	}


	 
	bool undo(){
	flagup();
	
	}
	bool redo(){
	flagup();
	}
	void insert(iterator index,const value_type &x){
		base_type::insert(index,x);
		mUndo.push_back(operate_memory_data(index,index));
		flagup();
	}
	void erase(iterator begin_,iterator end_){
		mUndo.push_back(operate_memory_data(begin_,end_));
		flagup();
	}
	void push_back(){}
	void pop_back(){
		mUndo.push_back(operate_memory_data(
	}
	void push_front(){}
	void pop_front(){}

	bool isUpdate(){
		return mUpdateFlag;
	}



};


}//end of dkutil namepsace

#endif //end of include once

