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

#include "FindText.h"
#include "TextMatchLib.h"
#include "TaEditShell.h"
#include "CompoundStr.h"

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

CFindText::CFindText() :
	pDoc( NULL ), EnableExitFlg( false ),
	IsMatchedFlg( false ), ErrorInfo()
{

}

CFindText::~CFindText()
{

}

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

// 検索のための情報を設定する
bool CFindText::SetInfo(
	const CTaEditDoc *pArgDoc,
	T_CurPos argSPos,
	const wstring &rArgPtn,
	VClsPtr< CConfigInfo > pArgConf )
{
	pDoc = pArgDoc;
	SPos = argSPos;
	IsMatchedFlg = false;

	// 検索用オブジェクトを構築
	if ( CreateFindObj( &m_FindObj, rArgPtn, pArgConf ) )
		return true;

	pDoc = NULL;
	return false;
}

// 検索を開始する
bool CFindText::start()
{
	assert( NULL != this && NULL != pDoc );
	return CProcesingObj::start();	// スレッドを開始
}

// 検索用スレッド
void CFindText::run()
{
	assert( NULL != this && NULL != pDoc );
	EnableExitFlg = false;
	IsMatchedFlg = FindNext( &m_FindObj, &m_ResultRange );	// 検索する
	EnableExitFlg = true;	// 終了可能のフラグを設定
}

// 終了可能か否か
bool CFindText::EnableExit() const
{
	return EnableExitFlg;
}

// 割り込み
void CFindText::Interrupt()
{
	m_FindObj.Interrupt();
}

// スレッドの終了を持ち合わせる
void CFindText::WaitThreadTerminate()
{
	CThread::Wait();
}

// 一定時間だけスレッドの終了を待ち合わせる
bool CFindText::WaitThreadTerminateForTime( int ms )
{
	return CThread::WaitForTime( ms );
}

// 見つかったか否かを取得
bool CFindText::IsMatched() const
{
	return IsMatchedFlg;
}

// 検索結果の範囲を取得
const T_SelRange& CFindText::GetMatchRange() const
{
	return m_ResultRange;
}

// エラー情報を取得
CErrorBool CFindText::GetErrorInfo() const
{
	return ErrorInfo;
}

// 検索用オブジェクトの構築
bool CFindText::CreateFindObj(
	N_SRegex::SRegex< wchar_t, const wchar_t*, tagPseudPtr > *pFindObj,
	const wstring &rPattern,
	VClsPtr< CConfigInfo > pConf ) const
{
	// 検索オブジェクトを初期化
	if ( pFindObj->Initialize( rPattern.c_str() ) )
		return true;	// 成功

	// 指定されたパターンに文法エラーが有る。

	// エラーメッセージとエラーが発生した位置を取得
	const wstring &rMsg = GetRegexErrString( pFindObj->GetLastError(), pConf );
	int idx = pFindObj->GetErrorPos() - rPattern.c_str();

	// ダイアログに表示するメッセージを取得
	CCompoundStr wCS;
	if ( !pConf->GetWrongRegexPatternMsg( &wCS, rMsg, idx ) )
		return false;

	// メッセージを表示
	m_TaEditShell->ShowErrorMsgBox( wCS );
	return false;
}

// SRegexのエラー値に対応するメッセージを取得する
const wstring& CFindText::GetRegexErrString( N_SRegex::SREGEX_ERR err, VClsPtr< CConfigInfo > pConf ) const
{
	switch ( err ) {
	case N_SRegex::SRE_EOF_NOT_ANTICIPATED:
		return pConf->RefWRP_EofNotAnticipated();

	case N_SRegex::SRE_OUT_OF_MEMORY:
		return pConf->RefWRP_OutOfMemory();

	case N_SRegex::SRE_UNCERTAIN_CHAR:
		return pConf->RefWRP_UncertainChar();

	case N_SRegex::SRE_ZERO_LENGTH_PTN:
		return pConf->RefWRP_ZeroLengthPattern();

	case N_SRegex::SRE_UNEXPENTED:
	default:
		return pConf->RefWRP_Unexpected();
	}
}

// 検索する
bool CFindText::FindNext( T_FindObj *pFindObj, T_SelRange *pRange ) const
{
	tagPseudPtr MatchSPos, MatchEPos;	// マッチした範囲を保持する
	T_LineDataItr_c wItr;
	T_CurPos wSPos, wEPos;

	// 検索用の疑似ポインタを構築
	tagPseudPtr pseudPtr( &( pDoc->RefData() ), pDoc->RefData().begin() + SPos.GetLine(), SPos );

	// 検索
	bool r = pFindObj->FindMatchStr( pseudPtr, &MatchSPos, &MatchEPos );
	if ( !r ) return false;

	wSPos = MatchSPos.GetCurPos();
	wEPos = MatchEPos.GetCurPos();

	// 開始位置及び終了位置が、最後の行+1になった場合は、最後の行の末尾の文字に設定する
	wItr = pDoc->RefData().end();
	--wItr;
	if ( wSPos.GetLine() == pDoc->RefData().size() )
		wSPos = T_CurPos( pDoc->RefData().size() - 1, wItr->length() );
	if ( wEPos.GetLine() == pDoc->RefData().size() )
		wEPos = T_CurPos( pDoc->RefData().size() - 1, wItr->length() );

	// 検索結果の選択位置を取得
	(*pRange) = T_SelRange( wSPos, wEPos );
	return true;
}

