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

#include "TaEditFindDlg.h"
#include "TaEditShell.h"

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

CTaEditFindDlg::CTaEditFindDlg()
{

}

CTaEditFindDlg::~CTaEditFindDlg()
{

}

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

// 構築
void CTaEditFindDlg::OnCreate( Widget argWgt, XtPointer user_data )
{

}

// 「閉じる」ボタンの押下
void CTaEditFindDlg::OnFindExit( Widget argWgt, XtPointer user_data )
{
	XtUnmanageChild( m_FindDlg );
}

// 「全て置換」ボタンの押下
void CTaEditFindDlg::OnFindAllReplace( Widget argWgt, XtPointer user_data )
{
	wstring PatternStr;
	wstring ReplaceStr;

	// 検索パターン及び置換後に設定する文字列を取得
	GetPatternStr( &PatternStr );
	GetReplaceStr( &ReplaceStr );

	// 検索パターンが入力されていなければ、処理を行わない
	if ( PatternStr.length() <= 0 ) return ;

	// 置換
	GetTextEditorObj()->ReplaceAll( PatternStr, ReplaceStr );	
}

// 「置換」ボタンの押下
void CTaEditFindDlg::OnFindReplace( Widget argWgt, XtPointer user_data )
{
	wstring ReplaceStr;

	// 置換後に設定する文字列を取得
	GetReplaceStr( &ReplaceStr );

	// 置換
	GetTextEditorObj()->PasteText( ReplaceStr, true );
}

// 「検索」ボタンの押下
void CTaEditFindDlg::OnFindNext( Widget argWgt, XtPointer user_data )
{
	wstring PatternStr;

	// 検索パターンの文字列を取得する
	GetPatternStr( &PatternStr );

	// 検索パターンが入力されていなければ、処理を行わない
	if ( PatternStr.length() <= 0 ) return ;

	// 検索する
	GetTextEditorObj()->FindText( PatternStr );
}

// ダイアログを表示
void CTaEditFindDlg::ShowDlg()
{
	XtManageChild( m_FindDlg );
}

// 検索の方法を取得
enumFINDTYPE CTaEditFindDlg::GetFindType() const
{
	// 「単純」トグルボタン
	if ( XmToggleButtonGetState( m_FindTypeNormal ) )
		return FINDTYPE_NORMAL;

	// 「ワイルドカード」トグルボタン
	if ( XmToggleButtonGetState( m_FindTypeWildcard ) )
		return FINDTYPE_WILDCARD;

	// 「正規表現」トグルボタン
	if ( XmToggleButtonGetState( m_FindTypeRegex ) )
		return FINDTYPE_REGEX;

	// とりあえず
	return FINDTYPE_NORMAL;
}

// 検索対象の文字列を取得
void CTaEditFindDlg::GetPatternStr( wstring *pStr ) const
{
	assert( NULL != this && NULL != pStr && NULL != m_FindPatternStr );

	// 入力された文字列を取得
	wchar_t *pIptStr = XmTextFieldGetStringWcs( m_FindPatternStr );

	// トグルボタンの選択にあわせて文字列を加工する
	switch ( GetFindType() ) {
	case FINDTYPE_NORMAL:
		// 入力された文字列に等しい文字列を検索する正規表現に変換
		ConvertNormalPtnToRegexPtn( pIptStr, pStr );
		break;

	case FINDTYPE_WILDCARD:
		// ワイルドカードが使用された文字列を検索する正規表現に変換
		ConvertWildcardPtnToRegexPtn( pIptStr, pStr );
		break;

	case FINDTYPE_REGEX:
		// 入力文字列をそのまま正規表現と見なす。
		(*pStr) = pIptStr;
	}

	XtFree( reinterpret_cast< char* >( pIptStr ) );
}

// 置換後の文字列を取得
void CTaEditFindDlg::GetReplaceStr( wstring *pStr ) const
{
	assert( NULL != this && NULL != pStr && NULL != m_FindReplaceStr );
	wchar_t *str = XmTextFieldGetStringWcs( m_FindReplaceStr );
	(*pStr) = str;
	XtFree( reinterpret_cast< char* >( str ) );
}

// テキスト編集オブジェクトを取得する
VClsPtr< CTextEdit > CTaEditFindDlg::GetTextEditorObj() const
{
	assert( NULL != this && NULL != m_TaEditShell );
	return m_TaEditShell->GetTextEditor();
}

// 入力された検索対象文字列を、正規表現に変換する
void CTaEditFindDlg::ConvertNormalPtnToRegexPtn( const wchar_t *pIptPtn, wstring *pRegexPtn ) const
{
	assert( NULL != pIptPtn && NULL != pRegexPtn );

	// 入力された文字列中に、REGEX_SPECIALCODE内に含まれる特殊記号が使用されていたら、
	// エスケープシーケンスを挿入する
	while ( (*pIptPtn) ) {
		if ( L'\\' == (*pIptPtn) || wcschr( REGEX_SPECIALCODE, (*pIptPtn) ) )
			(*pRegexPtn) += L'\\';
		(*pRegexPtn) += (*pIptPtn);
		pIptPtn++;
	}
}

// 入力されたワイルドカードによる検索パターンを、それと同等の正規表現に変換する。
void CTaEditFindDlg::ConvertWildcardPtnToRegexPtn( const wchar_t *pIptPtn, wstring *pRegexPtn ) const
{
	assert( NULL != pIptPtn && NULL != pRegexPtn );

	// 入力された文字列中に*が含まれていた場合は{.}に、
	// ?が含まれていた場合は.に置換する。
	// ただし\\は\\に、\*は*に、\?は?に置き換える。

	while ( (*pIptPtn) ) {
		switch ( (*pIptPtn) ) {
		case L'*':
			(*pRegexPtn) += L"{.}";
			break;
		case L'?':
			(*pRegexPtn) += L".";
			break;
		case '\\':
			pIptPtn++;
			if ( NULL == (*pIptPtn) ) {
				// \で終わっている。とりあえず\\を出力する
				(*pRegexPtn) += L"\\\\";
				return ;
			}
			if ( L'\\' == (*pIptPtn)  )
				(*pRegexPtn) += L"\\\\";
			else
				(*pRegexPtn) += (*pIptPtn);
			break;
		default:
			if ( wcschr( REGEX_SPECIALCODE, (*pIptPtn) ) )
				(*pRegexPtn) += L'\\';
			(*pRegexPtn) += (*pIptPtn);
		}
		pIptPtn++;
	}
	
}


