/*-----------------------------------------------------------------------------
[名称]	CommandDelete.cpp
[概要]	文字削除コマンドクラスの実装
[備考]	なし
[履歴]	2003-02-27	NC		コメント付加(moralog)
-----------------------------------------------------------------------------*/

//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "Shitarabian.h"
#include "CommandDelete.h"
#include "ShitarabianDoc.h"
#include "CommandInput.h"
#include "CommandCaret.h"
#include "ShitarabianPlugInManager.h"
#include "ExeCommon.h"

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


/*-----------------------------------------------------------------------------
[名称]	コンストラクタ
[機能]	インスタンスの生成。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CCommandDelete::CCommandDelete()
:	m_strDelete()
,	m_idxStartRow( 0 )
,	m_idxStartColumn( 0 )
,	m_idxEndRow( 0 )
,	m_idxEndColumn( 0 )
{

}


/*-----------------------------------------------------------------------------
[名称]	デストラクタ
[機能]	インスタンスの破棄。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CCommandDelete::~CCommandDelete()
{

}


/*-----------------------------------------------------------------------------
[名称]	複製
[機能]	新しいインスタンスを生成して複製する。
[戻値]	ICommand*	複製されたインスタンスへのポインタ [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
ICommand*	CCommandDelete::Duplicate()
{
	ICommand*	pcmdNew;

	pcmdNew = new CCommandDelete;
	pcmdNew->Copy( *this );

	return( pcmdNew );
}


/*-----------------------------------------------------------------------------
[名称]	複製
[機能]	新しいインスタンスを生成して複製する。
[戻値]	ICommand*	複製されたインスタンスへのポインタ [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
void		CCommandDelete::Copy(
	ICommand&	cmdSrc			// I  :コピー元インスタンス [-] (-) :-
)
{
	CCommandDelete*	pDelete;
	pDelete = dynamic_cast<CCommandDelete*>(&cmdSrc);

	if ( pDelete != NULL )
	{
		m_strDelete = pDelete->m_strDelete;	// 削除された文字列 [-] (-)
		m_idxStartRow = pDelete->m_idxStartRow;		// 削除された位置 [行] (-)
		m_idxStartColumn = pDelete->m_idxStartColumn;	// 削除された位置 [列] (-)
		m_idxEndRow = pDelete->m_idxEndRow;		// 削除された位置 [行] (-)
		m_idxEndColumn = pDelete->m_idxEndColumn;	// 削除された位置 [列] (-)
	}
	else
	{
		// 異なる型のコピーをしようとした
		ASSERT( FALSE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	実行
[機能]	文字削除コマンドを実行する。
[戻値]	BOOL	処理結果 [-] (TURE:成功、FALSE:失敗)
[備考]	SetAttribute()されていること。
-----------------------------------------------------------------------------*/
BOOL		CCommandDelete::Execute(
	CShitarabianDoc* pDoc		// I  :操作対象ドキュメント [-] (-) :-
)
{
	// スタート行のバイト位置を探す
	long		idxStartByte;
	CString*	pstrStartLine;
	{
		// 改行の削除する？
		// もし開始位置が先頭以前をさしていたら、前の行の尻へ
		if ( m_idxStartColumn < 0 )
		{
			pstrStartLine = pDoc->GetLine( m_idxStartRow-1 );
			if ( pstrStartLine == NULL )
			{
				return( FALSE );
			}
			m_idxStartRow--;
			m_idxStartColumn = ::ByteColumnToCaretColumn( *pstrStartLine, pstrStartLine->GetLength() );
		}

		pstrStartLine = pDoc->GetLine( m_idxStartRow );
		if ( pstrStartLine == NULL )
		{
			return( FALSE );
		}
		idxStartByte = ::CaretColumnToByteColumn( *pstrStartLine, m_idxStartColumn );
	}

	// 終了行のバイト位置を探す
	long		idxEndByte;
	CString*	pstrEndLine = pDoc->GetLine( m_idxEndRow );
	{
		if ( pstrEndLine == NULL )
		{
			return( FALSE );
		}

		idxEndByte = ::CaretColumnToByteColumn( *pstrEndLine, m_idxEndColumn );
		// 改行の削除する？
		// もし削除バイトが最後以後をさしていたら、次の行の頭へ（単文字削除のとき限定）
		if ( m_idxStartRow == m_idxEndRow )
		if ( m_idxStartColumn+1 == m_idxEndColumn )
		if ( idxStartByte >= pstrEndLine->GetLength() )
		{
			m_idxEndRow++;
			m_idxEndColumn = 0;
			idxEndByte = 0;
			pstrEndLine = pDoc->GetLine( m_idxEndRow );
			if ( pstrEndLine == NULL )
			{
				return( FALSE );
			}
		}
	}

	// 削除後行の作成
	CString		strRemainLine;
	{
		CString		strRight;
		if ( idxEndByte < pstrEndLine->GetLength() )
		{
			strRight = pstrEndLine->Mid( idxEndByte );
		}
		strRemainLine = pstrStartLine->Left( idxStartByte ) + strRight;
	}

	// 削除文字列の保存
	if ( m_idxStartRow == m_idxEndRow )
	{
	// １行内なら
		// SubStringしてm_strDeleteへ保存
		m_strDelete = pstrStartLine->Mid( idxStartByte, idxEndByte - idxStartByte );
	}
	else
	{
	// 複数行にわたるなら
		// 格納領域を確保
		char*	pStringBuffer= NULL;
		{
			// 必要バイト数を計算
			long	nByte = 0;

			long	idxLine;
			for( idxLine=m_idxStartRow ; idxLine<=m_idxEndRow ; idxLine++ )
			{
				nByte += pDoc->GetLine( idxLine )->GetLength() + strlen( pDoc->ReturnChar() );
			}
			pStringBuffer = new char[ nByte+1 ];
		}

		// コピー
		{
			long	iOffset = 0;

			//最初の行
			CString		strStartLine = pstrStartLine->Right( pstrStartLine->GetLength() - idxStartByte );
			memcpy( pStringBuffer, strStartLine, strStartLine.GetLength() );
			iOffset += strStartLine.GetLength();

			// 行を改行で連結して保存
			long	idxLine;
			for( idxLine=m_idxStartRow+1 ; idxLine<m_idxEndRow ; idxLine++ )
			{
				memcpy( pStringBuffer+iOffset, pDoc->ReturnChar(), strlen( pDoc->ReturnChar() ) );
				iOffset += strlen( pDoc->ReturnChar() );
				memcpy( pStringBuffer+iOffset, *( pDoc->GetLine( idxLine ) ), pDoc->GetLine( idxLine )->GetLength() );
				iOffset += pDoc->GetLine( idxLine )->GetLength();
			}

			// 最後の行
			memcpy( pStringBuffer+iOffset, pDoc->ReturnChar(), strlen( pDoc->ReturnChar() ) );
			iOffset += strlen( pDoc->ReturnChar() );
			CString		strLastLine = pstrEndLine->Left( idxEndByte );
			memcpy( pStringBuffer+iOffset, strLastLine, strLastLine.GetLength() );
			iOffset += strLastLine.GetLength();

			pStringBuffer[ iOffset ] = 0x00;
		}
		m_strDelete = pStringBuffer;

		delete [] pStringBuffer;
	}

	// 該当行をすべて削除
	pDoc->DeleteLinez( m_idxStartRow, m_idxEndRow-m_idxStartRow+1 );

	// 最初の行のLeftと最後の行のRightを連結したものを再登録
	CStringList	lst;
	lst.AddTail( strRemainLine );
	pDoc->InsertLinez( m_idxStartRow, lst );

	// キャレット位置の設定
	CCommandCaret	cmdCaret;
	cmdCaret.SetAttribute( 0x00, m_idxStartRow, m_idxStartColumn );
	cmdCaret.Execute( pDoc );

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

	// 再描画情報更新
	if ( m_idxStartRow == m_idxEndRow )
	{
	// 行数変更なし
		pDoc->SetUpdateStartRow( m_idxStartRow );
		pDoc->SetUpdateEndRow(m_idxStartRow );
	}
	else
	{
	// 行数変更あり
		pDoc->SetUpdateStartRow( m_idxStartRow );
		pDoc->SetUpdateEndRow( AllRow );
	}

	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	取り消し
[機能]	文字削除コマンドを取り消す。
[戻値]	BOOL	処理結果 [-] (TURE:成功、FALSE:失敗)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL		CCommandDelete::UnExecute(
	CShitarabianDoc* pDoc		// I  :操作対象ドキュメント [-] (-) :-
)
{
	// 文字入力コマンドを使用して処理する
	CCommandInput	cmdInput;
	cmdInput.SetAttribute( m_strDelete, m_idxStartRow, m_idxStartColumn );
	cmdInput.Execute( pDoc );

	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	属性設定
[機能]	インスタンスの属性を設定する。
[戻値]	なし
[備考]	Execute()前に必ず行っておくこと。
-----------------------------------------------------------------------------*/
void		CCommandDelete::SetAttribute(
	long		idxStartRow,			// 削除開始位置 [行] (-) :-
	long		idxStartColumn,			// 削除開始位置 [列] (-) :-
	long		idxEndRow,				// 削除終了位置 [行] (-) :-
	long		idxEndColumn			// 削除終了位置 [列] (-) :-
)
{
	BOOL	bNormal = TRUE;
	if ( idxStartRow > idxEndRow )
	{
		bNormal = FALSE;
	}

	if ( idxStartRow == idxEndRow )
	if ( idxStartColumn > idxEndColumn )
	{
		bNormal = FALSE;
	}

	if ( bNormal )
	{
		m_idxStartRow =		idxStartRow;		// 削除開始位置 [行] (-)
		m_idxStartColumn =	idxStartColumn;		// 削除開始位置 [列] (-)
		m_idxEndRow =		idxEndRow;			// 削除終了位置 [行] (-)
		m_idxEndColumn =	idxEndColumn;		// 削除終了位置 [列] (-)
	}
	else
	{
		m_idxStartRow =		idxEndRow;			// 削除開始位置 [行] (-)
		m_idxStartColumn =	idxEndColumn;		// 削除開始位置 [列] (-)
		m_idxEndRow =		idxStartRow;		// 削除終了位置 [行] (-)
		m_idxEndColumn =	idxStartColumn;		// 削除終了位置 [列] (-)
	}
}


