#include "StdAfx.h"
#include "MsgBox.h"
#include "Token.h"
#include "UISkinLexer.h"
#include "Parser.h"

#include "UIManager.h"
#include "UIEvent.h"
#include "UIImage.h"
#include "UIContainer.h"
#include "FontAgent.h"
#include "Button.h"
#include "Label.h"
#include "EditBox.h"
#include "Application.h"

#include "BaseStage.h"
#include "ItemManager.h"

cMsgBox::cMsgBox( eUINodeType type )
: cUIWindow( type )
, mpLabel(0)
, mpEdit(0)
, mpYesButton(0)
, mpNoButton(0)
, mTextPosX(0)
, mTextPosY(0)
, mCaptionPosX(0)
, mCaptionPosY(0)
, mExtraData(0)
, mStartTime(0)
, mTotalTime(0)
, mText(0)
, mResultEvent( false )
, mTimePrint( false )
{
	mEventType = eMBEVENT_NONE;
	mSkinType = eSKIN_NONE;
	mModalType = eMSGBOX_MODAL;

	SetBackupVisible( false );
}

cMsgBox::~cMsgBox()
{
	mpEdit = 0;
	mpYesButton = 0;
	mpNoButton = 0;
	mpLabel = 0;
}

bool cMsgBox::InitWindow()
{
	cUIWindow::InitWindow();

	/// 화면 중앙에 출력
	int x = (int)(( GetScreenWidth() - GetAbsoluteRect().GetWidth() ) * 0.5f);
	int y = (int)(( GetScreenHeight() - GetAbsoluteRect().GetHeight() ) * 0.35f);

	SetRelativePos( cUIPos( x, y) );
	return true;
}

void cMsgBox::OnShow()
{
	if( mSkinType == eSKIN_EDIT )
		mpEdit->SetFocus();

	/// 화면 중앙에 출력
	int x = (int)(( GetScreenWidth() - GetAbsoluteRect().GetWidth() ) * 0.5f);
	int y = (int)(( GetScreenHeight() - GetAbsoluteRect().GetHeight() ) * 0.35f);
	SetRelativePos( cUIPos( x, y) );

	cUIWindow::OnShow();
}

/// 주의사항 : 
bool cMsgBox::OnCreate( cUINodeProperty* )
{
	/// 스킨타입에 따라 버튼 생성여부를 결정한다.
	switch( mSkinType )
	{
	case eSKIN_OK:
		{
			mpYesButton = new cButton;
			if( mpYesButton->CreateBySkinName( mOkButtonSkin, this, eMESSAGE_BUTTON_YES ) == false )
			{
				return false;
			}

			mpYesButton->SetText( UIMAN->GetUIText(2) );
		}
		break;
	case eSKIN_YESNO:
		{
			mpYesButton = new cButton;
			mpNoButton = new cButton;
			if( mpYesButton->CreateBySkinName( mYesButtonSkin, this, eMESSAGE_BUTTON_YES ) == false )
			{
				return false;
			}

			if( mpNoButton->CreateBySkinName( mNoButtonSkin, this, eMESSAGE_BUTTON_NO ) == false )
			{
				return false;
			}
		}
		break;
	case eSKIN_CANCEL:
		{
			mpNoButton = new cButton;
			if( mpNoButton->CreateBySkinName( mNoButtonSkin, this, eMESSAGE_BUTTON_NO ) == false )
			{
				return false;
			}
		}
		break;
	case eSKIN_EDIT:
		{
			mpYesButton = new cButton;
			mpNoButton = new cButton;
			mpEdit = new cEditBox;
			if( mpYesButton->CreateBySkinName( mYesButtonSkin, this, eMESSAGE_BUTTON_YES ) == false )
			{
				return false;
			}
			if( mpNoButton->CreateBySkinName( mNoButtonSkin, this, eMESSAGE_BUTTON_NO ) == false )
			{
				return false;
			}
			if( mpEdit->CreateBySkinName( mEditSkin, this, eMESSAGE_EDIT ) == false )
			{
				return false;
			}
		}
		break;
	}


	//// 라벨은 반드시 생성한다
	mpLabel = new cLabel;
	if( mpLabel->CreateBySkinName( "eMB_LABEL", this, eMESSAGE_LABEL ) == false )
	{
		assert( 0 && "failed to create label" );
		return false;
	}

	if( mpLabel )
		mpLabel->SetEnabled( false );

	SetExceptSnap( true );

	return true;
}

/// 주의사항 : 
bool cMsgBox::Create(cBaseStage* msgHandler, eMSGBox_Event eventtype, eBoxSkin_Type skintype, eMSGBox_Type boxtype, 
					 void* extraData, unsigned long totaltime, bool printTime, bool success )
{
	Hide();

	mExtraData = extraData;

	mMsgHandler = msgHandler;

	/// 메시지박스의 속성 세팅 
	mEventType = eventtype;
	mSkinType = skintype;
	mModalType = boxtype;

	/// 시간정보 세팅
	mTotalTime = totaltime;
	mResultEvent = success;
	mStartTime = THEAPP->GetWorldAccumTime();
	mTimePrint = printTime;

	/// 읽어들일 스킨 결정 
	cString skinname;
	switch( skintype )
	{
	case eSKIN_NONE:	skinname = "eMB_NONE";	break;
	case eSKIN_OK:		skinname = "eMB_OK";	break;
	case eSKIN_YESNO:	skinname = "eMB_YESNO";	break;
	case eSKIN_CANCEL:	skinname = "eMB_Cancel";break;
	case eSKIN_GAUGE:	break;
	case eSKIN_EDIT:	skinname = "eMB_EDIT";	break;
	}

	/// 메시지 박스 생성 ( 부모는 루트윈도우 )
	if( cUINode::CreateBySkinName( skinname, 0, 1 ) == false )
	{
		return false;
	}
	if( IsValid() == false )
	{
		return false;
	}
	return true;
}

/// 주의사항 : 
bool cMsgBox::SetSkin( const cUINodeSkin* pskin )
{
	if( pskin->IsKindof( eUINODE_MESSAGEBOX ) == false )
	{
		assert( 0 && "not messagebox skin type" );
		return false;
	}

	if( cUINode::SetSkin( pskin ) == false )
	{
		return false;
	}

	cMessageBoxSkin* p = (cMessageBoxSkin*)pskin;

	mCaptionRect = p->mCaptionRect; 

	if( mCaptionRect.GetWidth() < 0 || mCaptionRect.GetHeight() < 0 )
	{
		assert( 0 && "caption rect is 0" );
		return false;
	}

	mOkButtonSkin = p->mOkButtonSkin;
	mYesButtonSkin = p->mYesButtonSkin;
	mNoButtonSkin = p->mNoButtonSkin;
	mEditSkin = p->mEditSkin;


	cUISkin* pUISkin = UIMAN->GetSkin();
	if( !pskin )
	{
		assert(0);
		return false;
	}

	/// 스킨 네임 유효성 검사
	if( mOkButtonSkin && pUISkin->GetNodeSkin( mOkButtonSkin ) == 0 )
	{
		assert( 0 && "error skin name" );
		return false;
	}
	if( mYesButtonSkin && pUISkin->GetNodeSkin( mYesButtonSkin ) == 0 )
	{
		assert( 0 && "error skin name" );
		return false;
	}
	if( mNoButtonSkin && pUISkin->GetNodeSkin( mNoButtonSkin ) == 0 )
	{
		assert( 0 && "error skin name" );
		return false;
	}
	if( mEditSkin && pUISkin->GetNodeSkin( mEditSkin ) == 0 )
	{
		assert( 0 && "error skin name" );
		return false;
	}
	return true;
}

/// 주의사항 : 
bool cMsgBox::IsValid() const
{
	if( !mpImage )
	{
		assert( 0 && "invalid image" );
		return false;
	}

	if( cUINode::IsValid() == false )
	{
		return false;
	}
	return true;
}

/// 주의사항 : 
bool cMsgBox::HandleEvent( const cUIEvent& event )
{
	if( mEnabled == false || mVisible == false )
	{
		return mpParent->HandleEvent( event );
	}

	switch( event.mType )
	{
	case eUIEVENT_LBUTTON_DOWN:
	case eUIEVENT_LBUTTON_UP:
	case eUIEVENT_MOUSE_MOVE:
		{
			cUINode* pNode = this->GetNode( event.mPos );
			if( pNode && (pNode->GetType() == eUINODE_BUTTON || pNode->GetType() == eUINODE_EDITBOX ))
				pNode->HandleEvent( event );
			else
				cUIWindow::HandleEvent( event );
		}
		break;
	case eUIEVENT_KEY_UP:
	case eUIEVENT_KEY_DOWN:
		if( event.mCode == eKEY_RETURN || event.mCode == eKEY_ESCAPE )
		{
			cUIWindow::HandleEvent( event );
		}
		break;
	case eUIEVENT_COMMAND:
		{
			if( mMsgHandler )
				mMsgHandler->MsgBoxEventParser( mEventType, event.mID, mExtraData );

			UIMAN->DestroyMsgBox( this );
		}
		break;
	case eUIEVENT_GAME_COMMAND:
		if( event.mID == eMESSAGE_BUTTON_YES || event.mID == eMESSAGE_BUTTON_NO )
		{
			if( mMsgHandler )
				mMsgHandler->MsgBoxEventParser( mEventType, event.mID, mExtraData );

			UIMAN->DestroyMsgBox( this );
		}
		else if( event.mID == eMESSAGE_NOTDESTROY )
		{
			if( mMsgHandler )
				mMsgHandler->MsgBoxEventParser( mEventType, event.mID, mExtraData );
		}
		break;
	case eUIEVENT_EDITBOX_ENTER:
		{
			/// 엔터키를 누르면 확인되었음을 적용
			if( mMsgHandler )
				mMsgHandler->MsgBoxEventParser( mEventType, eMESSAGE_BUTTON_YES, mExtraData );

			UIMAN->DestroyMsgBox( this );
			UIMAN->ReleaseFocusedNode( mpEdit );
		}	
		break;
	default:
		cUIWindow::HandleEvent( event );
		break;
	}
	return true;
}

/// 주의사항 : 
void cMsgBox::UpdateRect()
{
	cUIWindow::UpdateRect();
	/// 텍스트 좌표 업데이트 
	UpdateText();
}

void cMsgBox::UpdateSkin()
{
	cUIWindow::UpdateSkin();

	/// 화면 중앙에 출력
	int x = (int)(( GetScreenWidth() - GetAbsoluteRect().GetWidth() ) * 0.5f);
	int y = (int)(( GetScreenHeight() - GetAbsoluteRect().GetHeight() ) * 0.35f);

	SetRelativePos( cUIPos( x, y) );
}

void cMsgBox::OnProcess( unsigned long deltaTime, unsigned long accumTime )
{
	cUIWindow::OnProcess( deltaTime, accumTime );

	if( mTotalTime <= 0 )
		return;

	/// 시간 체크
	if( accumTime - mStartTime > mTotalTime )
	{
		/// 자동 거절
		UIMAN->SendEventToMsgbox( mResultEvent, mEventType );
		mStartTime = accumTime;
	}
	else if( mTimePrint )
	{
		unsigned long elased = (mTotalTime - (accumTime - mStartTime))/1000;
		unsigned int s = elased % 60;

		cStringT str;
		str.Format( mText, s );
		SetMessage( (LPCTSTR)str.Cstr() );
	}
}

/// 주의사항 : 
void cMsgBox::OnRender( cUIFontItemKeeper* pKeeper )
{
	/// 문자열 렌더링 
	pKeeper->AddFontItem( cFontAgent::eFont_UI, const_cast<LPTSTR>(mCaptionText.Cstr()), mCaptionPosX, mCaptionPosY, eCOLOR_WHITE );

	/// 자식들 업데이트 
	cUIWindow::OnRender(pKeeper);
}

void cMsgBox::OnKeyDown( eKeyCode code )
{
	/// 확인용 메시지 박스면, 엔터키를 누르면 자동으로 확인키가 눌린다
	if( mSkinType == eSKIN_OK && code == eKEY_RETURN )
	{
		UIMAN->DestroyMsgBox( this );

		if( mMsgHandler )
			mMsgHandler->MsgBoxEventParser( mEventType, (mResultEvent) ? eMESSAGE_BUTTON_YES : eMESSAGE_BUTTON_NO, mExtraData );
	}
}

/// 주의사항 :
void cMsgBox::SetText( LPCTSTR text, LPCTSTR caption )
{
	/// 텍스트 설정 
	mCaptionText = caption;
	mText = text;
	SetMessage( text );
}

///
void cMsgBox::SetMessage( LPCTSTR text )
{
	if( mpLabel )
		mpLabel->SetText( text );

	UpdateText();
}

/// 주의사항 : 텍스트 좌표 업데이트 
void cMsgBox::UpdateText()
{
	/// 텍스트가 뿌려질 위치 계산 
	cUIRect rc = GetAbsoluteRect();
	
	/// 캡션텍스트 위치 조정 
	mCaptionPosX = rc.mLeft + (rc.GetWidth() - FONTAGENT->GetTextExtent( cFontAgent::eFont_UI_BOLD, mCaptionText.Cstr(), mCaptionText.GetLength() ) ) / 2;
	mCaptionPosY = rc.mTop + ( mCaptionRect.GetHeight() - FONTAGENT->GetTextHeight(cFontAgent::eFont_UI_BOLD) ) / 2;
}

///
LPCTSTR cMsgBox::GetEditText() const
{
	if( mpEdit )
	{
		return mpEdit->GetText();
	}
	else
	{
		assert(0);
	}
	return 0;
}

///
unsigned int cMsgBox::GetLength() const
{
	if( mpEdit )
	{
		return mpEdit->GetLength();
	}
	else
	{
		assert(0);
	}
	return 0;
}

void cMsgBox::SetMaxLength( int length )
{
	if( mpEdit )
		mpEdit->SetMaxEditLength( length );
}

//////////////////////////////////////////////////////////////////////
cMessageBoxSkin::cMessageBoxSkin( eUINodeType type )
: cUINodeSkin( type )
, mMoveable( true )
{
	mCaptionRect.Set( 0, 0, 0, 0 );
}

cMessageBoxSkin::~cMessageBoxSkin()
{

}

/// 주의사항 : 스크립트 파일을 읽어들여서 값을 세팅한다
bool cMessageBoxSkin::Load( cParser& parser )
{
	if( parser.ExpectTokenString( "{" ) == false )
		return false;

	cToken token;
	cLexer* lexer = parser.GetLexer();

	/// 그다음토큰을 계속 검사
	while( lexer->GetNextToken( &token ) )
	{
		if( token == "}" )
			break;

		switch( token.mType )
		{
		case eTOKEN_CAPTIONXY:
			{
				mCaptionRect.mLeft = parser.ParseInt();
				mCaptionRect.mTop = parser.ParseInt();
			}
			break;
		case eTOKEN_CAPTIONWH:
			{
				mCaptionRect.mRight = mCaptionRect.mLeft + parser.ParseInt();
				mCaptionRect.mBottom = mCaptionRect.mTop + parser.ParseInt();
			}
			break;
		case eTOKEN_EDITSKIN:
			{
				mEditSkin = parser.ParseString();
			}
			break;
		case eTOKEN_OKBUTTONSKIN:
			{
				mOkButtonSkin = parser.ParseString();
			}
			break;
		case eTOKEN_YESBUTTONSKIN:
			{
				mYesButtonSkin = parser.ParseString();
			}
			break;
		case eTOKEN_NOBUTTONSKIN:
			{
				mNoButtonSkin = parser.ParseString();
			}
			break;
		case eTOKEN_MOVABLE:
			{
				lexer->GetNextToken( &token );

				if( token.mType == eTOKEN_TRUE )
				{
					mMoveable = true;
				}
				else if( token.mType == eTOKEN_FALSE )
				{
					mMoveable = false;
				}
				else
				{
					assert( 0 && "invalid token" );
					return false;
				}
			}
			break;
		default:
			if( cUINodeSkin::ParseLine( parser, token ) == false )
			{
				return false;
			}
			break;
		}
	}
	return true;
}


