////////////////////////////////////////////////////////////////////////////
// CUndoListMgr クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////

#include "UndoListMgr.h"
#include "TaEditShell.h"

////////////////////////////////////////////////////////////////////////////
// 構築/破棄
////////////////////////////////////////////////////////////////////////////

CUndoListMgr::CUndoListMgr() :
	MaxUndoCount( 1000 )
{
	Clear();
}

CUndoListMgr::~CUndoListMgr()
{

}

////////////////////////////////////////////////////////////////////////////
// メソッド
////////////////////////////////////////////////////////////////////////////

// Undo可能な最大数を設定
void CUndoListMgr::SetMaxUndoCount( int argCnt )
{
	assert( NULL != this && argCnt > 0 && argCnt <= INT_MAX );
	MaxUndoCount = argCnt;
}

// アンドゥ可能か否か
bool CUndoListMgr::EnableUndo() const
{
	list< pair< bool, list< VClsPtr< CEditCommand > > > >::const_iterator wItr;
	assert( NULL != this );

	// リストのサイズが0なら、そもそもUndoは不可能である
	if ( listUndo.size() == 0 ) return false;

	// 先頭を示していたらUndoは不可能
	if ( listUndo.begin() == itrUndo ) return false;

	// 末尾を示している場合はUndo可能
	if ( listUndo.end() == itrUndo ) return true;

	// 現在のリストが固定されていない場合はUndo不可
	if ( !itrUndo->first ) return false;

	return true;
}

// リドゥ可能か否か
bool CUndoListMgr::EnableRedo() const
{
	assert( NULL != this );

	// リストのサイズが0なら、そもそもRedoは不可能である
	if ( listUndo.size() == 0 ) return false;

	// 末尾を示していたらRedoは不可
	if ( listUndo.end() == itrUndo ) return false;

	// 現在のリストが固定されていない場合はRedo不可
	if ( !itrUndo->first ) return false;

	return true;
}

// Undo用に編集コマンドオブジェクトを取得
list< VClsPtr< CEditCommand > > CUndoListMgr::GetUndoObj()
{
	list< VClsPtr< CEditCommand > > wList;

	assert( NULL != this && EnableUndo() );

	itrUndo--;

	// 逆順に並び替える
	wList = itrUndo->second;
	wList.reverse();

	// メニューを更新する
	UpdateMenuStatus();

	return wList;
}

// Redo用に編集コマンドオブジェクトを取得
list< VClsPtr< CEditCommand > > CUndoListMgr::GetRedoObj()
{
	list< pair< bool, list< VClsPtr< CEditCommand > > > >::iterator  wItr;

	wItr = itrUndo;
	itrUndo++;

	// メニューを更新する
	UpdateMenuStatus();

	return wItr->second;
}

// 編集コマンドオブジェクトを追加する
void CUndoListMgr::PushBack( VClsPtr< CEditCommand > pObj )
{
	assert( NULL != this );

	// itrUndoの指しているリストが、固定された物であった場合は、後半部分を削除する
	if ( itrUndo != listUndo.end() ) {
		if ( itrUndo->first ) {
			listUndo.erase( itrUndo, listUndo.end() );
			itrUndo = listUndo.end();
		}
	}

	if ( itrUndo == listUndo.end() ) {
		// 新しいリストを追加
		list< VClsPtr< CEditCommand > > dmy;
		listUndo.push_back( pair< bool, list< VClsPtr< CEditCommand > > >( false, dmy ) );
		itrUndo--;

		// リストが最大数を超えた場合は、先頭のものを削除する
		if ( listUndo.size() > MaxUndoCount ) {
			list< pair< bool, list< VClsPtr< CEditCommand > > > >::iterator wItr = listUndo.begin();
			wItr++;
			listUndo.erase( listUndo.begin(), wItr );
		}
	}

	// 要素を追加する
	itrUndo->second.push_back( pObj );
}

// 編集が終了したことを示す
void CUndoListMgr::EndEdit()
{
	itrUndo->first = true;
	itrUndo = listUndo.end();

	UpdateMenuStatus();
}

// 初期化
void CUndoListMgr::Clear()
{
	assert( NULL != this );
	listUndo.clear();
	itrUndo = listUndo.end();
}

// Undo/Redoメニューの状態を更新する
void CUndoListMgr::UpdateMenuStatus() const
{
	assert( NULL != this );
	m_TaEditShell->SetEnableUndoMenu( EnableUndo() );
	m_TaEditShell->SetEnableRedoMenu( EnableRedo() );
}

// リストを交換する
void CUndoListMgr::Swap( CUndoListMgr *p )
{
	assert( this && p );

	list< pair< bool, list< VClsPtr< CEditCommand > > > >::iterator wItr;
	int wInt;

	wInt = this->MaxUndoCount;
	this->MaxUndoCount = p->MaxUndoCount;
	p->MaxUndoCount = wInt;

	wItr = this->itrUndo;
	this->itrUndo = p->itrUndo;
	p->itrUndo = wItr;

	listUndo.swap( p->listUndo );
}

