#include "StdAfx.h"
#include "UIManager.h"
#include "UINode.h"
#include "UIRootNode.h"
#include "MsgBox.h"
#include "TipWindow.h"
#include "DragWindow.h"

#include "UIIDList.h"
#include "UIText.h"
#include "InputSystem.h"
#include "StageManager.h"

#include "UIImageFont.h"
#include "Icon.h"
#include "UIFuncText.h"
#include "UINpcTelling.h"
#include "UIRoundGauge.h"

#include "ItemManager.h"

#include "ItemTipWindow.h"
#include "SkillTipWindow.h"
#include "BuffToolTipWindow.h"
#include "SimpleTipWindow.h"

#include "Page.h"
#include "PartyManager.h"

#include "Npc_Common.h"
#include "ObjectManager.h"
#include "Hero.h"

#include "GameUIManager.h"

cUIManager* cUIManager::mpSingleton = 0;

cUIManager::cUIManager()
: mMousePos(0, 0)
{
	assert( mpSingleton == 0 && "bad singleton!" );
	mpSingleton = this;

	for( unsigned int i = 0; i < eStage_Max; ++i )
	{
		mpStageRootNode[i] = new cUIRootNode;
	}

	mpRootNode = 0;
	mpSkinText = 0;
	mpIDList = 0;
	mpSkin = 0;
	mpProperty = 0;
	mpCaptureNode = 0;
	mpHoveredNode = 0;
	mpFocusedNode = 0;
	mpModalMsgBox = 0;
	mTipWindow = 0;
	mpDragWindow = 0;
	mpNpcBackWindow = 0;
	mChatItemTipWindow = 0;

	/// Npc
	mpNpcText = 0;
	mNpcFuncType = NPC_FUNC_NULL;
}

cUIManager::~cUIManager()
{
	SAFE_DELETE( mpNpcText );
	SAFE_DELETE( mpSkin );
	SAFE_DELETE( mpSkinText );
	SAFE_DELETE( mpProperty );
	SAFE_DELETE( mpIDList );

	/// 이미지 폰트
	{
		cImageFontMap::cIterator i = mImageFontMap.Begin();
		cImageFontMap::cIterator iend = mImageFontMap.End();

		for( ; i != iend; ++i )
		{
			delete (cUIImageFont*)(i->mSecond);
		}
	}

	/// 아이콘
	{
		cIconParamMap::cIterator i = mIconParamMap.Begin();
		cIconParamMap::cIterator iend = mIconParamMap.End();

		for( ; i != iend; ++i )
		{
			delete (cIconParam*)(i->mSecond);
		}
	}

	/// NPC
	{
		cNpcTellingMap::cIterator i = mNpcTellingMap.Begin();
		cNpcTellingMap::cIterator iend = mNpcTellingMap.End();

		for( ; i != iend; ++i )
		{
			delete (cUINpcTelling*)(i->mSecond);
		}
	}

	/// page
	{
		cPageMap::cIterator i = mPageMap.Begin();
		cPageMap::cIterator end = mPageMap.End();

		for( ; i != end; ++i )
		{
			delete (cPage*)(i->mSecond);
		}
		mPageMap.Clear();
	}

	/// scene
	{
		cSceneMap::cIterator i = mSceneMap.Begin();
		cSceneMap::cIterator end = mSceneMap.End();

		for( ; i != end; ++i )
		{
			delete (sSceneData*)(i->mSecond);
		}
		mSceneMap.Clear();
	}

	for( unsigned int i = 0; i < eStage_Max; ++i )
	{
		SAFE_DELETE( mpStageRootNode[i] );
	}

	/// 메세지 박스
	mMsgBoxList.Clear();

	///
	mOtherClickList.Clear();

	mpModalMsgBox = 0;
	mpSingleton = 0;
}

/// 주의사항 : 
bool cUIManager::InitSkin( const cString& pathName )
{
	mpIDList = new cUIIDList;
	if( !mpIDList )
	{
		assert(0 && "mpIDList not create!" );
		return false;
	}

	mpProperty = new cUIProperty;
	if( !mpProperty )
	{
		assert(0 && "mpProperty not create!" );
		return false;
	}

	mpSkinText = new cUIText;
	if( !mpSkinText )
	{
		assert(0 && "mpSkinText not create!" );
		return false;
	}

	mpSkin = new cUISkin;
	if( !mpSkin )
	{
		assert(0 && "mpskin not create!" );
		return false;
	}

	if( LoadIDList( "./Script/Interface/List_ID.txt" ) == false )
	{
		return false;
	}

	if( LoadProperty( "./Script/Interface/List_Property.txt" ) == false )
	{
		return false;
	}

	if( LoadSkinText( "./Script/Language/InterfaceMsg.txt" ) == false )
	{
		return false;
	}

	if( LoadSkin( pathName ) == false )
	{
		return false;
	}

	return true;
}

/// 주의사항 :
void cUIManager::Reset()
{
	ReleaseEventNode();
	ClearFocusedNode();

	if( mTipWindow )
		HideTip();

	if( mChatItemTipWindow && mChatItemTipWindow->IsVisible() )
		mChatItemTipWindow->Hide();

	if( mpDragWindow )
		mpDragWindow->Hide();

	if( IsShowNpcBack() == true )
		HideNpcBack();

	/// 데이터 초기화 
	mNpcFuncType = NPC_FUNC_NULL;

	mFrontIdGen.RestoreAll();
	mApplyFrontMap.Clear();
}

/// 주의사항 :
bool cUIManager::LoadIDList( const cString& pathName )
{
	/// 스킨 로딩 
	if( mpIDList->Load( pathName ) == false )
	{
		assert( 0 && "failed to load idlist" );
		return false;
	}
	return true;
}

/// 주의사항 : 
bool cUIManager::LoadSkin( const cString& pathName )
{
	/// 스킨 로딩 
	if( mpSkin->Load( pathName ) == false )
	{
		assert( 0 && "failed to load ui skin" );
		return false;
	}
	return true;
}

bool cUIManager::LoadProperty( const cString& pathName )
{
	/// 속성 로딩
	if( mpProperty->Load( pathName ) == false )
	{
		assert( 0 && "failed to load ui property" );
		return false;
	}
	return true;
}

/// 주의사항 : 
bool cUIManager::LoadSkinText( const cString& pathName )
{
	if( mpSkinText->Load( pathName ) == false )
	{
		assert( 0 && "failed to load skin text" );
		return false;
	}
	return true;
}

///
bool cUIManager::ReloadSkin( const cString& pathName )
{
	/// 스킨 로딩 
	if( mpSkin->Reload( pathName ) == false )
	{
		assert( 0 && "failed to Reload ui skin" );
		return false;
	}
	return true;
}

/// 주의사항 : 
void cUIManager::ChangeSkin( const cString& pathName )
{
	if( ReloadSkin( pathName ) == false )
	{
		assert( 0 && "failed to Reload ui skin" );
		return;
	}

	mpRootNode->UpdateSkin();
}

/// 주의사항 : 
void cUIManager::Process( unsigned long deltaTime, unsigned long accumTime )
{
	if( !mDestroyMsgBoxList.IsEmpty() )
	{
		cDestroyMsgBoxList::cIterator i = mDestroyMsgBoxList.Begin();
		cDestroyMsgBoxList::cIterator end = mDestroyMsgBoxList.End();

		for( ; i != end; ++i )
		{
			cMsgBox* pbox = (cMsgBox*)(*i);
			GetRootNode()->RemoveChildComplete( pbox );
		}
		mDestroyMsgBoxList.Clear();
	}

	if( mApplyFrontMap.IsEmpty() == false )
	{
		cApplyFrontMap::cIterator i = mApplyFrontMap.Begin();
		cApplyFrontMap::cIterator end = mApplyFrontMap.End();
			for( ; i != end; ++i )
		{
			cUINode* node = (cUINode*)(*i).mSecond;
			ApplyFrontNode( node );
		}

		mFrontIdGen.RestoreAll();
		mApplyFrontMap.Clear();
	}

	mpRootNode->OnProcess( deltaTime, accumTime );
}

/// 주의사항 : 
void cUIManager::Render()
{
	mpRootNode->OnRender();
}

bool cUIManager::SetModal( cUIWindow* window )
{
	mMsgBoxList.PushBack( window );

	int index = mMsgBoxList.GetSize();
	if( index > 1 )
	{
		cUIRect rc = window->GetAbsoluteRect();
		window->SetRelativePos( cUIPos(rc.mLeft + (index*3), rc.mTop + (index*3)) );
	}

	/// 적용
	ReleaseEventNode();
	ClearFocusedNode();

	mpModalMsgBox = window;
	mpModalMsgBox->ShowTop();
	return true;
}

/// 메시지박스 생성
bool cUIManager::CreateModal(eSTAGE handlerIndex, eMSGBox_Event eventtype, LPCTSTR text, LPCTSTR captiontext, eBoxSkin_Type skintype, 
							 void* extraData, unsigned long totaltime, bool printTime, bool success, unsigned int maxLen )
{
	cBaseStage* msgHandler = STAGEMAN->GetStage( handlerIndex );
	cMsgBox* pnewbox = new cMsgBox;
	
	if( pnewbox->Create( msgHandler, eventtype, skintype, eMSGBOX_MODAL, extraData, totaltime, printTime, success ) == false )
	{
		assert( 0 && "failed to create modal msgbox" );
		delete pnewbox;
		return false;
	}

	pnewbox->SetMaxLength( maxLen );
	pnewbox->SetText( text, captiontext );
		
    mMsgBoxList.PushBack( pnewbox );

	int index = mMsgBoxList.GetSize();
	if( index > 1 )
	{
		cUIRect rc = pnewbox->GetAbsoluteRect();
		pnewbox->SetRelativePos( cUIPos(rc.mLeft + (index*3), rc.mTop + (index*3)) );
	}

	/// 적용
	ReleaseEventNode();
	ClearFocusedNode();

	mpModalMsgBox = pnewbox;
	mpModalMsgBox->ShowTop();
	return true;
}

/// 일반 모달 윈도우 닫기
void cUIManager::ReleaseModal( cUIWindow* window )
{
	ClearFocusedNode();
	ReleaseEventNode();

	/// 같으면
	if( mpModalMsgBox == window )
	{
		mpModalMsgBox = 0;

		mMsgBoxList.PopBack();
		int index = mMsgBoxList.GetSize();
		if( index > 0 )
		{
			cUIWindow* p = (cUIWindow*)mMsgBoxList.Back();
			mpModalMsgBox = p;
		}
	}
	/// 다르면
	else
	{
		cMsgBoxList::cIterator i = mMsgBoxList.Begin();
		cMsgBoxList::cIterator end = mMsgBoxList.End();
		for( ; i != end; ++i )
		{
			cUIWindow* p = (cUIWindow*)(*i);

			/// 동일한 윈도우 찾으면 해당
			if( p && p->GetEvent() == window->GetEvent() )
			{
				mMsgBoxList.Erase(i);
				break;
			}
		}

		cUIWindow* back = (cUIWindow*)mMsgBoxList.Back();
		mpModalMsgBox = back;
	}
}

/// 모달 메세지 박스 닫기
void cUIManager::DestroyMsgBox( cMsgBox* pMsgBox )
{
	if( pMsgBox == 0 )
	{
		assert(0);
		return;
	}

	if( pMsgBox->GetSkinType() == eSKIN_EDIT )
		ClearFocusedNode();

	/// 초기화 - 에디트포커스 초기화는 호출 전에 이미 함
	ReleaseEventNode();

	if( pMsgBox == mpModalMsgBox )
		mpModalMsgBox = 0;

	pMsgBox->Hide();
	mDestroyMsgBoxList.PushBack( pMsgBox );
	mMsgBoxList.Remove( pMsgBox );

	if( mpModalMsgBox == 0 )
	{
		if( mMsgBoxList.IsEmpty() == false )
			mpModalMsgBox = (cUIWindow*)mMsgBoxList.Back();
	}
}

bool cUIManager::Close()
{
	return mpRootNode->Close();
}

void cUIManager::NetUnLockAllUI()
{
	return mpRootNode->NetUnLockAllUI();
}

/// 주의사항 : 어떤 윈도우가 show 될때 리셋할 값 정하기
void cUIManager::CheckEventNode( cUINode* n )
{
	if( n == 0 )
		return;

	/// 팁 윈도우 닫기
	if( mTipWindow && mTipWindow->IsVisible() && n != mTipWindow )
		HideTip();

	/// 드래그 윈도우 닫기
	if( mpDragWindow && mpDragWindow->IsVisible() && n != mpDragWindow )
		mpDragWindow->Hide();

	if( !mTipWindow && !mpDragWindow )
		UpdateHoveredNode( mpRootNode, cUIPos(MOUSE->GetMouseX(), MOUSE->GetMouseY()) );
}

/// 주의사항 : 
void cUIManager::UpdateHoveredNode( cUIContainer* root, const cUIPos& pos )
{
	cUINode* pnewHovered = root->GetNode( pos );

	if( mpHoveredNode && mpHoveredNode != pnewHovered )
	{
		cUIEvent event;
		event.mType = eUIEVENT_MOUSE_LEFT;
		event.mPos = pos;
		mpHoveredNode->HandleEvent( event );
	}

	if( pnewHovered && pnewHovered != mpRootNode )
	{
		if( pnewHovered != mpHoveredNode )
		{
			cUIEvent event;
			event.mType = eUIEVENT_MOUSE_HOVERED;
			event.mPos = pos;
			pnewHovered->HandleEvent( event );

			mpHoveredNode = pnewHovered;
		}
	}
	else
	{
		mpHoveredNode = 0;
	}
}

void cUIManager::AddEventOtherClick( cUIWindow* win )
{
	if( win )
	{
		mOtherClickList.PushBack( win );
	}
}

void cUIManager::EventOtherClick( const cUIPos& pos )
{
	/// 각 UI 에 메세지 발생
	cOtherClickList::cIterator i = mOtherClickList.Begin();
	cOtherClickList::cIterator end = mOtherClickList.End();
	for( ; i != end; ++i )
	{
		cUIWindow* win = (cUIWindow*)(*i);
		if( win )
		{
			cUIEvent event;
			event.mType = eUIEVENT_MOUSE_OTHERCLICK;
			event.mPos = pos;
			win->HandleEvent( event );
		}
	}
}

/// 주의사항 : 
void cUIManager::SetCaptureNode( cUINode* n )
{
	assert( n && "null ui node" );

	if( mpCaptureNode != n )
	{
		if( mpCaptureNode )
		{
			ReleaseCaptureNode( mpCaptureNode );
		}
		mpCaptureNode = n;
	}
}

/// 주의사항 : 
void cUIManager::ReleaseCaptureNode( cUINode* n )
{
	assert( n && "null ui node" );

	if( mpCaptureNode == 0 )
		return;

	if( mpCaptureNode->GetParent() == n || 
		mpCaptureNode == n )
	{
		cUIEvent event;
		event.mType = eUIEVENT_CAPTURE_LOST;

		mpCaptureNode->HandleEvent( event );
		mpCaptureNode = 0;
	}
}

/// 주의사항 : 
void cUIManager::ReleaseHoverNode( cUINode* n )
{
	assert( n && "null ui node" );

	if( mpHoveredNode == 0 )
		return;

	if( mpHoveredNode->GetParent() == n || 
		mpHoveredNode == n )
	{
		cUIEvent event;
		event.mType = eUIEVENT_MOUSE_LEFT;

		mpHoveredNode->HandleEvent( event );
		mpHoveredNode = 0;
	}
}

/// 주의사항 : 
void cUIManager::SetFocusedNode( cUINode* n )
{
	assert( n && "null ui node" );

	if( mpFocusedNode != n )
	{
		if( mpFocusedNode )
		{
			ReleaseFocusedNode( mpFocusedNode );
		}
		mpFocusedNode = n;
	}
}

/// 주의사항 : 
void cUIManager::ReleaseFocusedNode( cUINode* n )
{
	assert( n && "null ui node" );

	if( mpFocusedNode == n )
	{
		cUIEvent event;
		event.mType = eUIEVENT_FOCUS_LOST;

		mpFocusedNode->HandleEvent( event );
		mpFocusedNode = 0;
	}
}

void cUIManager::ClearFocusedNode()
{
	if( mpFocusedNode )
	{
		cUIEvent event;
		event.mType = eUIEVENT_FOCUS_LOST;

		mpFocusedNode->HandleEvent( event );
		mpFocusedNode = 0;
	}
}

/// 주의사항 : 
void cUIManager::ReleaseEventNode()
{
	if( mpCaptureNode )
	{
		cUIEvent event;
		event.mType = eUIEVENT_CAPTURE_LOST;
		mpCaptureNode->HandleEvent( event );
	}
	
	if( mpHoveredNode )
	{
		cUIEvent event;
		event.mType = eUIEVENT_MOUSE_LEFT;
		mpHoveredNode->HandleEvent( event );
	}

	mpHoveredNode = 0;
	mpCaptureNode = 0;
}

void cUIManager::ShowItemTip( eTip_Kind tipkind, const cUIPos& pos, unsigned long itemIndex, int slotIndex,
							 cUIRoundGauge* gauge )
{
	HideTip();

	/// data setting
	sInventory itemInfo;

	itemInfo.ItemIndex = itemIndex;
	itemInfo.number = slotIndex;

	/// slot check;
	itemInfo.enhanced = 0;
	itemInfo.cardSlot1 = 0;
	itemInfo.cardSlot2 = 0;
	itemInfo.cardSlot3 = 0;
	itemInfo.cardSlot4 = 0;
	itemInfo.cardSlot5 = 0;
	itemInfo.seal = 0;

	if( slotIndex >= MIN_INVENTORY && slotIndex <= MAX_INVENTORY )
	{
		cItem item = ITEMMAN->GetItem( slotIndex );
		if( item.GetDefine() != 0)
		{
			itemInfo.enhanced = item.GetEnhanceStep();
			itemInfo.cardSlot1 = item.GetCardIndex1();
			itemInfo.cardSlot2 = item.GetCardIndex2();
			itemInfo.cardSlot3 = item.GetCardIndex3();
			itemInfo.cardSlot4 = item.GetCardIndex4();
			itemInfo.cardSlot5 = item.GetCardIndex5();
		}
		else
		{
			assert(0);
		}
	}

	/// show tip
	cItemTipWindow* pTip = GAMEUI->GetItemTip();
	if( pTip && pTip->SetItemInfo( tipkind, pos, itemInfo, true ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}

void cUIManager::ShowItemTip( eTip_Kind tipkind, const cUIPos& pos, unsigned long itemIndex, unsigned int enhance )
{
	HideTip();

	/// data setting
	sInventory itemInfo;

	itemInfo.ItemIndex = itemIndex;
	itemInfo.number = (unsigned short)-1;

	/// slot check;
	itemInfo.enhanced = enhance;
	itemInfo.cardSlot1 = 0;
	itemInfo.cardSlot2 = 0;
	itemInfo.cardSlot3 = 0;
	itemInfo.cardSlot4 = 0;
	itemInfo.cardSlot5 = 0;
	itemInfo.seal = 0;

	cItemTipWindow* pTip = GAMEUI->GetItemTip();
	if( pTip && pTip->SetItemInfo( tipkind, pos, itemInfo, false ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}

void cUIManager::ShowOtherItemTip( eTip_Kind tipkind, const cUIPos& pos, sInventory& inven )
{
	HideTip();

	cItemTipWindow* pTip = GAMEUI->GetItemTip();
	if( pTip && pTip->SetItemInfo( tipkind, pos, inven, false ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}

void cUIManager::ShowSkillTip( eTip_Kind tipkind, cSkillTipWindow* pTip, const cUIPos& pos, 
							   unsigned long skillIdx, char stepIdx, bool store )
{	
	HideTip();

	if( pTip && pTip->SetSkill( tipkind, pos, skillIdx, stepIdx, store ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}

void cUIManager::ShowCommunityTip( cSimpleTipWindow* pTip, const cUIPos& pos, cStringT str )
{
	HideTip();

	if( pTip && pTip->SetSimpleTip( pos, str ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}

void cUIManager::ShowUITip( const cUIPos& pos, unsigned long tipIdx )
{
	HideTip();

	cSimpleTipWindow* pTip = GAMEUI->GetSimpleTip();
	if( pTip && pTip->SetSimpleTip( pos, GetUIText( tipIdx ) ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}


void cUIManager::ShowBuffTip( cBuffToolTipWindow* pTip, const cUIPos& pos, unsigned long uniqueIdx, unsigned long influenceIdx, bool showTime )
{
	HideTip();

	if( pTip && pTip->SetBuff( pos, uniqueIdx, influenceIdx, showTime ) )
	{
		mTipWindow = pTip;
		ShowTip();
	}
}

void cUIManager::ShowChatItemTip( const cUIPos& pos, sInventory& inven )
{
	if( mChatItemTipWindow )
	{
		mChatItemTipWindow->Hide();

		if( mChatItemTipWindow->SetItemInfo( eTIP_ITEM, pos, inven, false ) )
//		if( mChatItemTipWindow->SetOtherItem( eTIP_ITEM, pos, inven ) )
			mChatItemTipWindow->ShowTop();
	}
}

void cUIManager::ShowChatItemTip( const cUIPos& pos, unsigned long itemIndex, int slotIndex )
{
	if( mChatItemTipWindow )
	{
		mChatItemTipWindow->Hide();

		/// data setting
		sInventory itemInfo;

		itemInfo.ItemIndex = itemIndex;
		itemInfo.number = slotIndex;

		/// slot check;
		itemInfo.enhanced = 0;
		itemInfo.cardSlot1 = 0;
		itemInfo.cardSlot2 = 0;
		itemInfo.cardSlot3 = 0;
		itemInfo.cardSlot4 = 0;
		itemInfo.cardSlot5 = 0;
		itemInfo.seal = 0;

		if( slotIndex <= MAX_INVENTORY )
		{
			cItem item = ITEMMAN->GetItem( slotIndex );
			if( item.GetDefine() != 0)
			{
				itemInfo.enhanced = item.GetEnhanceStep();
				itemInfo.cardSlot1 = item.GetCardIndex1();
				itemInfo.cardSlot2 = item.GetCardIndex2();
				itemInfo.cardSlot3 = item.GetCardIndex3();
				itemInfo.cardSlot4 = item.GetCardIndex4();
				itemInfo.cardSlot5 = item.GetCardIndex5();
			}
			else
			{
				assert(0);
			}
		}

//		if( mChatItemTipWindow->SetItem( eTIP_ITEM, pos, itemIndex, slotIndex, 0 ) )
		if( mChatItemTipWindow->SetItemInfo( eTIP_ITEM, pos, itemInfo, false ) )
			mChatItemTipWindow->ShowTop();
	}
}

void cUIManager::ShowTip()
{
	if( mTipWindow == 0 )
		return;

	bool onsound = false;
	mTipWindow->Show( onsound );
	mpRootNode->mTipWindow = mTipWindow;
}

void cUIManager::HideTip()
{
	if( mTipWindow )
		mTipWindow->Hide();

	mTipWindow = 0;
}

void cUIManager::ShowDrag( cUIWindow* pcaller, eDragFrom dragFrom, cIcon* icon, const cUIPos& pos, bool shift )
{
	if( mpDragWindow )
		mpDragWindow->Show( pcaller, dragFrom, icon, icon->GetIconType(), pos, shift );
}

void cUIManager::HideDrag( cUIWindow* pcaller )
{
	if( mpDragWindow )
		mpDragWindow->Hide( pcaller );
}

bool cUIManager::IsVisibleDrag()
{
	if( mpDragWindow )
		return mpDragWindow->IsVisible();
	return false;
}

bool cUIManager::IsShowNpcBack()
{
	if( mpNpcBackWindow )
		return mpNpcBackWindow->IsVisible();
	return false;
}

void cUIManager::ShowNpcBack()
{
	if( mpNpcBackWindow )
		mpNpcBackWindow->Show();
}

void cUIManager::HideNpcBack()
{
	if( mpNpcBackWindow && mpNpcBackWindow->IsVisible() == true )
	{
		HERO->EndNpcTalk();
		HERO->SendEndNpcTalk();

		mpNpcBackWindow->Hide();
		mpRootNode->ShowAllChild( true, mpNpcBackWindow );

		mNpcFuncType = NPC_FUNC_NULL;
	}
}

/// 닫기 메세지 없이 강제로 닫고 상태 푼다
void cUIManager::HideNpcBackNoMsg()
{
	if( mpNpcBackWindow && mpNpcBackWindow->IsVisible() == true )
	{
		HERO->EndNpcTalk();
		HERO->SetStopFlag( eSTOP_NONE );
		HERO->SetState( eOBJECT_STATE_IDLE );
		
		mpNpcBackWindow->Hide();
		mpRootNode->ShowAllChild( true, mpNpcBackWindow );

		mNpcFuncType = NPC_FUNC_NULL;
	}
}

/// 복구해야할 윈도우 세팅
void cUIManager::SetRestoreShow( cUIWindow* n )
{
	if( n && mpRootNode )
		mRestore.PushBack( n );
}

/// 주의사항 : npc 창 열려 있을때 생성되었던 윈도우들을
///			   npc 창이 닫히고 나면 보여주기 위함.
void cUIManager::RestoreShow()
{
	/// 복구용 윈도우들 복구 
	if( mRestore.GetSize() > 0 )
	{
		for( unsigned int i = 0; i < mRestore.GetSize(); ++i )
		{
			cUIWindow* n = (cUIWindow*)mRestore[i];
			if( n )
				n->Show();
		}

		mRestore.Clear();
	}

	/// 파티 UI 
	if( HERO->GetPartyIndex() > 0 )
	{
		PARTYMAN->ShowPartyUI();
	}
	else
	{
		PARTYMAN->HidePartyUI();
	}
}

/// 주의사항 : 루트의 자식인 윈도우를 찾음 
cUIContainer* cUIManager::GetContainer( unsigned int id )
{
	cUINode* n = mpRootNode->GetChild( id );
	if( n == 0 )
		return 0;

	if( n->IsKindof( eUINODE_CONTAINER ) == false )
	{
		assert( 0 && "child isn't window type" );
		return 0;
	}	

	return (cUIContainer*)n;
}

/// 주의사항 :
void cUIManager::UpdateScreenSize( unsigned int, unsigned int )
{
	ReleaseEventNode();
	ClearFocusedNode();

	if( mTipWindow )
		HideTip();

	if( mpDragWindow )
		mpDragWindow->Hide();

	for( unsigned int i = 0; i < eStage_Max; ++i )
	{
		mpStageRootNode[i]->UpdateSkin();
	}
}

//void cUIManager::AddVisibleArr( cUINode* node, bool visible )
//{
//	mpRootNode->AddVisibleArr( node, visible );
//}

bool cUIManager::AddPage( unsigned long pageIdx, cPage* page )
{
	if( !page )
		return false;

	if( mPageMap.Insert( pageIdx, page ) == false )
	{
		assert( 0 && "failed to insert page" );
		return false;
	}

	return true;
}

cPage* cUIManager::GetPage( unsigned long pageIdx )
{
	return (cPage*)mPageMap.GetAt( pageIdx );
}

sSceneData* cUIManager::GetSceneData( unsigned long sceneIdx )
{
	return (sSceneData*)mSceneMap.GetAt( sceneIdx );
}

/// 주의사항 : 교차된 컨테이너 업데이트 
cUIContainer* cUIManager::UpdateNearContainer( cUIContainer* con, bool axisX ) const
{	
	return mpRootNode->GetNearRootChild( con, axisX );
}

LPCTSTR cUIManager::GetUIText( unsigned int textId )
{
	assert( mpSkinText );
	return mpSkinText->GetText( textId ).Cstr();
}

bool cUIManager::GetUIText( cStringT* str, unsigned int idx )
{
	assert( mpSkinText );
	return mpSkinText->GetText( str, idx );
}

/// 주의사항 : 유저로부터 받은 이벤트 처리
bool cUIManager::PostEventFromUser( const cUIEvent& event )
{
	if( mpModalMsgBox )
	{
		if( MsgBoxEventProcess( event ) == true )
			return true;
	}

	switch( event.mType )
	{
	case eUIEVENT_LBUTTON_DOWN:
	case eUIEVENT_RBUTTON_DOWN:
		if( mpFocusedNode )
		{
			UpdateHoveredNode( mpRootNode, event.mPos );

			if( mpHoveredNode != mpFocusedNode )
			{
				/// 에디트박스같이, 포커스가 있는 노드가있으면
				/// 마우스가 눌리면 무조건 포커스를 없앤다 
				cUIEvent e;
				e.mType = eUIEVENT_FOCUS_LOST;
				mpFocusedNode->HandleEvent( e );

				mpFocusedNode = 0;
				mpCaptureNode = 0;
			}
		}
		
		if( mTipWindow && mTipWindow->IsVisible() )
			HideTip();

		/// 다른 영역 클릭 검사
		EventOtherClick( event.mPos );

	case eUIEVENT_LBUTTON_UP:
	case eUIEVENT_RBUTTON_UP:
	case eUIEVENT_MOUSE_MOVE:
	case eUIEVENT_MOUSE_WHEEL:
	case eUIEVENT_LBUTTON_DBLCLK:
		/// 캡쳐노드가 존재하고, 마우스를 캡쳐하는 노드이고, 
		if( mpCaptureNode && mpCaptureNode->HandleEvent( event ) )
		{
			return true;
		}

		/// 캡쳐노드가 없고, 오버노드이면 그 노드의 이벤트를 실행
		if( mpCaptureNode == 0 )
		{
			UpdateHoveredNode( mpRootNode, event.mPos );

			if( mpHoveredNode )
			{
				bool used = mpHoveredNode->HandleEvent( event );

				if( event.mType == eUIEVENT_MOUSE_MOVE )
					/// 카메라 앵글 이동 가능하도록 한다.
					return false;
				else
				{
					if( mpHoveredNode && mpHoveredNode->IsLClickNotifyStage() )
						return false;

					return used;
				}
			}
		}
		break;
	case eUIEVENT_KEY_UP:
	case eUIEVENT_KEY_DOWN:
	case eUIEVENT_IME_NOTIFY:
	case eUIEVENT_IME_STARTCOMPOSITION:
	case eUIEVENT_IME_COMPOSITION:
	case eUIEVENT_IME_ENDCOMPOSITION:
	case eUIEVENT_CHAR:
		if( mpFocusedNode )
		{
			return mpFocusedNode->HandleEvent( event );
		}
		break;
	}

	mMousePos = event.mPos;
	return false;
}

bool cUIManager::MsgBoxEventProcess( const cUIEvent& event )
{
	switch( event.mType )
	{
	case eUIEVENT_MOUSE_MOVE:
		{
			/// 캡쳐노드가 존재하고, 마우스를 캡쳐하는 노드이고, 
			if( mpCaptureNode && mpCaptureNode->HandleEvent( event ) )
			{
				return true;
			}

			/// 캡쳐노드가 없고, 오버노드이면 그 노드의 이벤트를 실행
			if( mpCaptureNode == 0 )
			{
				UpdateHoveredNode( mpRootNode, event.mPos );

				if( mpHoveredNode )
				{
					if( mpHoveredNode == mpModalMsgBox )
					{
						mpModalMsgBox->HandleEvent( event );
						return true;
					}
					else
					{
						bool used = mpHoveredNode->HandleEvent( event );

						if( event.mType == eUIEVENT_MOUSE_MOVE )
							/// 카메라 앵글 이동 가능하도록 한다.
							return false;
						else
							return used;
					}
				}
			}
		}
		break;
	case eUIEVENT_LBUTTON_DOWN:
		{
			if( mpFocusedNode )
			{
				UpdateHoveredNode( mpRootNode, event.mPos );
				if( mpHoveredNode != mpFocusedNode )
				{
					/// 에디트박스같이, 포커스가 있는 노드가있으면
					/// 마우스가 눌리면 무조건 포커스를 없앤다 
					cUIEvent e;
					e.mType = eUIEVENT_FOCUS_LOST;
					mpFocusedNode->HandleEvent( e );

					mpFocusedNode = 0;
					mpCaptureNode = 0;

					mpModalMsgBox->HandleEvent( event );
					return true;
				}
			}
			else
			{
				mpModalMsgBox->HandleEvent( event );
				return true;
			}
		}
		break;
	case eUIEVENT_KEY_UP:
	case eUIEVENT_KEY_DOWN:
		{
			if( mpFocusedNode == 0 )
			{
				mpModalMsgBox->HandleEvent( event );
				return true;
			}
		}
		break;
	case eUIEVENT_IME_NOTIFY:
	case eUIEVENT_IME_STARTCOMPOSITION:
	case eUIEVENT_IME_COMPOSITION:
	case eUIEVENT_IME_ENDCOMPOSITION:
	case eUIEVENT_CHAR:
		break;
	default:
		mpModalMsgBox->HandleEvent( event );
		return true;
	}

	return false;
}


void cUIManager::ChangeModalMessage( LPCTSTR text )
{
	if( mpModalMsgBox && mpModalMsgBox->IsKindof( eUINODE_MESSAGEBOX ) )
	{
		cMsgBox* box = (cMsgBox*)mpModalMsgBox;
		box->SetMessage( text );
	}
}

void cUIManager::ModalEventFromGameSystem( bool success )
{
	/// 임의 이벤트 처리
	if( mpModalMsgBox == 0 )
		return;

	cUIEvent event;
	event.mType = eUIEVENT_GAME_COMMAND;

	if( success )
	{
		event.mID = eMESSAGE_BUTTON_YES;
		mpModalMsgBox->HandleEvent( event );
	}
	else
	{
		event.mID = eMESSAGE_BUTTON_NO;
		mpModalMsgBox->HandleEvent( event );
	}
}

/// 해당 이벤트를 가진 메세지박스에 임의로 이벤트 전달
void cUIManager::SendEventToMsgbox( bool success, eMSGBox_Event eventtype )
{
	unsigned int size = mMsgBoxList.GetSize();
	if( size == 0 )
		return;

	cUIEvent event;
	event.mType = eUIEVENT_GAME_COMMAND;

	cMsgBoxList::cIterator i = mMsgBoxList.Begin();
	cMsgBoxList::cIterator end = mMsgBoxList.End();
	for( ; i != end; ++i )
	{
		cUIWindow* p = (cUIWindow*)(*i);

		/// 동일한 윈도우 찾으면 해당
		if( p && p->GetEvent() == eventtype )
		{
			event.mID = ( success == true ) ? eMESSAGE_BUTTON_YES : eMESSAGE_BUTTON_NO;
			p->HandleEvent( event );
			break;	
		}
	}
}

/// 해당 이벤트를 가진 메세지박스 찾아서 닫기만 함
void cUIManager::CloseMsgBox( eMSGBox_Event eventtype )
{
	unsigned int size = mMsgBoxList.GetSize();
	if( size == 0 )
		return;

	ReleaseEventNode();
	ClearFocusedNode();

	cUIEvent event;
	event.mType = eUIEVENT_GAME_COMMAND;

	cMsgBoxList::cIterator i = mMsgBoxList.Begin();
	cMsgBoxList::cIterator end = mMsgBoxList.End();
	for( ; i != end; ++i )
	{
		cUIWindow* p = (cUIWindow*)(*i);

		/// 동일한 윈도우 찾으면 해당
		if( p && p->GetEvent() == eventtype )
		{
			if( p->IsKindof( eUINODE_MESSAGEBOX ) )
				DestroyMsgBox( (cMsgBox*)p );
			else
			{
				p->Hide();
				ReleaseModal( p );
			}
			mMsgBoxList.Erase(i);
			break;
		}
	}
}

/// 모든 메세지 박스 닫기
void cUIManager::CloseAllMsgBox( bool sendEvent )
{
	ReleaseEventNode();
	ClearFocusedNode();

	if( mMsgBoxList.GetSize() > 0 )
	{
		cMsgBoxList::cIterator i = mMsgBoxList.Begin();
		cMsgBoxList::cIterator end = mMsgBoxList.End();
 		for( ; i != end; )
		{
			cUIWindow* win = (cUIWindow*)(*i);

			/// 메세지박스
			if( win->IsKindof( eUINODE_MESSAGEBOX ) )
			{
				if( sendEvent == true )
				{
					cUIEvent e;
					e.mType = eUIEVENT_GAME_COMMAND;
					e.mID = eMESSAGE_NOTDESTROY;	/// 삭제 안하는 용
					win->HandleEvent( e );
				}

				i = mMsgBoxList.Erase(i);
				GetRootNode()->RemoveChildComplete( win );
			}
			/// 모달 윈도우
			else
			{
				if( sendEvent == true )
				{
					cUIEvent e;
					e.mType = eUIEVENT_GAME_COMMAND;
					e.mID = eMESSAGE_BUTTON_NO;
					win->HandleEvent( e );
				}

				win->SetVisible( false );
				i = mMsgBoxList.Erase(i);
			}
		}

		mMsgBoxList.Clear();
	}
	
	mpModalMsgBox = 0;
}

void cUIManager::GotoFrontNode( cUINode* node )
{
	unsigned long frontId = mFrontIdGen.GenerateIndex();
	if( mApplyFrontMap.Insert( frontId, node ) == false )
	{
		assert(0);
		return;
	}
	node->mFrontID = frontId;
}

void cUIManager::RemoveFrontNode( unsigned long frontId )
{
	mApplyFrontMap.Erase(frontId);
}

void cUIManager::ApplyFrontNode( cUINode* node )
{
	cUIContainer* parent = node->GetParent();
	if( parent == 0 )
		return;

	tPointerList<void*>* plist = parent->GetChildList();

	bool bFind = false;
	tPointerList<void*>::cIterator i = plist->Begin();
	tPointerList<void*>::cIterator end = plist->End();
	for( ; i != end; ++i )
	{	
		if( node == (*i) )
		{
			/// 찾았으면 앞으로 보냄 
			plist->Erase( i );
			plist->PushBack( node );
			node->mFrontID = 0;
			bFind = true;
			break;
		}
	}

	if( bFind == true && parent->GetType() != eUINODE_ROOT )
		ApplyFrontNode( parent );
}

void cUIManager::GotoFrontMsgBox()
{
	cMsgBoxList::cIterator i = mMsgBoxList.Begin();
	cMsgBoxList::cIterator end = mMsgBoxList.End();
	for( ; i != end; ++i )
	{
		cUINode* node = (cUINode*)(*i);
		if( node )
		{
			GotoFrontNode( node );
		}
	}
}

bool cUIManager::IsCameraEnableContainUI()
{
	if( mpHoveredNode )
	{
		if( mpHoveredNode == (cUINode*)GAMEUI->GetMinimapWindow() )
			return true;

		return false;
	}

	return true;
}
