////////////////////////////////////////////////////////////////////
// LinePseudoPtr.h
// CLinePseudoPtrクラスのインプリメンテーション
// T_LineDataに対する疑似ポインタ。文字列に対するものと、色情報に対するものとを定義
////////////////////////////////////////////////////////////////////

#if !defined( LINEPSEUDOPTR_H_INCLUDED_ )
#define LINEPSEUDOPTR_H_INCLUDED_

#include "../LineData.h"
#include "../TaEdit_std.h"

namespace NLangExt {

class CLinePseudoPtr
{
public:
	CLinePseudoPtr() : pData( NULL ){};
	CLinePseudoPtr( T_LineData *pArgData ) :
		pData( pArgData ), CurLineItr( pArgData->begin() ), CurCharPos( 0 )
	{
		// 一行以上はデータが存在すること
		assert( pArgData && pArgData->begin() != pArgData->end() );
	};

	CLinePseudoPtr( const CLinePseudoPtr& r ) :
		pData( r.pData ), CurLineItr( r.CurLineItr ), CurCharPos( r.CurCharPos )
	{};

	// 位置を設定
	void SetPos( T_CurPos c )
	{
		assert( this && pData );
		CurLineItr = pData->begin() + c.GetLine();
		CurCharPos = c.GetCPos();
	};

	// 末端に設定
	void SetEnd()
	{
		assert( this && pData );
		CurLineItr = pData->begin() + ( pData->size() - 1 );
		CurCharPos = CurLineItr->length();
	};

	// 比較
	bool operator ==( const CLinePseudoPtr &r ) const
	{
		assert( this && pData );
		assert( pData == r.pData );
		return CurLineItr == r.CurLineItr && CurCharPos == r.CurCharPos;
	};
	bool operator <( const CLinePseudoPtr &r ) const
	{
		assert( this && pData );
		assert( pData == r.pData );
		if ( CurLineItr < r.CurLineItr )
			return true;
		if ( CurLineItr > r.CurLineItr )
			return false;
		if ( CurCharPos < r.CurCharPos )
			return true;
		return false;
	};
	bool operator >( const CLinePseudoPtr &r ) const
	{
		assert( this && pData );
		assert( pData == r.pData );
		return !( this->operator ==( r ) ) && !( this->operator <( r ) );
	};

	// 代入
	const CLinePseudoPtr& operator =( const CLinePseudoPtr &r )
	{
		pData = r.pData;
		CurLineItr = r.CurLineItr;
		CurCharPos = r.CurCharPos;
		return (*this);
	};

	// デクリメント
	const CLinePseudoPtr& operator --()
	{
		assert( this && NULL != pData );
		assert( pData->begin() != CurLineItr || CurCharPos > 0 );
		if ( 0 == CurCharPos ) {
			--CurLineItr;
			CurCharPos = CurLineItr->length();
		}
		else {
			--CurCharPos;
		}
		return (*this);
	};

	// インクリメント
	const CLinePseudoPtr& operator ++()
	{
		assert( this && NULL != pData );
		assert( pData->begin() + ( pData->size() - 1 ) != CurLineItr ||
			CurCharPos < CurLineItr->length() );
		if ( CurCharPos == CurLineItr->length() ) {
			CurCharPos = 0;
			++CurLineItr;
		}
		else {
			++CurCharPos;
		}
		return (*this);
	};

protected:

	// データ
	T_LineData *pData;

	// 現在ポイントしている位置
	T_LineDataItr CurLineItr;
	int CurCharPos;
};

// テキスト
class CLinePseudoPtr_txt : public CLinePseudoPtr
{
public:
	CLinePseudoPtr_txt() : CLinePseudoPtr(){};
	CLinePseudoPtr_txt( T_LineData *pArgData ) : CLinePseudoPtr( pArgData ) {};
	virtual ~CLinePseudoPtr_txt(){};

	// 参照
	wchar_t operator *() const
	{
		if ( pData->begin() + ( pData->size() - 1 ) == CurLineItr &&
			CurCharPos == CurLineItr->length() )
			return NULL;	// 文字列の末端
		if ( CurCharPos == CurLineItr->length() )
			return L'\n';	// 行の末尾
		return (*CurLineItr)[ CurCharPos ].moji;
	};
};

// 色情報
class CLinePseudoPtr_clr : public CLinePseudoPtr
{
public:
	// 色情報を代入演算子によって書き換えるためのオブジェクト
	class CLinePseudoPtr_clr_work
	{
	public:
		CLinePseudoPtr_clr_work( T_LineDataItr argItr, int argCpos ) :
			itr( argItr ), cpos( argCpos ){};

		// 参照
		operator unsigned char() const
		{
			return itr->getIro( cpos );
		};

		// 代入
		unsigned char operator =( unsigned char c )
		{
			itr->setIro( cpos, c );
			return c;
		};
	private:
		T_LineDataItr itr;
		int cpos;
	};

	CLinePseudoPtr_clr() : CLinePseudoPtr(){};
	CLinePseudoPtr_clr( T_LineData *pArgData ) : CLinePseudoPtr( pArgData ) {};
	virtual ~CLinePseudoPtr_clr(){};


	// 参照
	CLinePseudoPtr_clr_work operator *()
	{
		// 色情報は、バッファの領域外の参照を許さない
		assert( pData->begin() + ( pData->size() - 1 ) != CurLineItr ||
			CurCharPos < CurLineItr->length() );
		return CLinePseudoPtr_clr_work( CurLineItr, CurCharPos );
	};
};

}; // namespace NLangExt

#endif // LINEPSEUDOPTR_H_INCLUDED_
