#include "Stdafx.h"
#include "TextCtrl.h"

#include "FontAgent.h"
#include "UIImage.h"

cTextCtrl::cTextCtrl( eUINodeType type )
: cUIWindow( type )
, mLine(0)
, mLineWidth(0)
, mMaxTextWidth(0)
, mTotalMaxNum(0)
, mDelCount(0)
{
	mTextQueue.Reserve( 60 );
}

cTextCtrl::~cTextCtrl()
{
	Clear();
}

/// 주의사항 : 전체를 지운다
void cTextCtrl::Clear()
{
	sRowTextData* p = 0;
	for( unsigned int i = 0; i < mTextQueue.GetSize(); ++i )
	{
		p = (sRowTextData*)mTextQueue[i];
		if( p )
		{
			for( unsigned int b = 0; b < p->mColumes.GetSize(); ++b )
			{
				SAFE_DELETE( p->mColumes[b] );
			}
			p->mColumes.Clear();
			SAFE_DELETE(p);
		}
	}
	mTextQueue.Clear();

	mLine = 0;
	mLineWidth = 0;
	mDelCount = 0;
}

///
void cTextCtrl::AddEmptyRow( unsigned int line )
{
	mLineWidth = 0;

	/// 공백라인 추가
	for( unsigned int i = 0; i < line; ++i )
		InsertRow( _T(""), mDefaultColor, 0, 0 );
}


/// 새로운 라인 추가
void cTextCtrl::AddNewRow( LPCTSTR str, unsigned long color, unsigned long itemIndex, unsigned int slotIndex )
{
	if( !str ) return;

	/// 문자열 폭 구하기
	unsigned int len = ::_tcslen( str );
	unsigned int width = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str, len );

	/// 검사한 폭과 길이
	unsigned int cutWidth = 0;
	unsigned int cutlen = 0;
	unsigned int startIndex = 0;
	mLineWidth = 0;

	/// 삽입용 문자열
	TCHAR text[256] = {0,};
	LPTSTR newtext = text;
	::ZeroMemory( newtext, 256 );

	/// 사이즈보다 크면 잘라낸다.
	while( cutlen < len )
	{
		/// 현재까지 검사한 문자의 폭 구하기
		cutlen++;
		cutWidth = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str + startIndex, cutlen );

		/// 현재 문자검사를 한다
		TCHAR temp[3] = {0,};
		::_tcsncpy( temp, &str[startIndex + cutlen], 2 );

		/// 엔터부호가 있으면 줄넘김
		if( ::_tcsncmp( temp, _T("\\n"), 2 ) == 0 )
		{
			/// 삽입
			Sstrncpy( newtext, 256, str + startIndex, cutlen );
			InsertRow( newtext, color, itemIndex, slotIndex );

			///
			width -= cutWidth; 
			startIndex += cutlen + 2;
			len -= (cutlen + 2);
			cutWidth = 0;
			cutlen = 0;
		}
		/// 현재까지의 길이가 맥스를 넘기면 
		else if( cutlen > 0 && cutWidth > mMaxTextWidth )	
		{
			if( startIndex + cutlen > 1 )
			{
				/// UNICODE 니까 무조건 길이를 1씩 
				int minusWidth = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str + startIndex + cutlen - 1, 1 );
				cutWidth -= minusWidth;
				cutlen -= 1;
			}

			Sstrncpy( newtext, 256, str + startIndex, cutlen );
			InsertRow( newtext, color, itemIndex, slotIndex );

			mLineWidth += width;

			///
			width -= cutWidth;
			startIndex += cutlen;
			len -= cutlen;
			cutWidth = 0;
			cutlen = 0;
		}
	}

	if( len > 0 )
	{
		Sstrncpy( newtext, 256, str + startIndex, len );
		InsertRow( newtext, color, itemIndex, slotIndex );

		mLineWidth = width;
	}
	else if( len < 0 )
	{
		assert(0);
	}
}


/// 기존라인에 연결하여 추가
void cTextCtrl::AddPasteRow( bool autoNewline, LPCTSTR str, unsigned long color, unsigned long itemIndex, unsigned int slotIndex )
{
	if( !str ) return;

	unsigned int len = ::_tcslen( str );
	if( len == 0 )
		return;

	/// 기존 라인에 붙여 출력하기
	if( mLine > 0 )
	{
		mLine--;
	}

	/// 문자열 폭 구하기
	unsigned int width = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str, len );

	/// 검사한 폭과 길이
	unsigned int cutWidth = 0;
	unsigned int cutlen = 0;

	/// 문자열 시작 인덱스 
	int startIndex = 0;

	/// 삽입용 문자열
	LPTSTR newtext = new TCHAR[256];
	::ZeroMemory( newtext, 256 );

	while( width + mLineWidth > mMaxTextWidth )
	{
		if( cutWidth + mLineWidth < mMaxTextWidth )	
		{
			cutlen++;

			/// 현재까지 검사한 문자의 폭 구하기
			cutWidth = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str + startIndex, cutlen );
		}
		else if( cutlen > 0 )
		{
			if( /*cutlen > 0 &&*/ cutWidth + mLineWidth > mMaxTextWidth )
			{
				/// UNICODE 니까 무조건 길이를 1씩 
				int minusWidth = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str + startIndex + cutlen - 1, 1 );
				cutWidth -= minusWidth;
				cutlen -= 1;
			}

			Sstrncpy( newtext, 256, str + startIndex, cutlen );
			
			/// 기능성 텍스트 아니면 그냥 삽입
			InsertColumn( autoNewline, newtext, color, itemIndex, slotIndex );
			mLineWidth = 0;

			///
			width -= cutWidth;
			startIndex += cutlen;
			len -= cutlen;
			cutWidth = 0;
			cutlen = 0;
		}
	}

	if( len > 0 )
	{
		Sstrncpy( newtext, 256, str + startIndex, len );

		if( mLineWidth == 0 && autoNewline == false )
			InsertRow( newtext, color, itemIndex, slotIndex );
		else
			InsertColumn( autoNewline, newtext, color, itemIndex, slotIndex );

		mLineWidth += width;
	}
	else if( len < 0 )
	{
		assert(0);
	}

	SAFE_DELETE_ARRAY( newtext );
}

void cTextCtrl::AddPasteRowInven( LPCTSTR str, unsigned long color, sInventory inventory )
{
	if( !str ) return;

	/// 기존 라인에 붙여 출력하기
	if( mLine > 0 )
	{
		mLine--;
	}

	unsigned int len = ::_tcslen( str );

	/// 문자열 폭 구하기
	unsigned int width = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str, len );

	/// 검사한 폭과 길이
	unsigned int cutWidth = 0;
	unsigned int cutlen = 0;

	/// 문자열 시작 인덱스 
	int startIndex = 0;

	/// 삽입용 문자열
	LPTSTR newtext = new TCHAR[256];
	::ZeroMemory( newtext, 256 );

	while( width + mLineWidth > mMaxTextWidth )
	{
		if( cutWidth + mLineWidth < mMaxTextWidth )	
		{
			cutlen++;

			/// 현재까지 검사한 문자의 폭 구하기
			cutWidth = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str + startIndex, cutlen );
		}
		else if( cutlen > 0 )
		{
			if( cutWidth + mLineWidth > mMaxTextWidth )
			{
				/// UNICODE 니까 무조건 길이를 1씩 
				int minusWidth = FONTAGENT->GetTextExtent( cFontAgent::eFont_System, str + startIndex + cutlen - 1, 1 );
				cutWidth -= minusWidth;
				cutlen -= 1;
			}

			Sstrncpy( newtext, 256, str + startIndex, cutlen );

			InsertColumnInven( newtext, color, inventory );
			mLineWidth = 0;

			///
			width -= cutWidth;
			startIndex += cutlen;
			len -= cutlen;
			cutWidth = 0;
			cutlen = 0;
		}
	}

	if( len > 0 )
	{
		Sstrncpy( newtext, 256, str + startIndex, len );

		if( mLineWidth == 0 )
			InsertRowInven( newtext, color, inventory );
		else
			InsertColumnInven( newtext, color, inventory );

		mLineWidth += width;
	}
	else if( len < 0 )
	{
		assert(0);
	}

	SAFE_DELETE_ARRAY( newtext );
}

///
void cTextCtrl::InsertRow( LPCTSTR str, unsigned long color, unsigned long itemIndex, unsigned int slotIndex )
{
	// 데이터 채우기
	sTextData* data = new sTextData;
	data->mLine = mLine;
	data->mColor = color;
	data->mText = str;
	data->mItemIndex = itemIndex;
	data->mSlotIndex = slotIndex;

	/// 라인정보를 삽입
	sRowTextData* rowData = new sRowTextData;
	rowData->mColumes.PushBack( data );

	/// 실제 열에 삽입
	mTextQueue.PushBack( rowData );

	/// 최대 갯수보다 크면
	if( mLine >= mTotalMaxNum )
	{
		sRowTextData* p = (sRowTextData*)mTextQueue.Front();
		if( p )
		{
			for( unsigned int b = 0; b < p->mColumes.GetSize(); ++b )
			{
				SAFE_DELETE( p->mColumes[b] );
			}
			p->mColumes.Clear();
	
			SAFE_DELETE(p);
		}		

		mTextQueue.PopFront();

		/// 지워낸갯수 증가 
		mDelCount++;
	}

	/// 다음 라인을 위해 증가
	mLine++;
}


void cTextCtrl::InsertColumn( bool autoNewline, LPCTSTR str, unsigned long color, unsigned long itemIndex, unsigned int slotIndex )
{
	/// 기존라인에 그냥 붙일경우, 마지막라인을 가져와서 붙인다
	if( autoNewline == false )
	{
		if( mTextQueue.GetSize() == 0 )
		{
			assert(0);
			return;
		}

		int linenum = mLine;
		if( mLine >= mTextQueue.GetSize() )
		{
			linenum = mTextQueue.GetSize() - 1;
		}

		sTextData* data = new sTextData;
		data->mLine = mLine;
		data->mColor = color;
		data->mText = str;
		data->mItemIndex = itemIndex;
		data->mSlotIndex = slotIndex;
		
		sRowTextData* pRow = (sRowTextData*)mTextQueue[linenum];
		pRow->mColumes.PushBack( data );

		mLine++;
	}
	/// 자동으로 새로운 라인으로 넣어야 하는경우 ( npc 대화.. )
	else
	{
		if( mLine >= mTextQueue.GetSize() )
		{
			InsertRow( str, color, 0, 0 );
			return;
		}

		sTextData* data = new sTextData;
		data->mLine = mLine;
		data->mColor = color;
		data->mText = str;
		data->mItemIndex = 0;
		data->mSlotIndex = UINT_MAX;

		sRowTextData* pRow = (sRowTextData*)mTextQueue[mLine];
		pRow->mColumes.PushBack( data );

		mLine++;
	}
}

void cTextCtrl::InsertRowInven( LPCTSTR str, unsigned long color, sInventory inventory )
{
	sInvenData* data = new sInvenData;
	data->mLine = mLine;
	data->mColor = color;
	data->mText = str;
	data->mItemIndex = 0;
	data->mSlotIndex = UINT_MAX;
	data->mUseInven = true;
	data->mInventory = inventory;

	/// 라인정보를 삽입
	sRowTextData* rowData = new sRowTextData;
	rowData->mColumes.PushBack( data );

	/// 실제 열에 삽입
	mTextQueue.PushBack( rowData );

	/// 최대 갯수보다 크면
	if( mLine >= mTotalMaxNum )
	{
		sRowTextData* p = (sRowTextData*)mTextQueue.Front();
		if( p )
		{
			p->mColumes.Clear();
			SAFE_DELETE(p);
		}		

		mTextQueue.PopFront();

		/// 지워낸갯수 증가 
		mDelCount++;
	}

	/// 다음 라인을 위해 증가
	mLine++;
}

void cTextCtrl::InsertColumnInven( LPCTSTR str, unsigned long color, sInventory inventory )
{
	if( mTextQueue.GetSize() == 0 )
	{
		assert(0);
		return;
	}

	int linenum = mLine;
	if( mLine >= mTextQueue.GetSize() )
	{
		linenum = mTextQueue.GetSize() - 1;
	}

	sInvenData* data = new sInvenData;
	data->mLine = mLine;
	data->mColor = color;
	data->mText = str;
	data->mItemIndex = 0;
	data->mSlotIndex = UINT_MAX;
	data->mUseInven = true;
	data->mInventory = inventory;

	sRowTextData* pRow = (sRowTextData*)mTextQueue[linenum];
	pRow->mColumes.PushBack( data );

	mLine++;
}

///
sRowTextData* cTextCtrl::GetRowData( unsigned int rowIdx )
{
	if( rowIdx >= mTextQueue.GetSize() )
		return 0;

	return (sRowTextData*)mTextQueue[rowIdx];
}


/// NPC 대사등의 특별한 컬럼 
//void cTextCtrl::InsertFuncColumn( LPCTSTR str, unsigned long color )
//{
//	if( mLine >= mTextQueue.GetSize() )
//	{
//		InsertRow( str, color, 0, 0 );
//		return;
//	}
//
//	sTextData data;
//	data.mLine = mLine;
//	data.mColor = color;
//	data.mText = str;
//	data.mItemIndex = 0;
//	data.mSlotIndex = UINT_MAX;
//
//	sRowTextData* pRow = (sRowTextData*)mTextQueue[mLine];
//	pRow->mColumes.PushBack( data );
//
//	mLine++;
//}

///
//void cTextCtrl::InsertColumn( LPCTSTR str, unsigned long color, unsigned long itemIndex, unsigned int slotIndex )
//{
//	if( mTextQueue.GetSize() == 0 )
//	{
//		assert(0);
//		return;
//	}
//
//	int linenum = mLine;
//	if( mLine >= mTextQueue.GetSize() )
//	{
//		linenum = mTextQueue.GetSize() - 1;
//	}
//	
//	sTextData data;
//	data.mLine = mLine;
//	data.mColor = color;
//	data.mText = str;
//	data.mItemIndex = itemIndex;
//	data.mSlotIndex = slotIndex;
//
//	sRowTextData* pRow = (sRowTextData*)mTextQueue[linenum];
//	pRow->mColumes.PushBack( data );
//
//	mLine++;
//}
