/*-----------------------------------------------------------------------------
[名称]	Selection.cpp
[概要]	選択クラス（基底）の実装
[備考]	なし
[履歴]	2003-02-26	NC		コメント付加(moralog)
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// インクルード・不完全定義
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "Shitarabian.h"
#include "Selection.h"
#include "ShitarabianDoc.h"
#include "ExeCommon.h"

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


/*-----------------------------------------------------------------------------
[名称]	コンストラクタ
[機能]	インスタンスの生成。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CSelection::CSelection()
{

}


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

}


/*-----------------------------------------------------------------------------
[名称]	選択情報取得（始端カラム）
[機能]	選択情報取得。
[戻値]	long		選択始端カラム [-] (-)
[備考]	ノーマライズされた値を得る
-----------------------------------------------------------------------------*/
long	CSelection::GetSelectedStartColumn()
{
	if ( m_idxSelectedRowStart > m_idxSelectedRowEnd )
	{
		return( m_idxSelectedColumnEnd );
	}
	else if ( m_idxSelectedRowStart == m_idxSelectedRowEnd )
	{
		if ( m_idxSelectedColumnStart > m_idxSelectedColumnEnd )
		{
			return( m_idxSelectedColumnEnd );
		}
	}
	return( m_idxSelectedColumnStart );
}


/*-----------------------------------------------------------------------------
[名称]	選択情報取得（終端カラム）
[機能]	選択情報取得。
[戻値]	long		選択終端カラム [-] (-)
[備考]	ノーマライズされた値を得る
-----------------------------------------------------------------------------*/
long	CSelection::GetSelectedEndColumn()
{
	if ( m_pDoc != NULL )
	{
		int		iOver = 0;
		if ( m_pDoc->IsOverwriteMode() )
		{
			iOver = 1;
		}

		if ( m_idxSelectedRowStart < m_idxSelectedRowEnd )
		{
			return( m_idxSelectedColumnEnd+iOver );
		}
		else if ( m_idxSelectedRowStart == m_idxSelectedRowEnd )
		{
			if ( m_idxSelectedColumnStart < m_idxSelectedColumnEnd )
			{
				return( m_idxSelectedColumnEnd+iOver );
			}
		}
		return( m_idxSelectedColumnStart+iOver );
	}
	return( 0 );
}


/*-----------------------------------------------------------------------------
[名称]	選択情報取得（始端行）
[機能]	選択情報取得。
[戻値]	long		選択始端行 [-] (-)
[備考]	ノーマライズされた値を得る
-----------------------------------------------------------------------------*/
long	CSelection::GetSelectedStartRow()
{
	if ( m_idxSelectedRowStart > m_idxSelectedRowEnd )
	{
		return( m_idxSelectedRowEnd );
	}
	else if ( m_idxSelectedRowStart == m_idxSelectedRowEnd )
	{
		if ( m_idxSelectedColumnStart > m_idxSelectedColumnEnd )
		{
			return( m_idxSelectedRowEnd );
		}
	}
	return( m_idxSelectedRowStart );
}


/*-----------------------------------------------------------------------------
[名称]	選択情報取得（終端行）
[機能]	選択情報取得。
[戻値]	long		選択終端行 [-] (-)
[備考]	ノーマライズされた値を得る
-----------------------------------------------------------------------------*/
long	CSelection::GetSelectedEndRow()
{
	if ( m_idxSelectedRowStart < m_idxSelectedRowEnd )
	{
		return( m_idxSelectedRowEnd );
	}
	else if ( m_idxSelectedRowStart == m_idxSelectedRowEnd )
	{
		if ( m_idxSelectedColumnStart < m_idxSelectedColumnEnd )
		{
			return( m_idxSelectedRowEnd );
		}
	}
	return( m_idxSelectedRowStart );
}


/*-----------------------------------------------------------------------------
[名称]	選択文字判定
[機能]	任意の文字が選択されているかを判定する。
[戻値]	BOOL	選択判定 [-] (TRUE:選択、FALSE:非選択)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL	CSelection::IsSelected(
	long	idxRow,			// I  :行 [-] (-) :-
	long	idxColumn		// I  :カラム [-] (-) :-
)
{
	if ( idxRow > GetSelectedEndRow() )
	{
		return( FALSE );
	}else if ( idxRow == GetSelectedEndRow() )
	{
		if ( idxColumn >= GetSelectedEndColumn() )
		{
			return( FALSE );
		}
	}

	if ( idxRow < GetSelectedStartRow() )
	{
		return( FALSE );
	}else if ( idxRow == GetSelectedStartRow() )
	{
		if ( idxColumn < GetSelectedStartColumn() )
		{
			return( FALSE );
		}
	}

	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	選択文字列取得
[機能]	選択中の文字列を取得する。
[戻値]	CString	選択文字列 [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
CString	CSelection::GetSelectedText()
{
	if ( m_pDoc == NULL )
	{
		return( _T("") );
	}

	CString		strSelectedText;

	int			idxSelectedColumnStart = GetSelectedStartColumn();
	int			idxSelectedColumnEnd = GetSelectedEndColumn();
	int			idxSelectedRowStart = GetSelectedStartRow();
	int			idxSelectedRowEnd = GetSelectedEndRow();


	// スタート行のバイト位置を探す
	long		idxStartByte;
	CString*	pstrStartLine;
	{
		// 改行の削除する？
		// もし開始位置が先頭以前をさしていたら、前の行の尻へ
		if ( idxSelectedColumnStart < 0 )
		{
			pstrStartLine = m_pDoc->GetLine( idxSelectedRowStart-1 );
			if ( pstrStartLine == NULL )
			{
				return( strSelectedText );
			}
			idxSelectedRowStart--;
			idxSelectedColumnStart = ::ByteColumnToCaretColumn( *pstrStartLine, pstrStartLine->GetLength() );
		}

		pstrStartLine = m_pDoc->GetLine( idxSelectedRowStart );
		if ( pstrStartLine == NULL )
		{
			return( strSelectedText );
		}
		idxStartByte = ::CaretColumnToByteColumn( *pstrStartLine, idxSelectedColumnStart );
	}

	// 終了行のバイト位置を探す
	long		idxEndByte;
	CString*	pstrEndLine = m_pDoc->GetLine( idxSelectedRowEnd );
	{
		if ( pstrEndLine == NULL )
		{
			return( strSelectedText );
		}
		idxEndByte = ::CaretColumnToByteColumn( *pstrEndLine, idxSelectedColumnEnd );
		// 改行の削除する？
		// もし終了バイトが最後以後をさしていたら、次の行の頭へ
		if ( idxEndByte > pstrEndLine->GetLength() )
		{
			idxSelectedRowEnd++;
			idxSelectedColumnEnd = 0;
			idxEndByte = 0;
			pstrEndLine = m_pDoc->GetLine( idxSelectedRowEnd );
			if ( pstrEndLine == NULL )
			{
				return( strSelectedText );
			}
		}
	}

	if ( idxSelectedRowStart == idxSelectedRowEnd )
	{
	// １行内なら
		// SubStringして保存
		strSelectedText = pstrStartLine->Mid( idxStartByte, idxEndByte - idxStartByte );
	}
	else
	{
	// 複数行にわたるなら

		// 格納領域を確保
		char*	pCopyBuffer= NULL;
		{
			// 必要バイト数を計算
			long	nByte = 0;

			long	idxLine;
			for( idxLine=idxSelectedRowStart ; idxLine<=idxSelectedRowEnd ; idxLine++ )
			{
				nByte += m_pDoc->GetLine( idxLine )->GetLength() + strlen( m_pDoc->ReturnChar() );
			}
			pCopyBuffer = new char[ nByte+1 ];
		}

		// コピー
		{
			long	iOffset = 0;

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

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

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

			pCopyBuffer[ iOffset ] = 0x00;
		}
		strSelectedText = pCopyBuffer;

		delete [] pCopyBuffer;
	}

	return( strSelectedText );
}


/*-----------------------------------------------------------------------------
[名称]	選択中判定
[機能]	選択操作中かを判定する。
[戻値]	BOOL	選択判定 [-] (TRUE:選択、FALSE:非選択)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL	CSelection::IsSelected()
{
	if ( GetSelectedStartRow() == GetSelectedEndRow() )
	if ( GetSelectedStartColumn() == GetSelectedEndColumn() )
	{
		return( FALSE );
	}
	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	選択解除
[機能]	選択を解除する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void	CSelection::SetSelectedNutral()
{
	if ( m_pDoc != NULL )
	{
		SetSelectedStart(
			m_pDoc->GetCaretRow(),
			m_pDoc->GetCaretColumn()
		);
		SetSelectedEnd(
			m_pDoc->GetCaretRow(),
			m_pDoc->GetCaretColumn()
		);
	}
}


/*-----------------------------------------------------------------------------
[名称]	選択始端設定
[機能]	選択始端を設定する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void	CSelection::SetSelectedStart(
	long	idxRow,			// I  :始端行 [-] (-) :-
	long	idxColumn		// I  :始端カラム [-] (-) :-
)
{
	m_idxSelectedRowStart = min( idxRow, m_pDoc->GetLineCount()-1 );
	m_idxSelectedColumnStart = idxColumn;

}

/*-----------------------------------------------------------------------------
[名称]	選択終端設定
[機能]	選択終端を設定する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void	CSelection::SetSelectedEnd(
	long	idxRow,			// I  :終端行 [-] (-) :-
	long	idxColumn		// I  :終端カラム [-] (-) :-
)
{
	m_idxSelectedRowEnd = min( idxRow, m_pDoc->GetLineCount()-1 );
	m_idxSelectedColumnEnd = idxColumn;
}


/*-----------------------------------------------------------------------------
[名称]	選択行情報取得
[機能]	行ごとの選択カラム情報を取得する。
[戻値]	CArray<TSelectColumn, TSelectColumn&>*	選択情報 [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
CArray<TSelectColumn, TSelectColumn&>*	CSelection::GetSelectedLinez()
{
	m_atSelectColumnz.RemoveAll();

	int	idxStartRow = GetSelectedStartRow();
	int	idxEndRow = GetSelectedEndRow();

	if ( idxStartRow == idxEndRow )
	{
	// １行の場合
		TSelectColumn	tColumn;
		tColumn.idxStart = GetSelectedStartColumn();
		tColumn.idxEnd = GetSelectedEndColumn();
		m_atSelectColumnz.Add( tColumn );
	}
	else
	{
	// ２行以上の場合
		TSelectColumn	tColumn;

		// １行目
		tColumn.idxStart = GetSelectedStartColumn();
		tColumn.idxEnd = ::StringToColumn( *(m_pDoc->GetLine( idxStartRow )) );
		m_atSelectColumnz.Add( tColumn );

		int	idxRow;
		for( idxRow=idxStartRow+1 ; idxRow<idxEndRow ; idxRow++ )
		{
			tColumn.idxStart = 0;
			tColumn.idxEnd = ::StringToColumn( *(m_pDoc->GetLine( idxRow )) );
			m_atSelectColumnz.Add( tColumn );
		}

		// 最終行
		tColumn.idxStart = 0;
		tColumn.idxEnd = GetSelectedEndColumn();
		m_atSelectColumnz.Add( tColumn );
	}

	return( &m_atSelectColumnz );
}


/*-----------------------------------------------------------------------------
[名称]	選択行情報設定
[機能]	行ごとの選択カラム情報を設定する。
[戻値]	BOOL	処理結果 [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CSelection::SetSelectedLinez(
	int idxLine,				// I  :行 [-] (-) :-
	TSelectColumn& tSelect		// I  :行選択情報 [-] (-) :-
)
{
	if ( idxLine < m_atSelectColumnz.GetSize() )
	{
		m_atSelectColumnz.RemoveAt( idxLine );
		m_atSelectColumnz.InsertAt( idxLine, tSelect );

		// ノーマル選択のために、選択範囲末尾位置を変更する please! 行ごとの選択範囲変更I/Fを用意すべき
		{
			if ( idxLine == 0 )
			{
				SetSelectedStart( m_idxSelectedRowStart, tSelect.idxStart );
			}
			if ( idxLine == m_atSelectColumnz.GetSize()-1 )
			{
				SetSelectedEnd( m_idxSelectedRowStart+idxLine, tSelect.idxEnd );
			}
		}
		return( TRUE );
	}
	return( FALSE );
}


/*-----------------------------------------------------------------------------
[名称]	正規化
[機能]	選択情報を正規化する。
[戻値]	なし
[備考]	開始行が上にくるように‥‥。
-----------------------------------------------------------------------------*/
void CSelection::Normalize()
{
	BOOL	bSwap = FALSE;
	
	if ( m_idxSelectedRowStart > m_idxSelectedRowEnd )
	{
		bSwap = TRUE;
	}

	if ( m_idxSelectedRowStart == m_idxSelectedRowEnd )
	if ( m_idxSelectedColumnStart > m_idxSelectedColumnEnd )
	{
		bSwap = TRUE;
	}

	if ( bSwap )
	{
		int	iTmp;

		iTmp = m_idxSelectedRowStart;
		m_idxSelectedRowStart = m_idxSelectedRowEnd;
		m_idxSelectedRowEnd = iTmp;

		iTmp = m_idxSelectedColumnStart;
		m_idxSelectedColumnStart = m_idxSelectedColumnEnd;
		m_idxSelectedColumnEnd = iTmp;
	}
}

