/*-----------------------------------------------------------------------------
[名称]	ReplacerDlg.cpp
[概要]	置換ダイアログクラスの実装
[備考]	なし
[履歴]	2003-03-11	NC		コメント付加(moralog)
		2003-03-28	RB0005	選択部分の置換関数、出力を１行分に(moralog)
		2003-12-27	b031228	(3332)選択範囲が１行のときの置換範囲
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "Shitarabian.h"
#include "ReplacerDlg.h"
#include "ShitarabianDoc.h"
#include "ShitarabianView.h"
#include "Selection.h"
#include "Finder.h"
#include "CommandManager.h"
#include "Selection.h"
#include "CommandInput.h"
#include "CommandCaret.h"
#include "CommandDelete.h"
#include "Common.h"
#include "ExeCommon.h"
#include "MainFrm.h"
#include "BregPool.h"
#include "ReplacerProgressDlg.h"
#include "ProgressDlg.h"
#include "CommandModify.h"
#include "ShitarabianPlugInManager.h"
#include "CommandMultiEdit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/*-----------------------------------------------------------------------------
[名称]	置換スレッドパラメータ
[用途]	置換処理用ワーカスレッドに渡すパラメータ。
[備考]	なし
-----------------------------------------------------------------------------*/
typedef struct {
	CReplacerDlg*	pParent;			// 親ダイアログ [-] (-)
	CStringArray*	pastrReplacedz;		// 置換後行群 [-] (-)
	CDWordArray*	padwReplacedLinez;	// 置換行番号群 [-] (-)
} TReplaceParam;


//-----------------------------------------------------------------------------
// 関数プロトタイプ
//-----------------------------------------------------------------------------

// 文書全置換処理（ワーカスレッド）
static UINT ReplacerAll( LPVOID pThreadParam );
// 選択範囲全置換処理（ワーカスレッド）
static UINT ReplacerSelectedAll( LPVOID pThreadParam );


//-----------------------------------------------------------------------------
// ファイル内変数
//-----------------------------------------------------------------------------
static	int		s_iOnProposeModeID;		// 押された正規表現補完ボタン [リソースID] (-)


/*-----------------------------------------------------------------------------
[名称]	コンストラクタ
[機能]	インスタンスの生成。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CReplacerDlg::CReplacerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CReplacerDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CReplacerDlg)
	m_strSubString = _T("");
	m_bSelected = FALSE;
	m_bCaseCare = FALSE;
	m_bLoop = FALSE;
	m_strReplace = _T("");
	m_bToken = FALSE;
	m_bRegExp = FALSE;
	//}}AFX_DATA_INIT
}


/*-----------------------------------------------------------------------------
[名称]	データ変換
[機能]	CDialog::DoDataExchange() のヘルプを参照。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CReplacerDlg)
	DDX_Control(pDX, IDC_REPLACER_REGEXP, m_btnRegName);
	DDX_Control(pDX, IDC_REPLACER_REPLACESTRING, m_comboReplace);
	DDX_Control(pDX, IDC_REPLACER_SUBSTRING, m_comboSubString);
	DDX_CBString(pDX, IDC_REPLACER_SUBSTRING, m_strSubString);
	DDX_Check(pDX, IDC_REPLACER_SELECTED, m_bSelected);
	DDX_Check(pDX, IDC_REPLACER_UPPERLOWER, m_bCaseCare);
	DDX_Check(pDX, IDC_REPLACER_LOOP, m_bLoop);
	DDX_CBString(pDX, IDC_REPLACER_REPLACESTRING, m_strReplace);
	DDX_Check(pDX, IDC_REPLACER_TOKEN, m_bToken);
	DDX_Check(pDX, IDC_REPLACER_REGEXP, m_bRegExp);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CReplacerDlg, CDialog)
	//{{AFX_MSG_MAP(CReplacerDlg)
	ON_BN_CLICKED(IDC_REPLACER_NEXT, OnReplacerNext)
	ON_WM_SHOWWINDOW()
	ON_BN_CLICKED(IDC_REPLACER_LOOP, OnVisibleControl)
	ON_BN_CLICKED(IDC_REPLACER_REPLACE, OnReplacerReplace)
	ON_BN_CLICKED(IDC_REPLACER_ALLREPLACE, OnReplacerAllreplace)
	ON_BN_CLICKED(IDC_REPLACER_REGPROPOSE1, OnReplacerRegpropose1)
	ON_BN_CLICKED(IDC_REPLACER_REGPROPOSE2, OnReplacerRegpropose2)
	ON_COMMAND(IDM_REGEXP_CHAR, OnRegexpChar)
	ON_COMMAND(IDM_REGEXP_RENGE, OnRegexpRenge)
	ON_COMMAND(IDM_REGEXP_RENGEOVER, OnRegexpRengeover)
	ON_COMMAND(IDM_REGEXP_HEAD, OnRegexpHead)
	ON_COMMAND(IDM_REGEXP_LAST, OnRegexpLast)
	ON_COMMAND(IDM_REGEXP_NOTTOKEN, OnRegexpNotToken)
	ON_COMMAND(IDM_REGEXP_COUNT, OnRegexpCount)
	ON_COMMAND(IDM_REGEXP_SPACE, OnRegexpSpace)
	ON_COMMAND(IDM_REGEXP_NOTSPACE, OnRegexpNotSpace)
	ON_COMMAND(IDM_REGEXP_TAG, OnRegexpTag)
	ON_COMMAND(IDM_REGEXP_NOT, OnRegexpNot)
	ON_COMMAND(IDM_REGEXP_OR, OnRegexpOr)
	ON_COMMAND(IDM_REGEXP_0MATCH, OnRegexp0match)
	ON_COMMAND(IDM_REGEXP_1MATCH, OnRegexp1match)
	ON_COMMAND(IDM_REGEXP_TOKEN, OnRegexpToken)
	ON_COMMAND(IDM_REGEXP_GROUP, OnRegexpGroup)
	ON_BN_CLICKED(IDC_REPLACER_SELECTED, OnVisibleControl)
	ON_CBN_EDITCHANGE(IDC_REPLACER_SUBSTRING, OnVisibleControl)
	ON_CBN_CLOSEUP(IDC_REPLACER_SUBSTRING, OnVisibleControl)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/*-----------------------------------------------------------------------------
[名称]	表示状態制御
[機能]	各コントロールのEnable状態を制御する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::VisibleControl() 
{
	CShitarabianDoc*	pDoc = ::GetDocument();
	UpdateData( TRUE );

	if( pDoc != NULL )
	{
		// 選択範囲のみ
		BOOL	bSelected = pDoc->GetSelection()->IsSelected();
		CButton*	pbtnSelected = (CButton*)(GetDlgItem( IDC_REPLACER_SELECTED ) );
		pbtnSelected->EnableWindow( bSelected );
		bSelected &= m_bSelected;

		// 上下循環
		GetDlgItem( IDC_REPLACER_LOOP )->EnableWindow( !bSelected );

		// 検索ボタン
		BOOL	bNext = !m_strSubString.IsEmpty();
		GetDlgItem( IDC_REPLACER_ALLREPLACE )->EnableWindow( bNext );
		bNext &= !bSelected;
		GetDlgItem( IDC_REPLACER_NEXT )->EnableWindow( bNext );
		GetDlgItem( IDC_REPLACER_REPLACE )->EnableWindow( bNext );

		// 正規表現
		CFinder*	pFinder = ::GetFinder( TRUE );
		BOOL	bRegExp = pFinder->IsAlive();
		GetDlgItem( IDC_REPLACER_REGEXP )->EnableWindow( bRegExp );
		bRegExp &= ( ((CButton*)GetDlgItem( IDC_REPLACER_REGEXP ))->GetCheck () == 1 );

		GetDlgItem( IDC_REPLACER_REGPROPOSE1 )->EnableWindow( bRegExp );
		GetDlgItem( IDC_REPLACER_REGPROPOSE2 )->EnableWindow( bRegExp );

		GetDlgItem( IDC_REPLACER_UPPERLOWER )->EnableWindow( !bRegExp );
		GetDlgItem( IDC_REPLACER_TOKEN )->EnableWindow( !bRegExp );
	}
}


//-----------------------------------------------------------------------------
// イベントハンドラ
//-----------------------------------------------------------------------------


/*-----------------------------------------------------------------------------
[名称]	設定更新ハンドラ
[機能]	各コントロールのEnable状態を制御する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnVisibleControl()
{
	VisibleControl();
}


/*-----------------------------------------------------------------------------
[名称]	ダイアログ表示ハンドラ
[機能]	コントロール初期状態の設定。
[戻値]	なし
[備考]	CDialog::OnShowWindow()のヘルプを参照。
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnShowWindow(BOOL bShow, UINT nStatus) 
{
	CShitarabianDoc*	pDoc = ::GetDocument();
	CDialog::OnShowWindow(bShow, nStatus);

	// 選択範囲のみ
	BOOL	bSelected = pDoc->GetSelection()->IsSelected();
// ▼ (3332) BGN 2003.12.27 (moralog) 複数行選択中の場合は「選択範囲のみ」をデフォルトに
	// 複数行選択中の場合は「選択範囲のみ」をデフォルトにする
	BOOL	bMultiLine;
	bMultiLine = (pDoc->GetSelection()->GetSelectedStartRow() != pDoc->GetSelection()->GetSelectedEndRow() );
	bSelected &= bMultiLine;
// ▲ (3332) END
	CButton*	pbtnSelected = (CButton*)(GetDlgItem( IDC_REPLACER_SELECTED ) );
	pbtnSelected->SetCheck( bSelected?1:0 );
	m_bSelected = bSelected;

	// 選択文字を検索文字に設定
// ▼ (3332) BGN 2003.12.27 (moralog) 1行選択中の場合のみ検索文字列登録
	if ( !bMultiLine )
	{
		// １行のときには選択範囲を検索文字列とする
		CString	strSelected = pDoc->GetSelection()->GetSelectedText();
		if ( !strSelected.IsEmpty() )
		{
			GetDlgItem( IDC_REPLACER_SUBSTRING )->SetWindowText( strSelected );
		}
	}
// ▽ oridinal BGN
//	CString	strSelected = pDoc->GetSelection()->GetSelectedText();
//	if ( !strSelected.IsEmpty() )
//	{
//		m_strSubString = strSelected;
//		UpdateData( FALSE );
//	}
// △ oridinal END
// ▲ (3332) END

	VisibleControl();

	// コンボボックスにフォーカスを移す
	m_comboSubString.SetEditSel( 0, -1 );
	m_comboSubString.SetFocus();

	SetWindowPos( &wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );

}


/*-----------------------------------------------------------------------------
[名称]	「次を検索」ハンドラ
[機能]	後方検索してマッチ語彙を選択する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnReplacerNext()
{
	CShitarabianDoc*	pDoc = ::GetDocument();
	UpdateData();
	CString		strSubString = m_strSubString;
	if ( pDoc == NULL )
	{
		return;
	}

	// 検索語彙をリストに追加
	::GetMainFrame()->AddSubString( m_strSubString, &m_comboSubString );

	// 検索
	BOOL	bFound = FALSE;
	CFinder*	pFinder = ::GetFinder( m_bRegExp );
	bFound = pFinder->FindNextForSelect(
		pDoc,
		strSubString,
		m_bCaseCare,
		m_bLoop,
		m_bToken
	);
}


/*-----------------------------------------------------------------------------
[名称]	「置換」ボタンハンドラ
[機能]	選択語彙が検索文字列と同じであれば置換を行う。
		次のマッチ語彙を検索する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnReplacerReplace()
{
	CShitarabianDoc*	pDoc = ::GetDocument();
	UpdateData();
	CString		strSubString = m_strSubString;

	// リストに追加
	::GetMainFrame()->AddSubString( m_strSubString, &m_comboSubString );
	::GetMainFrame()->AddReplaceString( m_strReplace, &m_comboReplace );

	if ( pDoc == NULL )
	{
		return;
	}

	// 選択範囲が検索文字列に合致すれば置換
	{
		int idxStartRow = pDoc->GetSelection()->GetSelectedStartRow();
		int idxStartColumn = pDoc->GetSelection()->GetSelectedStartColumn();
		int idxEndRow = pDoc->GetSelection()->GetSelectedEndRow();
		int idxEndColumn = pDoc->GetSelection()->GetSelectedEndColumn();

		BOOL	bFound;
		if( idxStartRow == idxEndRow )
		{
			long	idxFoundCaretColumn;
			long	nCaretColumn;
			CFinder*	pFinder = ::GetFinder( m_bRegExp );
			bFound = pFinder->FindAtLine(
				*(pDoc->GetLine( idxStartRow )),
				idxStartColumn,
				idxEndColumn,
				m_strSubString,
				&idxFoundCaretColumn,
				&nCaretColumn,
				m_bCaseCare,
				m_bToken
			);
			if ( bFound )
			{
				pFinder->Replace(
					pDoc,
					idxStartRow,
					idxStartColumn,
					idxEndColumn,
					m_strSubString,
					m_strReplace,
					m_bCaseCare,
					m_bToken
				);

// ▼ (3332) BGN 2003.12.27 (moralog) 選択状態修正
				// 選択状態初期化
				pDoc->GetSelection()->SetSelectedNutral();
// ▲ (3332) END
			}
		}
	}

	// 次を検索する
	OnReplacerNext();
}


/*-----------------------------------------------------------------------------
[名称]	初期化ハンドラ
[機能]	コントロールの初期化処理。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CReplacerDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	CFinder*	pFinder = ::GetFinder( TRUE );
	CString	strCaption;
	strCaption.Format( "正規表現（%s）", pFinder->Name() );
	m_btnRegName.SetWindowText( strCaption );

	m_ProgressDlg.Create( IDD_REPLACER_PREGRESS, this );
// please! destroyしてないよ

	return TRUE;  // コントロールにフォーカスを設定しないとき、戻り値は TRUE となります
	              // 例外: OCX プロパティ ページの戻り値は FALSE となります
}


/*-----------------------------------------------------------------------------
[名称]	検索文字列正規表現補完ボタンハンドラ
[機能]	正規表現補完のポップアップメニューを表示する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnReplacerRegpropose1() 
{
	s_iOnProposeModeID = IDC_REPLACER_REGPROPOSE1;

	CMenu menu;
	VERIFY(menu.LoadMenu( IDR_REGEXP ));
	CMenu* pPopup = menu.GetSubMenu(0);
	ASSERT(pPopup != NULL);

	CRect	rcButton;
	GetDlgItem( IDC_REPLACER_REGPROPOSE1 )->GetWindowRect( &rcButton );

	pPopup->TrackPopupMenu(
		TPM_LEFTALIGN | TPM_RIGHTBUTTON,
		rcButton.right, rcButton.top,
		this
	);	
}


/*-----------------------------------------------------------------------------
[名称]	置換文字列正規表現補完ボタンハンドラ
[機能]	正規表現補完のポップアップメニューを表示する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnReplacerRegpropose2() 
{
	s_iOnProposeModeID = IDC_REPLACER_REGPROPOSE2;

	CMenu menu;
	VERIFY(menu.LoadMenu( IDR_REGEXP ));
	CMenu* pPopup = menu.GetSubMenu(0);
	ASSERT(pPopup != NULL);

	CRect	rcButton;
	GetDlgItem( IDC_REPLACER_REGPROPOSE2 )->GetWindowRect( &rcButton );

	pPopup->TrackPopupMenu(
		TPM_LEFTALIGN | TPM_RIGHTBUTTON,
		rcButton.right, rcButton.top,
		this
	);	
}


//-----------------------------------------------------------------------------
// 正規表現補完機能 関連
//-----------------------------------------------------------------------------


/*-----------------------------------------------------------------------------
[名称]	コンボボックス取得
[機能]	正規表現補完の対象コンボボックスを取得する。
[戻値]	CComboBox*	正規表現補完の対象 [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
CComboBox* CReplacerDlg::GetComboBox()
{
	switch( s_iOnProposeModeID )
	{
	case IDC_REPLACER_REGPROPOSE2:
		return( &m_comboReplace );
		break;

	case IDC_REPLACER_REGPROPOSE1:
	default:
		return( &m_comboSubString );
		break;
	}
}


/*-----------------------------------------------------------------------------
[名称]	正規表現補完ポップアップメニューハンドラ
[機能]	メニュー項目に対応した正規表現を、対象コンボボックスに挿入する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnRegexpChar() 		{ CFinder::RegexpChar( GetComboBox() ); }
void CReplacerDlg::OnRegexpRenge()		{ CFinder::RegexpRenge( GetComboBox() ); }
void CReplacerDlg::OnRegexpRengeover()	{ CFinder::RegexpRengeover( GetComboBox() ); }
void CReplacerDlg::OnRegexpHead() 		{ CFinder::RegexpHead( GetComboBox() ); }
void CReplacerDlg::OnRegexpLast()		{ CFinder::RegexpLast( GetComboBox() ); }
void CReplacerDlg::OnRegexpToken()		{ CFinder::RegexpToken( &m_comboSubString ); }
void CReplacerDlg::OnRegexpNotToken()	{ CFinder::RegexpNotToken( &m_comboSubString ); }
void CReplacerDlg::OnRegexpSpace()		{ CFinder::RegexpSpace( &m_comboSubString ); }
void CReplacerDlg::OnRegexpNotSpace()	{ CFinder::RegexpNotSpace( &m_comboSubString ); }
void CReplacerDlg::OnRegexpTag()		{ CFinder::RegexpTag( GetComboBox() ); }
void CReplacerDlg::OnRegexpNot()	 	{ CFinder::RegexpNot( GetComboBox() ); }
void CReplacerDlg::OnRegexpOr() 		{ CFinder::RegexpOr( GetComboBox() ); }
void CReplacerDlg::OnRegexp0match()		{ CFinder::Regexp0match( GetComboBox() ); }
void CReplacerDlg::OnRegexp1match()		{ CFinder::Regexp1match( GetComboBox() ); }
void CReplacerDlg::OnRegexpCount()		{ CFinder::RegexpCount( GetComboBox() ); }
void CReplacerDlg::OnRegexpGroup()		{ CFinder::RegexpGroup( GetComboBox() ); }


//-----------------------------------------------------------------------------
// 置換処理
//-----------------------------------------------------------------------------


/*-----------------------------------------------------------------------------
[名称]	「全て置換」ボタンハンドラ
[機能]	文書全体、または選択範囲を対象に置換処理を行う。
[戻値]	なし
[備考]	置換処理をサブスレッドで行う。
		(1)サブスレッド起動
		(sub)サブスレッドでは、行単位で置換処理データを作成する。
		(2)サブスレッドが終了するまでの間、メッセージを処理しながら待つ。
		(3)サブスレッドが終了したら行単位で差し替え。
		(4)表示色解析。
		(5)置換個数のメッセージ出力。
-----------------------------------------------------------------------------*/
void CReplacerDlg::OnReplacerAllreplace() 
{
	CShitarabianDoc*	pDoc = ::GetDocument();

	// 検索語彙リストに追加
	::GetMainFrame()->AddSubString( m_strSubString, &m_comboSubString );
	::GetMainFrame()->AddReplaceString( m_strReplace, &m_comboReplace );

	CStringArray	astrReplacedz;
	CDWordArray		adwReplacedLinez;
	TReplaceParam	tParam;
	tParam.pParent = this;
	tParam.pastrReplacedz = &astrReplacedz;
	tParam.padwReplacedLinez = &adwReplacedLinez;

	// サブスレッドの開始
	m_ProgressDlg.Run();
	if( m_bSelected && pDoc->GetSelection()->IsSelected() )
	{
		::AfxBeginThread( ReplacerSelectedAll, &tParam );
	}
	else
	{
		::AfxBeginThread( ReplacerAll, &tParam );
	}

	// スレッド終了を待つ
	m_ProgressDlg.ShowWindow( SW_SHOW );
	while( m_ProgressDlg.IsRunnning() )
	{
		MSG	msg;
		if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {
              ::TranslateMessage(&msg);
              DispatchMessage(&msg);
        }
	}
	m_ProgressDlg.ShowWindow( SW_HIDE );

	// 置換個数取得
	int		nReplace = 0;
	nReplace = m_ProgressDlg.GetReplacedCount();

// ▼ (3332) BGN 2003.12.27 (moralog) キャレット位置補正
	if ( nReplace > 0 )
	{
		// キャレット位置移動
		CCommandCaret	pCaret;
		CCommandCaret	cmdCaret;
		cmdCaret.SetAttribute( 0x00, pDoc->GetSelection()->GetSelectedStartRow(), pDoc->GetSelection()->GetSelectedStartColumn() );
		cmdCaret.Execute( pDoc );

		// 選択状態初期化
		pDoc->GetSelection()->SetSelectedNutral();
	}
// ▲ (3332) END

	// 置換行へ差し替え
	// 高速化のため一時的に表示色解析をストップする
	CEmphasisLine::SetAnalizeMultiLineEmphasisEnable( FALSE );
	if ( !m_ProgressDlg.IsAbort() )
	{
		CCommandMultiEdit	cmdEdit;

		// 複数行化した挿入行のため行位置がずれる可能性があるので下の行から処理する
		for( int idxLine=adwReplacedLinez.GetSize()-1 ; idxLine>=0 ; idxLine-- )
		{
			// 行の書き換え（表示色解析結果Detailの破棄を伴う）
			CCommandModify	cmdModify;
			cmdModify.SetAttribute(
				adwReplacedLinez[idxLine],
				astrReplacedz[idxLine]
			);

/*
//please! 行情報をいじくるとUndoがうまくいかないな‥‥
			if( astrReplacedz[idxLine].IsEmpty() )
			{
				// 空白に置き換えた→行を削除したので、以降の行情報を更新する
				int		idxUpdateLine;
				for( idxUpdateLine=idxLine+1 ; idxUpdateLine<adwReplacedLinez.GetSize()-1 ; idxUpdateLine++ )
				{
					adwReplacedLinez[idxUpdateLine]--;
				}
				adwReplacedLinez.RemoveAt(idxLine);
			}
*/

			cmdModify.Execute( pDoc );
			cmdEdit.Add( cmdModify );
		}
		CCommandManager*	pCmd = CCommandManager::GetInstance();
		pCmd->Add( cmdEdit );
	}
	CEmphasisLine::SetAnalizeMultiLineEmphasisEnable( TRUE );

	// 更新通知
	CShitarabianPlugInManager::GetInstance()->OnEdit(
		pDoc
	);

	// ドキュメント表示情報の再構築
	if ( !m_ProgressDlg.IsAbort() )
	if ( adwReplacedLinez.GetSize() > 0 )
	{
		pDoc->AnalizeEmphasisLinez( adwReplacedLinez );
	}

	// メインウィンドウの再描画
	pDoc->SetAllUpdate();
	pDoc->ReDraw();

	// メッセージ出力
	if ( !m_ProgressDlg.IsAbort() )
	{
		CString		strMes;
		strMes.Format( "%d 箇所を置換しました。", nReplace );
		MessageBox(
			strMes
		);
	}
	else
	{
		MessageBox(
			"中断しました。"
		);
	}
}


/*-----------------------------------------------------------------------------
[名称]	文書全置換
[機能]	文書全体を対象に置換処理を行う。
[戻値]	UINT	置換個数 [-] (-)
[備考]	ワーカスレッドとして使用。
		pThreadParam は TReplaceParam*。
-----------------------------------------------------------------------------*/
static UINT ReplacerAll(
	LPVOID pThreadParam	// I/O:置換スレッドパラメータ [-] (-) :-
)
{
	CShitarabianDoc*		pDoc = ::GetDocument();
	TReplaceParam*			pParam = (TReplaceParam*)pThreadParam;
	CReplacerDlg*			pParent = pParam->pParent;
	CReplacerProgressDlg*	pProgress = pParent->GetProgressDialog();

	pParam->pastrReplacedz->RemoveAll();
	pParam->padwReplacedLinez->RemoveAll();

	int		nReplace = 0;
	int		idxRow;
	for( idxRow=0 ; idxRow<pDoc->GetLineCount() ; idxRow++ ) // 行のループ
	{
		// 中断チェック
		if ( pProgress->IsAbort() )
		{
			pProgress->NotifyStop( nReplace );
			return( 0 );
		}
		pProgress->NotifyProgress( (idxRow*100)/pDoc->GetLineCount() );

		// 置換後文字列の作成
		BOOL		bReplaced = FALSE;
		CString		strReplaced;
		{
			BOOL		bFound = TRUE;
			int			idxStartColumn = 0;

			CString*	pTarget = pDoc->GetLine( idxRow );
			if ( pTarget != NULL )
			{
				int			nSrcColumn = ::StringToColumn( *pTarget );
				while( bFound )
				{
					// 中断チェック
					if ( pProgress->IsAbort() )
					{
						pProgress->NotifyStop( nReplace );
						return( 0 );
					}

					long	idxFoundStartColumn;
					long	nFoundColumn;
					CFinder*	pFinder = ::GetFinder( pParent->m_bRegExp );
					bFound = pFinder->FindAtLine(
						*pTarget,
						idxStartColumn,
						INT_MAX,
						pParent->m_strSubString,
						&idxFoundStartColumn,
						&nFoundColumn,
						pParent->m_bCaseCare,
						pParent->m_bToken
					);

					if ( bFound )
					{
						// 置換文字列の取得
						CString		strReplace;
						{
							strReplace = pFinder->GetReplaceWord(
								pDoc,
								idxRow,
								idxFoundStartColumn,
								idxFoundStartColumn + nFoundColumn,
								pParent->m_strSubString,
								pParent->m_strReplace,
								pParent->m_bCaseCare,
								pParent->m_bToken
							);
						}

						long	idxStartByte = ::CaretColumnToByteColumn( *pTarget, idxStartColumn );
						long	idxFoundStartByte = ::CaretColumnToByteColumn( *pTarget, idxFoundStartColumn );

						strReplaced += pTarget->Mid(
							idxStartByte,
							idxFoundStartByte-idxStartByte );

						strReplaced += strReplace;
						idxStartColumn = idxFoundStartColumn + nFoundColumn;
						nReplace++;
						bReplaced = TRUE;

						if ( nSrcColumn == idxStartColumn )
						{
							// すでに行末に達しているので終了
							break;
						}
					}
					else
					{
						if ( bReplaced )
						{
							long	idxStartByte = ::CaretColumnToByteColumn( *pTarget, idxStartColumn );
							strReplaced += pTarget->Mid( idxStartByte );
						}
					}
				}
			}
		}
		// 変更情報を蓄える
		if ( bReplaced )
		{
			pParam->pastrReplacedz->Add( strReplaced );
			pParam->padwReplacedLinez->Add( idxRow );
		}
	}

	pProgress->NotifyComplete( nReplace );
	return( 0 );
}


/*-----------------------------------------------------------------------------
[名称]	選択範囲全置換
[機能]	選択範囲を対象に置換処理を行う。
[戻値]	UINT	置換個数 [-] (-)
[備考]	ワーカスレッドとして使用。
		pThreadParam は TReplaceParam*。
		置換後文字列（１行分すべて）のアレイを返す。
-----------------------------------------------------------------------------*/
static UINT ReplacerSelectedAll(
	LPVOID pThreadParam		// I/O:置換スレッドパラメータ [-] (-) :-
)
{
	CShitarabianDoc*		pDoc = ::GetDocument();
	TReplaceParam*			pParam = (TReplaceParam*)pThreadParam;
	CReplacerDlg*			pParent = pParam->pParent;
	CReplacerProgressDlg*	pProgress = pParent->GetProgressDialog();

	pParam->pastrReplacedz->RemoveAll();
	pParam->padwReplacedLinez->RemoveAll();

	int		idxStartRow = pDoc->GetSelection()->GetSelectedStartRow();
	int		idxEndRow = pDoc->GetSelection()->GetSelectedEndRow();

	CArray<TSelectColumn, TSelectColumn&>*	pColumnz;
	pColumnz = pDoc->GetSelection()->GetSelectedLinez();

	if ( pColumnz->GetSize() != (idxEndRow-idxStartRow+1) )
	{
		// 選択情報がおかしい
		ASSERT( FALSE );
		return( 0 );
	}

// ▼ RB0005 BGN 2003.03.28 (moralog)
	// 検索オブジェクトの取得
	CFinder*	pFinder = ::GetFinder( pParent->m_bRegExp );
// ▲ RB0005 END

	int		nReplace = 0;
	int		idxRow;
	for( idxRow=idxStartRow ; idxRow<=idxEndRow ; idxRow++ ) // 行のループ
	{
		// 中断チェック
		if ( pProgress->IsAbort() )
		{
			pProgress->NotifyStop( nReplace );
			return( 0 );
		}
		pProgress->NotifyProgress( (idxRow*100)/pDoc->GetLineCount() );

		// 置換後文字列の作成
		BOOL		bReplaced = FALSE;
		CString		strReplaced;
		{
			TSelectColumn	tColumn = pColumnz->GetAt(idxRow-idxStartRow);
			BOOL	bFound = TRUE;
			int		idxStartColumn = tColumn.idxStart;

// ▼ RB0005 BGN 2003.03.28 (moralog)
			CString*	pTarget = pDoc->GetLine(idxRow);
			long		idxStartByte = ::CaretColumnToByteColumn( *pTarget, idxStartColumn );
			// 出力を１行分とするために、まず検索開始位置までを取得
			strReplaced = pTarget->Left( idxStartByte );
// ▲ RB0005 END

			while( bFound )
			{
				// 中断チェック
				if ( pProgress->IsAbort() )
				{
					pProgress->NotifyStop( nReplace );
					return( 0 );
				}

				long	idxFoundStartColumn;
				long	nFoundColumn;
// ▼ RB0005 BGN 2003.01.26 (moralog)
// ▽ oridinal BGN
//				CFinder*	pFinder = ::GetFinder( pParent->m_bRegExp );
//				CString*	pTarget = pDoc->GetLine(idxRow);
// △ oridinal END
// ▲ RB0005 END
				bFound = pFinder->FindAtLine(
					*pTarget,
					idxStartColumn,
					tColumn.idxEnd,
					pParent->m_strSubString,
					&idxFoundStartColumn,
					&nFoundColumn,
					pParent->m_bCaseCare,
					pParent->m_bToken
				);

				if ( bFound )
				{
					// 置換文字列の取得
					CString		strReplace;
					{
						strReplace = pFinder->GetReplaceWord(
							pDoc,
							idxRow,
							idxFoundStartColumn,
							idxFoundStartColumn + nFoundColumn,
							pParent->m_strSubString,
							pParent->m_strReplace,
							pParent->m_bCaseCare,
							pParent->m_bToken
						);
					}

// ▼ RB0005 BGN 2003.01.26 (moralog)
// ▽ oridinal BGN
//					long	idxStartByte = ::CaretColumnToByteColumn( *pTarget, idxStartColumn );
// △ oridinal END
					// 検索開始位置を取得
					idxStartByte = ::CaretColumnToByteColumn( *pTarget, idxStartColumn );
// ▲ RB0005 END
					long	idxFoundStartByte = ::CaretColumnToByteColumn( *pTarget, idxFoundStartColumn );
					tColumn.idxEnd -= ::StringToColumn( pParent->m_strSubString );
					tColumn.idxEnd += ::StringToColumn( strReplace );

					// 検索開始位置までを合成
					strReplaced += pTarget->Mid(
						idxStartByte,
						idxFoundStartByte-idxStartByte );

					// 置換文字列を合成
					strReplaced += strReplace;
					idxStartColumn = idxFoundStartColumn + nFoundColumn;
					nReplace++;
					bReplaced = TRUE;
				}
				else
				{
					if ( bReplaced )
					{
						long	idxStartByte = ::CaretColumnToByteColumn( *pTarget, idxStartColumn );
						strReplaced += pTarget->Mid( idxStartByte );
					}
				}
			}
		}

		// 変更情報を蓄える
		if ( bReplaced )
		{
			pParam->pastrReplacedz->Add( strReplaced );
			pParam->padwReplacedLinez->Add( idxRow );
		}
	}

	pProgress->NotifyComplete( nReplace );
	return( 0 );
}
