#include "StdAfx.h"
#include "ChatManager.h"
#include "TextBox.h"
#include "ChatCommands.h"

#include "Protocol.h"
#include "Chat_Common.h"

#include "ChatWindow.h"
#include "EditBox.h"
#include "NoteWindow.h"
#include "FriendWindow.h"
#include "SendNoteWindow.h"

#include "ChatCommands.h"
#include "Tokenizer.h"
#include "item_common.h"
#include "Party_Common.h"
#include "gameResourceManager.h"
#include "FilterManager.h"
#include "PartyManager.h"
#include "ObjectManager.h"
#include "GameUIManager.h"
#include "Hero.h"

#include "CommunityScript.h"

#ifdef _GMTOOL
#include "CheatManager.h"
#endif

cChatManager* cChatManager::mInstance = 0;

cChatManager::cChatManager()
: mpCommands(0)
, mpNoteWindow(0)
, mpFriendWindow(0)
{
	assert( mInstance == 0 && "bad singleton!" );
	mInstance = this;
}

cChatManager::~cChatManager()
{
	DeleteNote();

	mFocusArr.Clear();
	mChatWindowList.Clear();
	
	mpFriendWindow = 0;
	mpNoteWindow = 0;
	mInstance = 0;

	SAFE_DELETE( mpCommands );
}

/// 주의사항 :
bool cChatManager::Init()
{
	mpCommands = new cChatCommands;
	if( !mpCommands )
	{
		assert( 0 && "mpCommands is null" );
		return false;
	}

	/// apply community script 
	cCommunityScript::cComHashMap* pCom = COMMUNITYSCRIPT->GetComSkillMap();
	if( pCom == 0 )
		return false;

	cCommunityScript::cComHashMap::cIterator iter = pCom->Begin();
	for( ;iter != pCom->End() ; ++iter )
	{
		sCommunitySkillInfo* info = (sCommunitySkillInfo*)(*iter).mSecond;
		if( info == 0 )
			continue;

		for( unsigned int i = 0; i< 5; i++ )
		{
			if( info->mCommandIndex[i] == 0 )
				continue;

			LPCTSTR str = UIMAN->GetUIText( info->mCommandIndex[i] );
			AddCommunityData( str, info->mIndex );
		}
	}

	return true;
}

void cChatManager::Clear()
{
	/// 채팅창 클리어
	{
		cChatWindowList::cIterator b = mChatWindowList.Begin();
		cChatWindowList::cIterator end = mChatWindowList.End();

		cChatWindow* w = 0;

		for( ; b != end; ++b )
		{
			w = (cChatWindow*)(*b);
			if( w )
			{
				w->Clear();
			}
			else
			{
				assert(0);
			}
		}
	}
}

void cChatManager::AddNoticeMsg( LPCTSTR msg, unsigned long color )
{
	HERO->ActiveNoticeText( msg, color );

	///
	AddChatMsg( msg, eCHAT_NOTICE );
}

/// 주의사항 : 채팅 메시지 파서 
void cChatManager::SendChatMsg( eChatMsgKind type, LPCTSTR msg )
{
	if( msg == 0 )
		return;

	if( !mpCommands )
	{
		assert(0);
		return;
	}

#ifdef _GMTOOL
	/// 치트 명령을 처리
	if( CHEATMAN->Interpret( msg, ::_tcslen(msg) ) )
		return;
#endif

	/// filtering
	if( FILTERMAN->CheckWholeMatch( msg ) == true )
	{
		/// 에러메시지 출력
		cStringT errorMsg;
		errorMsg.Format( GAMERESOURCEMAN->GetGameText( 80 ) );
		AddSystemMsg( eSYSTEM_NORMAL, (LPCTSTR)errorMsg.Cstr() );
		return;
	}

	/// filtering
	if( FILTERMAN->CheckPartMatch( msg ) == true )
	{
		/// 에러메시지 출력
		cStringT errorMsg;
		errorMsg.Format( GAMERESOURCEMAN->GetGameText( 80 ) );
		AddSystemMsg( eSYSTEM_NORMAL, (LPCTSTR)errorMsg.Cstr() );
		return;
	}

	/// "/" 명령어인지 검사
	TCHAR temp[2] = {0,};
	::_tcsncpy( temp, &msg[0], 1 );

	/// 명령어가 있는경우 우선 처리
	if( ::_tcsncmp( temp, _T("/"), 2 ) == 0 )
	{
		mpCommands->MessageParser( msg );
	}
	/// 명령어가 없는경우 타입 보고 결정
	else
	{
		mpCommands->MessageParserByType( type, msg );
	}
}

///
void cChatManager::AddSystemMsg( eSystemMsgKind kind, LPCTSTR chatmsg )
{
	cChatWindowList::cIterator b = mChatWindowList.Begin();
	cChatWindowList::cIterator end = mChatWindowList.End();

	cChatWindow* w = 0;

	for( ; b != end; ++b )
	{
		w = (cChatWindow*)(*b);
		if( w )
			w->InsertTextSystem( kind, chatmsg );
	}
}

void cChatManager::AddTipMsg( LPCTSTR msg )
{
	cChatWindow* w = GAMEUI->GetChatWindow();
	if( w )
		w->InsertTextTip( msg );
}

/// 아이템 획득시를 위한 메세지
void cChatManager::AddItemMsg( unsigned long itemIndex, unsigned int slotIndex, LPCTSTR msg1, LPCTSTR msg2, bool IsQuest )
{
	cChatWindowList::cIterator b = mChatWindowList.Begin();
	cChatWindowList::cIterator end = mChatWindowList.End();

	cChatWindow* w = 0;

	for( ; b != end; ++b )
	{
		w = (cChatWindow*)(*b);
		if( w )
			w->InsertItemText( itemIndex, slotIndex, msg1, msg2, IsQuest );
	}
}

/// 아이템 거래 메세지
void cChatManager::AddItemMsg( sInventory inventory, LPCTSTR name, LPCTSTR msg, eChatMsgKind msgkind )
{
	cChatWindowList::cIterator b = mChatWindowList.Begin();
	cChatWindowList::cIterator end = mChatWindowList.End();

	cChatWindow* w = 0;

	for( ; b != end; ++b )
	{
		w = (cChatWindow*)(*b);
		if( w )
			w->InsertItemText( inventory, name, msg, msgkind );
	}
}

void cChatManager::AddChatMsg( LPCTSTR chatmsg, unsigned int msgkind )
{
	cChatWindowList::cIterator b = mChatWindowList.Begin();
	cChatWindowList::cIterator end = mChatWindowList.End();

	cChatWindow* w = 0;

	for( ; b != end; ++b )
	{
		w = (cChatWindow*)(*b);
		if( w )
			w->InsertText( (eChatMsgKind)msgkind, chatmsg );
	}
}

/// 주의사항 :
void cChatManager::SetChatWindow( cUIWindow* w )
{
	/// 채팅윈도우 세팅 
	if( w )
		mChatWindowList.PushBack( w );
}

///
void cChatManager::SetNoteWindow( cUIWindow* w )
{
	/// 쪽지 윈도우 세팅
	if( w)
		mpNoteWindow = w;
}

///
void cChatManager::SetFriendWindow( cUIWindow* w )
{
	/// 친구 윈도우 세팅
	if( w )
		mpFriendWindow = w;
}

void cChatManager::AddFocusNode( cUINode* n )
{
	if( n )
		mFocusArr.PushBack( n );
}

/// 주의사항 : 일대일대화창, 채팅창 간의 포커스 이동
void cChatManager::ChangeFocus()
{
	/// 전체적으로 포커스 없으면 리턴 
	if( !UIMAN->GetFocusedNode() )
		return;

	if( mFocusArr.GetSize() < 4 )
		return;

	/// 채팅창을 제외한 나머지 창이 닫혀있으면 체크 안함
	if( ((cEditBox*)mFocusArr[1])->IsVisible() == false &&
		((cEditBox*)mFocusArr[2])->IsVisible() == false &&
		((cEditBox*)mFocusArr[3])->IsVisible() == false )
		return;

	cEditBox* pEdit = 0;
	int focusIdx = -1;
	for( int i = 0; i < (int)mFocusArr.GetSize(); ++i )
	{
		pEdit = (cEditBox*)mFocusArr[i];
		if( pEdit == 0 )
		{
			assert(0);
			return;
		}

		/// 범위를 넘어가면 다시처음으로 검사
		if( focusIdx >= (int)mFocusArr.GetSize() )
		{
			focusIdx = 0;
		}

		if( pEdit->IsFocus() )	
		{
			focusIdx = i + 1;
		}

		/// 동일하면		
		if( i == focusIdx )
		{
			cEditBox* pNewEdit = (cEditBox*)mFocusArr[ focusIdx ];
            if( pNewEdit == 0 )
			{
				assert(0);
				return;
			}
			
			if( pNewEdit->IsVisible() )
			{
				/// 보이면 이놈이 포커스
				pNewEdit->SetFocus();
				return;
			}
			else
			{
				/// 안보이면 고다음으로 넘긴다
				focusIdx = i + 1;
			}
		}
	}

	/// 결국없으면 채팅창에 포커스 주기
	pEdit = (cEditBox*)mFocusArr[0];
	pEdit->SetFocus();
}

bool cChatManager::AddCommunityData( LPCTSTR key, unsigned long index )
{
	if( mpCommands->AddCommunityData( key, index ) == false )
		return false;
	return true;
}

void cChatManager::DeleteNote()
{
	cNoteList::cIterator ni = mNoteList.Begin();
	cNoteList::cIterator nend = mNoteList.End();
	for( ; ni != nend; ++ni )
	{
		sNoteList* data = (sNoteList*)(*ni);
		SAFE_DELETE( data );
	}
	mNoteList.Clear();
}

bool NoteSort( const void *arg1, const void *arg2 )
{
	sNoteList* data1 = (sNoteList*)arg1;
	sNoteList* data2 = (sNoteList*)arg2;
	
	return (data1->Idx - data2->Idx > 0);
}

/// 주의사항 :
void cChatManager::NetworkMsgParser( char* pMsg )
{
	cStringT Message;
	MSGROOT* pTemMsg = (MSGROOT*)pMsg;

	switch( pTemMsg->Protocol )
	{
	case NM_CHAT_NORMAL_RES:
		{
			MSG_RES_CHAT* pmsg = (MSG_RES_CHAT*)pMsg;

			switch( pmsg->ErrorCode )
			{
			case ERROR_CHAT_SUCCESS:
				break;
			case ERROR_CHAT_BLOCK:		/// 채팅 블럭
				{
					Message.Format( GAMERESOURCEMAN->GetGameText( 69 ), pmsg->validTrue.wYear, pmsg->validTrue.wMonth,
									pmsg->validTrue.wDay, pmsg->validTrue.wHour, pmsg->validTrue.wMinute, pmsg->validTrue.wSecond );
					AddSystemMsg( eSYSTEM_NORMAL, (LPCTSTR)Message.Cstr() );
				}
				break;
			case ERROR_CHAT_FAIL:		/// 채팅 실패
				break;
			}
		}
		break;
	case NM_CHAT_NORMAL_SYN:
		{
			MSG_SYN_CHAT* pmsg = (MSG_SYN_CHAT*)pMsg;
			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

			AddItemMsg( pmsg->inventory, pmsg->Name, pmsg->Message, eCHAT_NORMAL );

			unsigned int len = ::_tcslen(pmsg->Message);
			cPlayer* p = OBJECTMAN->GetPlayer( pmsg->CharacterIdx );
			if( p && len > 0 )
			{
				p->ActiveChatBubble( pmsg->Message, (unsigned long)0xFFFCFF9E );

				if( pmsg->emotionIdx != 0 )
					p->SetEmotionFace( pmsg->emotionIdx );
			}
		}
		break;
	case NM_CHAT_SHOUT_RES:
		break;
	case NM_CHAT_SHOUT_SYN:
		{
			MSG_SYN_CHAT_SHOUT* pmsg = (MSG_SYN_CHAT_SHOUT*)pMsg;

			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

			Message.Format( UIMAN->GetUIText( 10000 ), pmsg->Name, pmsg->Message );
			AddChatMsg( (LPCTSTR)Message.Cstr(), eCHAT_SHOUT );
		}	
		break;
	case NM_CHAT_TRADE_SYN:
		{
			MSG_SYN_CHAT_TRADE* pmsg = (MSG_SYN_CHAT_TRADE*)pMsg;

			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

			AddItemMsg( pmsg->inventory, pmsg->Name, pmsg->Message, eCHAT_TRADE );
		}
		break;
	case NM_CHAT_WHISPER_RES:
		{
			MSG_RES_CHAT_WHISPER* pmsg = (MSG_RES_CHAT_WHISPER*)pMsg;

			switch ( pmsg->ErrorCode )
			{
			case ERROR_CHAT_WHISPER_SUCCESS:
				pmsg->Name[MAX_NAME_SIZE] = 0;
				pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

				Message.Format( UIMAN->GetUIText( 9998 ), pmsg->Name );
				AddItemMsg( pmsg->inventory, (LPCTSTR)Message.Cstr(), pmsg->Message, eCHAT_WHISPER );
				break;
			case ERROR_CHAT_WHISPER_CHARACTER_NAME:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 24 ) );
				break;	
			case ERROR_CHAT_WHISPER_DISCONNECT:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 25 ) );
				break;	
			case ERROR_CHAT_WHISPER_NO_MESSAGE:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 28 ) );
				break;	
			case ERROR_CHAT_WHISPER_INPUT_TIME:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 26 ) );
				break;
			case ERROR_CHAT_WHISPER_MYSELF:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 27 ) );
				break;
			case ERROR_CHAT_WHISPER_OPTIONREFUSE:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 2704 ) );
				break;
			}
		}
		break;
	case NM_CHAT_WHISPER_SYN:
		{
			MSG_SYN_CHAT_WHISPER* pmsg = (MSG_SYN_CHAT_WHISPER*)pMsg;

			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;
			
			Message.Format( UIMAN->GetUIText( 9999 ), pmsg->Name );
			AddItemMsg( pmsg->inventory, (LPCTSTR)Message.Cstr(), pmsg->Message, eCHAT_WHISPER );
		}
		break;

		/// note
	case NM_CHAT_NOTE_DEL_RES:
		{
			AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 33 ) );

			cNoteWindow* win = GAMEUI->GetNoteWindow();
			if( win )
			{
				win->NetUnLock();
			}
			else
			{
				assert(0);
			}
		}
		break;
	case NM_CHAT_NOTE_RECV_RES:
		{
			/// 서버 -> 쪽지 윈도우 ( 받기 )
			MSG_RES_NOTE_RECV* msg = (MSG_RES_NOTE_RECV*)pMsg;

			/// 초기화
			DeleteNote();

			sNoteList* table = msg->table;
			for( int i = 0; i < msg->RowCount; ++i, ++table )
			{
				sNoteList* data = new sNoteList;
				*data = *table;

				mNoteList.PushBack( data );
			}

			/// 정렬
			mNoteList.Sort( NoteSort );

			///
			cNoteWindow* pNote = (cNoteWindow*)mpNoteWindow;
			if( pNote )
			{
				pNote->Clear();

				cNoteList::cIterator ni = mNoteList.Begin();
				cNoteList::cIterator nend = mNoteList.End();
				for( ; ni != nend; ++ni )
				{
					sNoteList* data = (sNoteList*)(*ni);
					pNote->AddNote( data );
				}

				pNote->UpdateButton();
			}
			else
			{
				assert(0);
				return;
			}

			/// 50개가 다 찼으면 경고 메시지 출력
			if( msg->RowCount >= MAX_NOTE_COUNT )
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 37 ) );
		}
		break;
	case NM_CHAT_NOTE_SEND_SYN:
		{
			/// 서버 -> 쪽지 윈도우 ( 받기 )
			MSG_SYN_NOTE_SEND* msg = (MSG_SYN_NOTE_SEND*)pMsg;

			/// 데이터 삽입
			sNoteList* data = new sNoteList;
			sNoteList* table = &(msg->table);
			*data = *table;
			mNoteList.PushBack( data );

			/// 정렬
			mNoteList.Sort( NoteSort );

			///
			cNoteWindow* pNote = (cNoteWindow*)mpNoteWindow;
			if( pNote )
			{
				pNote->Clear();

				cNoteList::cIterator ni = mNoteList.Begin();
				cNoteList::cIterator nend = mNoteList.End();
				for( ; ni != nend; ++ni )
				{
					sNoteList* data = (sNoteList*)(*ni);
					pNote->AddNote( data );
				}

				pNote->UpdateButton();
			}
			else
			{
				assert(0);
				return;
			}

			/// 쪽지 도착 알림
			AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 63 ) );

			/// 50개가 다 찼으면 경고 메시지 출력
			if( mNoteList.GetSize() >= MAX_NOTE_COUNT )
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 37 ) );
		}
		break;
	case NM_CHAT_NOTE_SEND_RES:
		{
			/// 서버 -> 쪽지 윈도우 ( 보내기 )
			MSG_RES_NOTE_SEND*	pmsg = (MSG_RES_NOTE_SEND*)pMsg;

			switch( pmsg->ErrorCode )
			{
			case ERROR_CHAT_NOTE_SUCCESS:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 29 ) );
				break;
			case ERROR_CHAT_NOTE_NOTEXIST:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 184 ) );
				break;
			case ERROR_CHAT_NOTE_OVER:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 34 ) );
				break;
			case ERROR_CHAT_NOTE_UNKNOWN:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 24 ) );
				break;
			case ERROR_CHAT_NOTE_OPTIONREFUSE:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 2705 ) );
				break;
			}

			/// 락 풀기
			cSendNoteWindow* win = GAMEUI->GetSendNoteWindow();
			if( win )
			{
				win->NetUnLock();
			}
			else
			{
				assert(0);
			}
		}
		break;
	case NM_CHAT_GUILDNOTE_SEND_RES:
		{
			MSG_RES_NOTE_SEND*	pmsg = (MSG_RES_NOTE_SEND*)pMsg;

			switch( pmsg->ErrorCode )
			{
			case ERROR_CHAT_NOTE_SUCCESS:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 1259 ) );
				break;
			case ERROR_CHAT_NOTE_UNKNOWN:
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 24 ) );
				break;
			case ERROR_CHAT_NOTE_GUILD:		/// 길드 중 아님
				AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 1256 ) );
				break;
			}

			/// 락 풀기
			cGuildSendNoteWindow* win = GAMEUI->GetGuildSendNoteWindow();
			if( win )
			{
				win->NetUnLock();
			}
			else
			{
				assert(0);
			}
		}
		break;

		/// Friend
	case NM_CHAT_FRIEND_LIST_RES:
		{
			/// 서버 -> 친구 윈도우 ( 리스트 보냄 )
			cFriendWindow* pFriend = (cFriendWindow*)mpFriendWindow;
			if( pFriend )
			{
				pFriend->AddFriend( (MSG_RES_FRIEND_LIST*)pMsg );
			}
			else
			{
				assert(0);
			}
		}
		break;
	case NM_CHAT_FRIEND_ADD_RES:
		{
			/// 서버 -> 친구 윈도우 ( 친구 요청 결과 : 에러처리 )
			MSG_REQ_FRIEND_LIST msg;
			::memset( &msg, 0, sizeof( msg ) );

			msg.Category = NM_CHAT;
			msg.Protocol = NM_CHAT_FRIEND_LIST_REQ;

			NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
		}
		break;
	case NM_CHAT_FRIEND_DEL_RES:
		{
			AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 32 ) );
		}
		break;
	case NM_CHAT_PARTY_SYN:
		{
			/// 파티 대화
			MSG_SYN_CHAT_PARTY* pmsg = (MSG_SYN_CHAT_PARTY*)pMsg;

			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

			AddItemMsg( pmsg->inventory, pmsg->Name, pmsg->Message, eCHAT_PARTY );
		}
		break;
	case NM_CHAT_GUILD_SYN:
		{
			/// 길드 대화
			MSG_SYN_CHAT_GUILD* pmsg = (MSG_SYN_CHAT_GUILD*)pMsg;

			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

			AddItemMsg( pmsg->inventory, pmsg->Name, pmsg->Message, eCHAT_GUILD );
		}
		break;

	case NM_CHAT_GM_NORMAL_RES:
		break;
	case NM_CHAT_GM_NORMAL_SYN:
		{
			MSG_SYN_CHAT* pmsg = (MSG_SYN_CHAT*)pMsg;
			pmsg->Name[MAX_NAME_SIZE] = 0;
			pmsg->Message[MAX_CHAT_BUFFER_SIZE] = 0;

			AddItemMsg( pmsg->inventory, pmsg->Name, pmsg->Message, eCHAT_GM );

			unsigned int len = ::_tcslen(pmsg->Message);
			cPlayer* p = OBJECTMAN->GetPlayer( pmsg->CharacterIdx );
			if( p && len > 0 )
			{
				p->ActiveChatBubble( pmsg->Message, eCOLOR_GM );

				if( pmsg->emotionIdx != 0 )
					p->SetEmotionFace( pmsg->emotionIdx );
			}
		}
		break;
	}
}
