// ★コメント未記入
// MacroExecute.cpp: CMacroExecute クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "shitarabian.h"
#include "MacroExecute.h"
#include "ShitarabianDoc.h"
#include "MainFrm.h"

#include "CommandCaret.h"
#include "CommandInput.h"
#include "CommandManager.h"
#include "CommandDelete.h"
#include "Selection.h"
#include "ToolBarManager.h"
#include "ShitarabianView.h"
#include "RoiSelection.h"
#include "GeneralSetting.h"
#include "SettingPath.h"
#include "EditDrawer.h"
#include "Common.h"
#include "ExeCommon.h"

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



// どういうわけか__stdcallではエクスポートできないようなので
// __cdecl（C、C++標準）で我慢する。
extern "C" BOOL __declspec(dllexport) FuncExecuteMacroCommand( int, int, void* );
BOOL FuncExecuteMacroCommand(
	int				eCommand,
	int				nArg,
	void*			paArg
)
{
	return(
		CMacroExecute::Execute(
			(EMacroCommand)eCommand,
			nArg,
			paArg
		)
	);
}




//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CMacroExecute::CMacroExecute()
{

}

CMacroExecute::~CMacroExecute()
{

}


BOOL	CMacroExecute::Execute(
	int				eCommand,
	int				nArg,
	void*			paArg
)
{
	BOOL	bSuccess = FALSE;

	CShitarabianDoc* pDoc;
	{
		pDoc = ::GetDocument();
		if ( pDoc == NULL )
		{
			return( FALSE );
		}
	}
	CSelection*			pSelection = pDoc->GetSelection();

	BOOL	bSelectedModify = FALSE;
	int idxOldSelectedStartRow = pSelection->GetSelectedStartRow();
	int idxOldSelectedEndRow = pSelection->GetSelectedEndRow();

	int idxRow = pDoc->GetCaretRow();
	int idxColumn = pDoc->GetCaretColumn();

	int	nRow = pDoc->GetLineCount();

	switch( (EMacroCommand)eCommand )
	{
//挿入系
	case MC_insert:			//文字列の挿入（キャレット移動あり）
		if ( nArg == 1 )
		{
			CString		strInsert( (const char*)(*(void**)paArg) );
			CCommandInput	cmdInput;
			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			cmdInput.SetAttribute( strInsert, idxRow, idxColumn );
			cmdInput.Execute( pDoc );

			CCommandManager*	pCmd = CCommandManager::GetInstance();
			pCmd->Add( cmdInput );
			bSuccess = TRUE;
		}
		break;

	case MC_insertfix:		//文字列の挿入（キャレット移動なし）
		if ( nArg == 1 )
		{
			CString		strInsert( (const char*)(*(void**)paArg) );
			CCommandInput	cmdInput;
			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			cmdInput.SetAttribute( strInsert, idxRow, idxColumn );
			cmdInput.Execute( pDoc );

			CCommandManager*	pCmd = CCommandManager::GetInstance();
			pCmd->Add( cmdInput );

			// カーソルを元の位置に戻す
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( 0x00, idxRow, idxColumn );
			cmdCaret.Execute( pDoc );
			bSuccess = TRUE;
		}
		break;

//削除系
	case MC_backspace:		//BSキー入力
		if ( nArg == 0 )
		{
			// 文書の先頭ではBSできない
			if ( idxRow == 0 )
			if ( idxColumn == 0 )
			{
				break;
			}
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( VK_LEFT, idxRow, idxColumn );
			cmdCaret.Execute( pDoc );
		} // MC_deleteへ

	case MC_delete:			//DELキー入力
		if ( nArg == 0 )
		{
			{
				// コマンドの登録
				CCommandDelete	cmdDelete;

				if (( pSelection->GetSelectedStartColumn() == pSelection->GetSelectedEndColumn() ) &&
					( pSelection->GetSelectedStartRow() == pSelection->GetSelectedEndRow() ) )
				{
				// 単文字削除のとき
					int idxRow = pDoc->GetCaretRow();
					int idxColumn = pDoc->GetCaretColumn();
					cmdDelete.SetAttribute( idxRow, idxColumn, idxRow, idxColumn+1 );
				}
				else
				{
				// 選択範囲削除
					cmdDelete.SetAttribute(
						pSelection->GetSelectedStartRow(),
						pSelection->GetSelectedStartColumn(),
						pSelection->GetSelectedEndRow(),
						pSelection->GetSelectedEndColumn()
					);
					
				}
				cmdDelete.Execute( pDoc );

				CCommandManager*	pCmd = CCommandManager::GetInstance();
				pCmd->Add( cmdDelete );
			}
			// 選択状態の解除
			if ( pSelection->IsSelected() )
			{
				bSelectedModify = TRUE;
			}
			pSelection->SetSelectedNutral();
			bSuccess = TRUE;
		}
		break;

//カーソル移動系
	case MC_up:				//カーソル上移動
		if ( nArg == 0 )
		{
			if ( idxRow > 0 )
			{
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( VK_UP, idxRow, idxColumn );
				cmdCaret.Execute( pDoc );
				bSuccess = TRUE;
			}
		}
		break;

	case MC_down:			//カーソル下移動
		if ( nArg == 0 )
		{
			if ( idxRow < nRow-1 )
			{
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( VK_DOWN, idxRow, idxColumn );
				cmdCaret.Execute( pDoc );
				bSuccess = TRUE;
			}
		}
		break;

	case MC_left:			//カーソル左移動
		if ( nArg == 0 )
		{
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( VK_LEFT, idxRow, idxColumn );
			bSuccess = cmdCaret.Execute( pDoc );
		}
		break;

	case MC_right:			//カーソル右移動
		if ( nArg == 0 )
		{
			CString*	pstr = pDoc->GetLine( idxRow );
			if ( pstr != NULL )
			{
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( VK_RIGHT, idxRow, idxColumn );
				bSuccess = cmdCaret.Execute( pDoc );
			}
		}
		break;

	case MC_gofileend:		//ファイルの最後に移動
		if ( nArg == 0 )
		{
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( 0x00, nRow-1, 0 );
			cmdCaret.Execute( pDoc );
			cmdCaret.SetAttribute( VK_END, 0, 0 );
			bSuccess = cmdCaret.Execute( pDoc );
		}
		break;

	case MC_gofiletop:		//ファイルの先頭に移動
		if ( nArg == 0 )
		{
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( 0x00, 0, 0 );
			bSuccess = cmdCaret.Execute( pDoc );
		}
		break;

	case MC_golastupdated:	//最後に編集した所に移動
		AfxMessageBox( "未実装(MC_golastupdated)" );
		break;

	case MC_golineend:		//行の最後に移動
		if ( nArg == 0 )
		{
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( VK_END, 0, 0 );
			bSuccess = cmdCaret.Execute( pDoc );
		}
		break;

	case MC_golinetop:		//行の先頭に移動
		if ( nArg == 0 )
		{
			CCommandCaret	cmdCaret;
			cmdCaret.SetAttribute( VK_HOME, 0, 0 );
			bSuccess = cmdCaret.Execute( pDoc );
		}
		break;

	case MC_goscreenend:	//画面の最後に移動
	case MC_goscreentop:	//画面の先頭に移動
		AfxMessageBox( "未実装(MC_goscreenend/top)" );
		break;

	case MC_gocaretrow:		//任意の行へのカーソル移動
		if ( nArg == 1 )
		{
			int	iNewRow = *( (int*)(*(void**)paArg) );
			if ( iNewRow >= 0 )
			if ( iNewRow < nRow )
			{
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( 0x00, iNewRow, idxColumn );
				bSuccess = cmdCaret.Execute( pDoc );
			}
		}
		break;

	case MC_gocaretcolumn:	//任意の列へのカーソル移動
		if ( nArg == 1 )
		{
			int	iNewColumn = *( (int*)(*(void**)paArg) );

			CString*	pstr = pDoc->GetLine( idxRow );
			if ( pstr != NULL )
			if ( iNewColumn < ::StringToColumn( *pstr ) )
			{
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( 0x00, idxRow, iNewColumn );
				bSuccess = cmdCaret.Execute( pDoc );
			}
		}
		break;

	case MC_wordleft:		//単語左
	case MC_wordright:		//単語右
		AfxMessageBox( "未実装(MC_wordleft/right)" );
		break;

	case MC_setmark:		//現在行のマーク/マーク解除
		if ( nArg == 0 )
		{
			pDoc->Mark( idxRow );
			bSuccess = TRUE;
		}
		break;

	case MC_clearallmark:	//マークを全て解除
		if ( nArg == 0 )
		{
			pDoc->DeMark();
			bSuccess = TRUE;
		}
		break;

	case MC_nextmark:		//マーク行の下検索
		if ( nArg == 0 )
		{
			pDoc->NextMark();
			bSuccess = TRUE;
		}
		break;

	case MC_prevmark:		//マーク行の上検索
		if ( nArg == 0 )
		{
			pDoc->PrevMark();
			bSuccess = TRUE;
		}
		break;

//クリップボード
	case MC_beginsel:		//範囲選択開始
	case MC_endsel:			//範囲選択モードを解除
	case MC_escapesel:		//範囲選択解除
	case MC_copy:			//コピー
	case MC_cut:			//切り抜き
	case MC_paste:			//貼り付け

//その他編集
	case MC_indent:			//選択行のインデント
	case MC_unindent:		//選択行の逆インデント
	case MC_undo:			//やり直し
	case MC_redo:			//やり直しのやり直し
	case MC_overwriteswitch://挿入・上書きモード切替

//検索
	case MC_find:			//任意の単語の検索（パラメタつき）
	case MC_finddown:		//下候補
	case MC_findup:			//上候補
	case MC_replace:		//任意の単語の置換（パラメタつき）
	case MC_replacedown:	//下方向置換
	case MC_replaceup:		//上方向置換
	case MC_replaceall:		//全置換
		break;

// 表示
	case MC_setallupdate:	// 全表示要求
		if ( nArg == 0 )
		{
			pDoc->SetAllUpdate();
			bSuccess = TRUE;
		}
		break;

	case MC_redraw:			// 再描画
		if ( nArg == 0 )
		{
		    const HINSTANCE hInstance = ::AfxGetResourceHandle();
			CWinApp*		pApp = AfxGetApp();
			::AfxSetResourceHandle( pApp->m_hInstance );
			pDoc->ReDraw();
			::AfxSetResourceHandle(hInstance);
			bSuccess = TRUE;
		}
		break;

// Docの取得
	case MC_getlinecount:	// 行数の取得
		if ( nArg == 1 )
		{
			int*	pnLine = ( (int*)(*(void**)paArg) );
			*pnLine = pDoc->GetLineCount();
			bSuccess = TRUE;
		}
		break;

	case MC_getline:		// 任意行内容の取得
		if ( nArg == 3 )
		{
			// 第一引数	行番号
			int			iLine = *( (int*)(*(void**)paArg) );
			// 第二引数 格納バッファアドレス
			char*		pstrLine = ((char*)*((void**)paArg+1) );
			// 第三引数 格納バイト数
			int*		pLength = ((int*)*((void**)paArg+2) );

			// pstrLine がNULLのときは長さだけを返す
			CString*	pstrSrc = pDoc->GetLine( iLine );
			if ( pstrLine == NULL )
			{
				*pLength = pstrSrc->GetLength();
			}
			else
			{
				*pLength = min( (*pLength)-1, pstrSrc->GetLength() );
				memcpy( pstrLine, (LPCTSTR)*pstrSrc, *pLength );
				pstrLine[ *pLength ] = 0x00;
			}
			bSuccess = TRUE;
		}
		break;

	case MC_getcaretcolumn:	// キャレット桁の取得
	case MC_getcaretrow:	// キャレット行の取得
		break;

// ツールバー制御
	case MC_entrytoolbar:		// ツールバーの追加
		if ( nArg == 1 )
		{
			// [0] リソースID
				int		idResource = *((int*)(*(((void**)paArg)+0)));

			// EXEのツールバー管理にアクセス！
			bSuccess = CToolBarManager::GetInstance()->EntryToolBar(
				idResource
			);
		}
		break;

	case MC_showtoolbar:		// ツールバーの表示／非表示
		if ( nArg == 1 )
		{
			// [0] BOOL
				BOOL		bShow = *((BOOL*)(*(((void**)paArg)+0)));

			// EXEのツールバー管理にアクセス！
			bSuccess = CToolBarManager::GetInstance()->ShowToolBar(
				bShow
			);
		}
		break;


	case MC_spawncombobox:		// コンボボックスの作成
		if ( nArg == 4 )
		{
			int			idxButton = *((int*)(*(((void**)paArg)+0)));
			int			iWidth = *((int*)(*(((void**)paArg)+1)));
			BOOL		bEdit = *((BOOL*)(*(((void**)paArg)+2)));
			HWND*		phwnd = (HWND*)(*(((void**)paArg)+3));
//			CComboBox**	ppCombo = ((CComboBox**)(*(((CComboBox***)paArg)+3)));

			// EXEのツールバー管理にアクセス！
			*phwnd = CToolBarManager::GetInstance()->SpawnComboBox(
				idxButton,
				iWidth,
				bEdit
			)->m_hWnd;
			bSuccess = ( *phwnd != NULL );
		}
		break;

	case MC_keydown:
		if ( nArg == 4 )
		{
			// [0] キー
				const char*	pstrKey = ((const char*)(*(((void**)paArg)+0)));
			// [1] シフト状態
				BOOL		bShift = *((BOOL*)(*(((void**)paArg)+1)));
			// [2] コントロール状態
				BOOL		bCtrl = *((BOOL*)(*(((void**)paArg)+2)));
			// [3] Alt状態
				BOOL		bAlt = *((BOOL*)(*(((void**)paArg)+3)));

			if( strlen(pstrKey) != 0 )
			{
				pDoc->GetMainView()->OnKeyDown(
					pstrKey[0],
					bShift,
					bCtrl,
					bAlt
				);
			}
			bSuccess = TRUE;
		}
		break;

	case MC_keyinput:
		if ( nArg == 4 )
		{
			// [0] キー
				const char*	strChar = ((const char*)(*(((void**)paArg)+0)));
			// [1] シフト状態
				BOOL		bShift = *((BOOL*)(*(((void**)paArg)+1)));
			// [2] コントロール状態
				BOOL		bCtrl = *((BOOL*)(*(((void**)paArg)+2)));
			// [3] Alt状態
				BOOL		bAlt = *((BOOL*)(*(((void**)paArg)+3)));

			// 
			pDoc->GetMainView()->OnChar(
				strChar,
				bShift,
				bCtrl,
				bAlt,
				FALSE
			);
			bSuccess = TRUE;
		}
		break;

	case MC_setselectmode:
		if ( nArg == 1 )
		{
			// [0] モード種別
				int		iMode = *((int*)(*(((void**)paArg)+0)));

			// 
			pDoc->SetOperationMode( (EOperationMode)iMode );

			CSelection*	pSelection;
			pSelection = pDoc->GetSelection();
			pSelection->SetSelectedNutral();
			bSuccess = TRUE;
		}
		break;

	case MC_getselectmode:
		if ( nArg == 1 )
		{
			// [0] モード種別
				int*	piMode = ((int*)(*(((void**)paArg)+0)));

			// 
			*piMode = pDoc->GetOperationMode();
			bSuccess = TRUE;
		}
		break;

	case MC_getroi:
		if ( nArg == 1 )
		{
			// [0] ROI矩形
				CRect*	prcROI = ((CRect*)(*(((void**)paArg)+0)));

			// 
			CROISelection*	pSelection = pDoc->GetROISelection();
			CRect rcROI = pSelection->GetROI();
			rcROI.NormalizeRect();
			*prcROI = rcROI;

			return( *prcROI != CRect(0,0,0,0) );
		}
		break;

	case MC_draw:
		if ( nArg == 4 )
		{
			// [0] ROI矩形
//				CDC*	pDstDC =	 ((CDC*)(*(((CDC**)paArg)+0)));
				HDC		hdc =		*((HDC*)(*(((void**)paArg)+0)));
			// [1] ROI矩形
//				int		iSrcLeft = *((int*)(*(((int**)paArg)+1)));
			// [2] ROI矩形
//				int		iSrcTop = *((int*)(*(((int**)paArg)+2)));
			// [3] ROI矩形
				RECT	rcSrcROI = *((RECT*)(*(((void**)paArg)+3)));

			// 
			pDoc->GetMainView()->DrawToROI(
				CDC::FromHandle( hdc ),
				0,
				0,
				rcSrcROI
			);

			return( TRUE );
		}
		break;

	case MC_setemphasisenable:
		if ( nArg == 1 )
		{
			// [0] 
				BOOL	bEnable = *((BOOL*)(*(((void**)paArg)+0)));

			// 
			CGeneralSetting::GetInstance()->GetEmphasisDefine()->SetEnable( bEnable );

			// ドキュメント表示情報の再構築
			pDoc->ReflectEmphasis();

			bSuccess = TRUE;
		}
		break;

	case MC_getemphasisenable:
		if ( nArg == 0 )
		{
			BOOL	bEnable;
			bEnable = CGeneralSetting::GetInstance()->GetEmphasisDefine()->GetEnable();
			return( bEnable );
		}
		break;

	case MC_getinipath:
		if ( nArg == 2 )
		{
			// [0] IniPath
				char*	pstr = ((char*)(*(((void**)paArg)+0)));
			// [1] 長さ
				int*	pLength = ((int*)(*(((void**)paArg)+1)));

			CString		strIniPath = CSettingPath::GetInstance()->GetFolderPath();
			if ( pstr == NULL )
			{
				*pLength = strIniPath.GetLength();
			}
			else
			{
				*pLength = min( (*pLength)-1, strIniPath.GetLength() );
				memcpy( pstr, (LPCTSTR)strIniPath, *pLength );
				pstr[ *pLength ] = 0x00;
			}
			bSuccess = TRUE;
		}
		break;

	case MC_getclientrect:
	// ウィンドウ内矩形取得
		if ( nArg == 1 )
		{
			CWinApp*		pApp = ::AfxGetApp();
			CMainFrame*		pWnd = (CMainFrame*)(pApp->GetMainWnd());

			RECT*	prcClient = ((CRect*)(*(((void**)paArg)+0)));
			CRect	rcClient;
			pWnd->GetClientRect( &rcClient );
			*prcClient = rcClient;
			bSuccess = TRUE;
		}
		break;

	case MC_getselectedtext:
	// 選択テキスト取得
		if ( nArg == 2 )
		{
			// [0] text
				char*	pstr = ((char*)(*(((void**)paArg)+0)));
			// [1] 長さ
				int*	pLength = ((int*)(*(((void**)paArg)+1)));

			CString		str = pDoc->GetSelection()->GetSelectedText();

			if ( pstr == NULL )
			{
				*pLength = str.GetLength();
			}
			else
			{
				*pLength = min( (*pLength)-1, str.GetLength() );
				memcpy( pstr, (LPCTSTR)str, *pLength );
				pstr[ *pLength ] = 0x00;
			}
			bSuccess = TRUE;
		}
		break;

	case MC_getselectinfonormal:
	// 通常選択情報取得
		if ( nArg == 4 )
		{
			int*	piStartRow		= ((int*)(*(((void**)paArg)+0)));
			int*	piStartColumn	= ((int*)(*(((void**)paArg)+1)));
			int*	piEndRow		= ((int*)(*(((void**)paArg)+2)));
			int*	piEndColumn		= ((int*)(*(((void**)paArg)+3)));

			*piStartRow		= pDoc->GetNormalSelection()->GetSelectedStartRow();
			*piStartColumn	= pDoc->GetNormalSelection()->GetSelectedStartColumn();
			*piEndRow		= pDoc->GetNormalSelection()->GetSelectedEndRow();
			*piEndColumn	= pDoc->GetNormalSelection()->GetSelectedEndColumn();
			bSuccess = TRUE;
		}
		break;

	case MC_getselectinfobox:
	// ＢＯＸ選択情報取得
		if ( nArg == 1 )
		{
//			CDWordArray*	pdwaSelectInfoz	= ((CDWordArray*)(*(((CDWordArray**)paArg)+0)));

			// please! 未実装
			::ErrorLog(
				"未実装",
				"CMacroExecute::Execute()"
			);

			bSuccess = TRUE;
		}
		break;

	case MC_isselected:
	// 選択状態判定
		if ( nArg == 1 )
		{
			BOOL*	pbSelected = ((BOOL*)(*(((void**)paArg)+0)));
			*pbSelected = pDoc->GetSelection()->IsSelected();
			bSuccess = TRUE;
		}
		break;

	case MC_scrolltocaret:
	// 選択状態判定
		if ( nArg == 0 )
		{
			CShitarabianView*	pView = pDoc->GetMainView();
			if ( pView != NULL )
			{
				pView->ScrollToCaret();
			}
		}
		break;
// エラー
	default:
		ASSERT( FALSE );
		{
			CString		str;
			str.Format( "不明なマクロコマンド（%d）", eCommand );
			::ErrorLog(
				str,
				"CMacroExecute::Execute()"
			);
		}
		break;
	}

	if ( bSelectedModify )
	{
		pDoc->SetUpdateStartRow( min( idxOldSelectedStartRow, pSelection->GetSelectedStartRow() ) );
		pDoc->SetUpdateEndRow( max( idxOldSelectedEndRow, pSelection->GetSelectedEndRow() ) );
	}

	return( bSuccess );
}
