/*-----------------------------------------------------------------------------
[名称]	ShitarabianViewFloating.cpp
[概要]	Viewクラス（フローティング貼り付け時）の実装
[備考]	なし
[履歴]	2003-02-25	NC		コメント付加(moralog)
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "Common.h"
#include "Shitarabian.h"
#include "ShitarabianDoc.h"
#include "ShitarabianView.h"
#include "imm.h"
#include "EditDrawer.h"
#include "CommandManager.h"
#include "CommandInput.h"
#include "CommandCaret.h"
#include "CommandDelete.h"
#include "GeneralSetting.h"
#include <process.h>
#include "Selection.h"
#include "BoxSelection.h"
#include "FloatingSelection.h"
#include "CommandMultiEdit.h"
#include "Padding.h"
#include "TokenReader.h"


//-----------------------------------------------------------------------------
// ファイル内関数
//-----------------------------------------------------------------------------

/*-----------------------------------------------------------------------------
[名称]	描画オブジェクト取得
[機能]	描画オブジェクト取得処理。
[戻値]	CEditDrawer*	描画オブジェクト [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
static CEditDrawer*	GetDrawer()
{
	return( CEditDrawer::GetInstance() );
}



//-----------------------------------------------------------------------------
// クラスメンバ関数
//-----------------------------------------------------------------------------

/*-----------------------------------------------------------------------------
[名称]	イベントハンドラ
[機能]	主にマウスイベント処理。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::PreTranslateFloatingMode(
	MSG*	pMsg,				// I  :メッセージ [-] (-)
	BOOL	bShift,				// I  :シフト状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bCtrl,				// I  :Ctrl状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bAlt				// I  :Alt状態 [-] (TRUE:押下、FALSE:なし)
)
{
	// warning C4100:警告の無視
	bAlt; bCtrl; bShift;

	CEditDrawer*	pDrawer = GetDrawer();
	CShitarabianDoc* pDoc = GetDocument();

	CFloatingSelection*	pSelection;
	pSelection = pDoc->GetFloatingSelection();


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

	BOOL	bBreak = FALSE;
	BOOL	bRedraw = FALSE;

	switch( pMsg->message )
	{
	case WM_LBUTTONUP:
		ReleaseCapture();
		m_bDrag = FALSE;
		bBreak = TRUE;
		break;

	case WM_MOUSEMOVE:
		DrawStatusBar();
		if ( m_bDrag )
		{
			long	iStartRow = pSelection->GetSelectedStartRow();
			long	iStartColumn = pSelection->GetSelectedStartColumn();

			POINTS	pt = MAKEPOINTS( pMsg->lParam );
			CPoint posCursor( pt.x, pt.y );
			posCursor = ScrollBoxToPixel( posCursor );

			// フローティングの移動座標計算
			CPoint		ptFloat( posCursor );
			ptFloat.x += m_iFloatOffsetX;
			ptFloat.y += m_iFloatOffsetY;

			// 移動処理と表示色解析
			MoveFloatPosition( ptFloat );

			// オートスクロール
			{
				// ScrollToCaret() でカタをつけるためにキャレットを移動させる
				// できれば上端または下端にしたい
				// 上に移動したときは上端？下移動なら下はし？
				BOOL	bUp = ( iStartRow > pSelection->GetSelectedStartRow() );
				BOOL	bDown = ( iStartRow < pSelection->GetSelectedStartRow() );
				BOOL	bLeft = ( iStartColumn > pSelection->GetSelectedStartColumn() );
				BOOL	bRight = ( iStartColumn < pSelection->GetSelectedStartColumn() );

				long	idxRow = pSelection->GetSelectedStartRow();
				long	idxColumn = pSelection->GetSelectedStartColumn();

				if ( bUp )
				{
					//
				}
				if ( bDown )
				{
					idxRow = pSelection->GetSelectedEndRow();
					idxColumn = pSelection->GetSelectedEndColumn();
				}
				if ( bLeft )
				{
					idxRow = pSelection->GetFloatBoundMinRow();
					idxColumn = pSelection->GetFloatBoundMinColumn();
				}
				if ( bRight )
				{
					idxRow = pSelection->GetFloatBoundMaxRow();
					idxColumn = pSelection->GetFloatBoundMaxColumn();
				}

				// キャレットの移動
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute(
					0x00,
					idxRow,
					idxColumn
				);
				cmdCaret.Execute( pDoc );
				ScrollToCaret();
			}

			bRedraw = TRUE;
		}
		bBreak = TRUE;
		break;

	case WM_LBUTTONDOWN:
		{
			m_bDrag = TRUE;
			SetCapture( );

			// ピクセル座標を得る
			POINTS	pt = MAKEPOINTS( pMsg->lParam );
			CPoint posCursor( pt.x, pt.y );
			posCursor = ScrollBoxToPixel( posCursor );

			CDC*		pDC = NULL;
			pDC = GetDC();
			if ( pDC == NULL )
			{
				break;
			}

			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			idxRow = pDrawer->PixelToCaretRow( posCursor.y, pDoc );
			CString*	pstrCurrentLine = pDoc->GetLine( idxRow );
			if ( pstrCurrentLine != NULL )
			{
				idxColumn = 0;
				CEmphasisLine*	pEmphasisLine = pDoc->GetEmphasisLine( idxRow );
				if ( pEmphasisLine != NULL )
				{
					idxColumn = pEmphasisLine->PixelToCaretColumn( posCursor.x, TRUE );
				}

				if ( pSelection->IsSelected( idxRow, idxColumn ) )
				{
					CFloatingSelection*	pSelection;
					pSelection = pDoc->GetFloatingSelection();
					CPoint	ptFloat = pSelection->GetPosition();
					m_iFloatOffsetX = ptFloat.x - posCursor.x;
					m_iFloatOffsetY = ptFloat.y - posCursor.y;
				}
				else
				{
					// 選択BOX外なら定着
					OnEditFloatCopy();
					// すぐにBOX選択を開始する
					PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
					m_bDrag = FALSE;
				}
			}
			ReleaseDC( pDC );
		}
		bRedraw = TRUE;
		bBreak = TRUE;
		break;

	default:
		break;
	}

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

	if ( bRedraw )
	{
		// 再描画
		pDoc->ReDraw();

	}

	if( bBreak )
	{
		return( TRUE );
	}
	else
	{
		return( FALSE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	BOX選択モードへの移行
[機能]	BOX選択モードへ移行する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::ToBoxSelection()
{
	CShitarabianDoc* pDoc = GetDocument();
	CFloatingSelection*	pSelection;
	pSelection = pDoc->GetFloatingSelection();

	pSelection->UnDoReflect();
	pDoc->SetOperationMode( OperationBoxSelect );
	pDoc->SetAllUpdate();
}


/*-----------------------------------------------------------------------------
[名称]	通常編集モードへの移行
[機能]	通常編集モードへ移行する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::ToNormal()
{
	CShitarabianDoc* pDoc = GetDocument();
	CFloatingSelection*	pSelection;
	pSelection = pDoc->GetFloatingSelection();

	// キャレットを表示させるモード
	m_bVisibleCaret = TRUE;

	pSelection->UnDoReflect();
	pDoc->SetOperationMode( OperationNormal );
	pDoc->SetAllUpdate();
}


/*-----------------------------------------------------------------------------
[名称]	フローティング貼り付け取り消し
[機能]	フローティング貼り付け取り消し処理。
[戻値]	なし
[備考]	BOX選択モードへ移行する。
-----------------------------------------------------------------------------*/
void CShitarabianView::OnEditFloatCancel()
{
	CShitarabianDoc* pDoc = GetDocument();

	ToBoxSelection();

	// ワンショットBOX選択の設定であれば通常モードに戻る
	if( CGeneralSetting::GetInstance()->GetOneShotBOXSelect() )
	{
		ToNormal();
	}

	// 再描画
	pDoc->ReDraw();
}


/*-----------------------------------------------------------------------------
[名称]	コピー貼り付けハンドラ
[機能]	フローティング貼り付け複製定着処理。
[戻値]	なし
[備考]	「ここへコピー」
-----------------------------------------------------------------------------*/
void CShitarabianView::OnEditFloatCopy()
{
	CShitarabianDoc* pDoc = GetDocument();

	//定着
	{
		CFloatingSelection*	pSelection;
		pSelection = pDoc->GetFloatingSelection();
		pSelection->Confirm();

		// モードの取り消し
		ToBoxSelection();

		// 選択範囲取り消し
		CBoxSelection*	pBox;
		pBox = pDoc->GetBoxSelection();
		pBox->SetSelectedNutral();

	}

	// ワンショットBOX選択の設定であれば通常モードに戻る
	if( CGeneralSetting::GetInstance()->GetOneShotBOXSelect() )
	{
		ToNormal();
	}

	// 再描画
	pDoc->ReDraw();
}


/*-----------------------------------------------------------------------------
[名称]	移動貼り付けハンドラ
[機能]	フローティング貼り付け切り取り定着処理。
[戻値]	なし
[備考]	「ここへ移動」
-----------------------------------------------------------------------------*/
void CShitarabianView::OnEditFloatMove()
{
	CShitarabianDoc*	pDoc = GetDocument();
	CFloatingSelection*	pSelection;
	pSelection = pDoc->GetFloatingSelection();

	// Box選択範囲のクリア
	pSelection->UnDoReflect();
	pDoc->GetBoxSelection()->BoxClear();
	pSelection->DoReflect();

	// コピー
	OnEditFloatCopy();
}


/*-----------------------------------------------------------------------------
[名称]	キー押下ハンドラ
[機能]	押下されたキーに応じた処理。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::PreTranslateKeyDownFloatingMode(
	UCHAR	unKey,				// I  :キー [仮想キーコード] (-)
	BOOL	bShift,				// I  :シフト状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bCtrl,				// I  :Ctrl状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bAlt				// I  :Alt状態 [-] (TRUE:押下、FALSE:なし)
)
{
	// warning C4100:警告の無視
	bAlt; bCtrl; bShift;

	CEditDrawer*		pDrawer = GetDrawer();
	CShitarabianDoc*	pDoc = GetDocument();
	CFloatingSelection*	pSelection;
	pSelection = pDoc->GetFloatingSelection();

	BOOL	bBreak = FALSE;

//	int idxOldSelectedStartRow = pSelection->GetSelectedStartRow();
//	int idxOldSelectedEndRow = pSelection->GetSelectedEndRow();

	int	nRow = pDoc->GetLineCount();


	switch( unKey )
	{
	case VK_F4:
		// 選択状態の解除
		// モードの取り消し
		pSelection->UnDoReflect();
		ToNormal();
		bBreak = TRUE;
		break;

	case VK_LEFT:
	case VK_RIGHT:
	case VK_UP:
	case VK_DOWN:
		{
			int		iRowHeight = pDrawer->CaretRowToPixel( 1 );

			// フローティングの移動位置計算
			CPoint	ptTopLeft;				
			ptTopLeft = pSelection->GetPosition();
			switch( unKey )
			{
			case VK_LEFT:
				ptTopLeft.x--;
				if ( ptTopLeft.x < 0 )
				{
					ptTopLeft.x = 0;
				}
				break;
			case VK_RIGHT:
				ptTopLeft.x++;
				break;
			case VK_UP:
				ptTopLeft.y -= iRowHeight;
				if ( ptTopLeft.y < 0 )
//				if ( !CGeneralSetting::GetInstance()->GetFreeCursor() )
//				{
					ptTopLeft.y = 0;
//				}
				break;
			case VK_DOWN:
				ptTopLeft.y += iRowHeight;
				break;
			default:
				break;
			}

			// 移動処理と表示色解析
			MoveFloatPosition( ptTopLeft );

			// オートスクロール
			CCommandCaret	cmdCaret;
			switch( unKey )
			{
			case VK_UP:
				cmdCaret.SetAttribute(
					0x00,
					pSelection->GetSelectedStartRow(),
					pSelection->GetSelectedStartColumn()
				);
				break;
			case VK_LEFT:
				cmdCaret.SetAttribute(
					0x00,
					pSelection->GetFloatBoundMinRow(),
					pSelection->GetFloatBoundMinColumn()
				);
				break;
			case VK_RIGHT:
				cmdCaret.SetAttribute(
					0x00,
					pSelection->GetFloatBoundMaxRow(),
					pSelection->GetFloatBoundMaxColumn()
				);
				break;
			case VK_DOWN:
				cmdCaret.SetAttribute(
					0x00,
					pSelection->GetSelectedEndRow(),
					pSelection->GetSelectedEndColumn()
				);
				break;
			default:
				break;
			}
			cmdCaret.Execute( pDoc );
			ScrollToCaret();
		}
		bBreak = TRUE;
		break;

	case VK_BACK:
	case VK_DELETE:
		bBreak = TRUE;
		break;

	default:
		return( FALSE );
		break;
	}

	if ( nRow != pDoc->GetLineCount() )
	{
		ResetHScroll();
	}

	{
		// 再描画
		pDoc->ReDraw();

		// ここでDrawCaret()すると描画が全くされない。
		// キャレットの描画はDrawPage()内でする。

		GetDocument()->SetMainView( this );
		return( TRUE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	文字入力ハンドラ
[機能]	入力された文字に応じた処理。
[戻値]	なし
[備考]	VK_ESCAPE:	取り消し
		VK_RETURN:	定着
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::PreTranslateCharFloatingMode(
	CString	strChar,			// I  :入力文字列　[-] (-)
	BOOL	bShift,				// I  :シフト状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bCtrl,				// I  :Ctrl状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bAlt				// I  :Alt状態 [-] (TRUE:押下、FALSE:なし)
)
{
	// warning C4100:警告の無視
	bAlt; bCtrl; bShift;

	CShitarabianDoc*	pDoc = GetDocument();
	CFloatingSelection*	pSelection;
	pSelection = pDoc->GetFloatingSelection();

	BOOL	bBreak = FALSE;
	BOOL	bSelectedModify = FALSE;

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

	int	nRow = pDoc->GetLineCount();

	if ( strChar == VK_ESCAPE )
	{
		// 選択状態の解除
		// モードの取り消し
		{
			pSelection->UnDoReflect();
			ToNormal();
			bSelectedModify = TRUE;
			bBreak = TRUE;
		}
	}
	else
	if ( strChar == VK_RETURN )
	{
		CFloatingSelection*	pSelection;
		pSelection = pDoc->GetFloatingSelection();
		pSelection->Confirm();

		// モードの取り消し
		ToBoxSelection();

		// 選択範囲取り消し
		CBoxSelection*	pBox;
		pBox = pDoc->GetBoxSelection();
		pBox->SetSelectedNutral();
		bBreak = TRUE;
	}
	else
	{
		return( FALSE );
	}


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

	if ( nRow != pDoc->GetLineCount() )
	{
		ResetHScroll();
	}

	{
		// スクロールできそうであればスクロールバーを制御
		ScrollToCaret();

		// 再描画
		pDoc->ReDraw();

		// ここでDrawCaret()すると描画が全くされない。
		// キャレットの描画はDrawPage()内でする。

		GetDocument()->SetMainView( this );
		return( TRUE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	フローティング移動処理
[機能]	移動処理と、それに伴う複数行表示色解析。
[戻値]	BOOL	処理結果 [-] (TRUE:成功、FALSE:失敗)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::MoveFloatPosition(
	CPoint&	ptFloat			// I  :Floating座標　[プレーンpixel] (-)
)
{
	CShitarabianDoc*	pDoc = GetDocument();
	CFloatingSelection*	pSelection = pDoc->GetFloatingSelection();
	CEditDrawer*		pDrawer = CEditDrawer::GetInstance();

	// 選択情報を更新し、変更の生じた行の範囲を得る
	long	iStartRow = pSelection->GetSelectedStartRow();
	long	iEndRow = pSelection->GetSelectedEndRow();
	{
		// 一時的に表示色解析をOFFにして行の編集を行う。
		CEmphasisLine::SetAnalizeMultiLineEmphasisEnable( FALSE );
		pSelection->UnDoReflect();

		if ( CGeneralSetting::GetInstance()->GetFreeCursor() )
		{
		// フリーカーソルの場合は行の拡張をする
			pSelection->SetPosition( ptFloat );

			// 上方向
			if( ptFloat.y < 0 )
			{
				// キャレットの移動
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( 0x00, 0, 0 );
				cmdCaret.Execute( pDoc );
				cmdCaret.SetAttribute( VK_UP, 0, 0 );
				cmdCaret.Execute( pDoc );

				// 選択行情報は１行分下へずれる
				iStartRow++;
				iEndRow++;
			}

			// 下方向
			{
				int		iRequiredRow = pDrawer->PixelToCaretRow( ptFloat.y, pDoc );
				iRequiredRow += iEndRow - iStartRow;
				// 行位置決定
				if( iRequiredRow >= pDoc->GetLineCount() )
				{
					// フリーカーソルモードのとき行・カラムを拡張する
					pDoc->AppendRow( iRequiredRow );
				}
			}
		}
		else
		{
		// フリーカーソルで無い場合は移動範囲を制限する
			ptFloat.y = max( 0, ptFloat.y );
			TRACE("%d",(pDoc->GetLineCount()-(iEndRow-iStartRow+1))
					* pDrawer->CaretRowToPixel(1) );
			ptFloat.y = min(
				ptFloat.y,
				(pDoc->GetLineCount()-(iEndRow-iStartRow+1))
					* pDrawer->CaretRowToPixel(1)
			);

			pSelection->SetPosition( ptFloat );
		}

		pSelection->DoReflect();
		CEmphasisLine::SetAnalizeMultiLineEmphasisEnable( TRUE );

		// 変更が生じた行範囲の取得
		iStartRow = min( iStartRow, pSelection->GetSelectedStartRow() );
		iEndRow = max( iEndRow, pSelection->GetSelectedEndRow() );
	}

	// 変更の生じた行に対し、複数行表示色のみ表示色解析
	int		idxLine;
	for( idxLine=iStartRow ; idxLine<=iEndRow ; idxLine++ )
	{
		CEmphasisLine*	pLine = pDoc->GetEmphasisLine( idxLine );
		if ( pLine != NULL )
		{
			pLine->ResetDetailEmphasis();
		}
	}
	for( idxLine=iStartRow ; idxLine<=iEndRow ; idxLine++ )
	{
		pDoc->AnalizeMultiLineEmphasis(
			CGeneralSetting::GetInstance()->GetEmphasisDefine(),
			idxLine
		);
	}
	return( TRUE );
}