#include "StdAfx.h"
#include "chatroom.h"
#include "webctrl.h"

ChatRoom::ChatRoom(int id, const TCHAR * r)
{
	recipientId = id;
	recipient = r;
	padding = 5;
	db.GetGroupMembers(id,members);
	db.GetAttendingGroupMembers(id,active);
}

ChatRoom::~ChatRoom(void)
{
	db.LeaveGroupMeeting(theApp.user.UserId,recipientId);
	rpc.ServerNotifyImmediate(bcGroup,recipientId,bcIdle,theApp.user.UserId);
}

static float RandomJitter(){
	return 2*((rand()/(float)RAND_MAX)-0.5);
}

int ChatRoom::Create(HWND parent)
{
	Load("chatroom");

	// jitter the starting position a bit
	location.X += 25*RandomJitter();
	location.Y += 25*RandomJitter();

	title = env.GetWideString("chatroom","title",L"ChatRoom");
	title += L": ";
	title += recipient;
	titlebar.Load("chatroom::titlebar");
	titlebar.title = title;

	MyFormat = env.GetWideString("chatroom","MyFormat",L"%s: %s<br>");
	FriendFormat = env.GetWideString("chatroom","FriendFormat",L"%s: %s<br>");
	SystemFormat = env.GetWideString("chatroom","SystemFormat",L"%s<br>");

	if(SkinnableFrame::Create(parent)){
		padding = resize.size.Width;
		// the history window
		history.Load("chatroom::history");
		history.scrollbar.Load("chatroom::scrollbar");
		history.location = Point(padding,padding+titlebar.size.Height);
		history.size = Size(size.Width-padding*2,size.Height-padding*2-100-titlebar.size.Height);
		//history.Create(hWnd,ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_READONLY);

		// the msg window
		msg.Load("chatroom::message");
		msg.scrollbar.Load("chatroom::scrollbar");
		msg.location = Point(padding,size.Height-100);
		msg.size = Size(size.Width-2*padding,100-padding);
		msg.Create(hWnd,ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL);
		msg.SetMsgOnCarriageReturn(hWnd,WM_CHAR,(WPARAM)0x0D,(LPARAM)msg.hWnd);

		InitWebCtrl();

		TCHAR buffer[1024], dir[1024];
		GetCurrentDirectory(1023,dir);

		_stprintf(buffer,L"about:blank");

		hBrowser = CreateWindow(
						WC_WEBCTRL,
						buffer,
						WS_CHILD | WS_VISIBLE,
						history.location.X, history.location.Y,
						history.size.Width, history.size.Height,
						hWnd,
						(HMENU) NULL,
						env.hInstance,
						NULL );

		_stprintf(buffer,L"<base href=\"file:///%s/\">\n",dir);
		SafeSendMessage(hBrowser,WC_APPEND,0,(LPARAM)buffer);

		std::wstring htmlbase = env.GetWideString("chatroom","htmlbase",L"<html><body>");
		SafeSendMessage(hBrowser,WC_APPEND,0,(LPARAM)htmlbase.data());

		if(active.length>0){
			std::wstring tmp = L"Current Participants: ", tmp2;
			for(int i=0;i<active.length;i++){
				db.GetCachedUsername(active[i],tmp2);
				tmp += tmp2;
				if(i!=active.length-1)
					tmp += L", ";
			}
			SystemMessage(tmp.data());
		} else
			SystemMessage(L"No current participants.");

		msg.SetText(L"");
		//history.SetText(L"");

		// finally request notifications for changes
		AddCustomNotification(bcUser);
		AddCustomNotification(bcGroup);

		return 1;
	} else
		return 0;
}

static TCHAR xxx[10000];

void ChatRoom::FriendMessage(const TCHAR * username, const TCHAR * msg)
{
	_stprintf(xxx,FriendFormat.data(),username,ChatWindow::TranslateMessage(msg));
	SafeSendMessage(hBrowser,WC_APPEND,0,(LPARAM)xxx);
	SafeSendMessage(hBrowser,WC_SCROLL,-1000000,1000000);}

void ChatRoom::MyMessage(const TCHAR * msg)
{
	_stprintf(xxx,MyFormat.data(),(TCHAR*)theApp.user.UserLogin,ChatWindow::TranslateMessage(msg));
	SafeSendMessage(hBrowser,WC_APPEND,0,(LPARAM)xxx);
	SafeSendMessage(hBrowser,WC_SCROLL,-1000000,1000000);}

void ChatRoom::SystemMessage(const TCHAR * msg)
{
	_stprintf(xxx,SystemFormat.data(),ChatWindow::TranslateMessage(msg));
	SafeSendMessage(hBrowser,WC_APPEND,0,(LPARAM)xxx);
	SafeSendMessage(hBrowser,WC_SCROLL,-1000000,1000000);
}

void ChatRoom::OnCarriageReturn(HWND h)
{
	if(h==msg.hWnd){

		if(theApp.user.Away){
			// set to not away anymore
			theApp.SetAwayStatus(0);
		}

		std::wstring message;
		msg.GetText(message);
		msg.SetText(_T(""));
		message.erase(message.end()-2,message.end());

		switch(mode){
			case sendinvite:
				if(rpc.SendGroupMessage(recipientId,recipient.data(),message.data()))
					MyMessage(message.data());
				else {
					SystemMessage(L"Failed to send invitation.");
					print(L"ChatRoom: Failed to send group invitation to %s\n",recipient.data());
				}
				break;
			case rsvp:
				AcceptInvitation();
				// now send the rsvp message
				if(rpc.SendGroupMessage(recipientId,recipient.data(),message.data()))
					MyMessage(message.data());
				else {
					SystemMessage(L"Failed to send message.");
					print(L"ChatRoom: Failed to send group message to %s\n",recipient.data());
				}
				break;
			case accepted:
				if(rpc.SendGroupMessage(recipientId,recipient.data(),message.data()))
					MyMessage(message.data());
				else {
					SystemMessage(L"Failed to send message.");
					print(L"ChatRoom: Failed to send group message to %s\n",recipient.data());
				}
				break;
		}
	}
}

void ChatRoom::OnSize(int cx, int cy)
{
	SkinnableFrame::OnSize(cx,cy);
	history.SetSize(size.Width-2*padding,size.Height-2*padding-100-titlebar.size.Height);
	SetWindowPos(hBrowser,NULL,0,0,history.size.Width,history.size.Height,SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE);
	msg.SetLocation(padding,size.Height-100);
	msg.SetSize(size.Width-2*padding,100-padding);
}

void ChatRoom::OnClose()
{
	theApp.CloseChatRoom(recipient.data());
}

// the interaction states
void ChatRoom::SendInvitation() // the user is expected to enter an invitation message
{
	mode = sendinvite;
}

void ChatRoom::RespondToInvitation() // the user is expected to respond to the invitation message
{
	mode = rsvp;
}

void ChatRoom::AcceptInvitation() // if accepted then a discussion starts
{
	mode = accepted;
	// the user has accepted the invitiation
	// so join the discussion
	db.EnterGroupMeeting(theApp.user.UserId,recipientId);
	rpc.ServerNotifyImmediate(bcGroup,recipientId,bcActive,theApp.user.UserId);
}

void ChatRoom::OnCustomNotify(int id, Notification& n)
{
	TCHAR buffer[1024];
	COleDateTime now = COleDateTime::GetCurrentTime();

	switch(id){
	case bcUser:
		if(members.find(n.param[0])!=-1){
			std::wstring username;
			db.GetCachedUsername(n.param[0],username);
			switch(n.reason){
			case bcLogOn:
				active.insert(n.param[0]);
				_stprintf(buffer,L"%s logged on at %s.",username.data(),now.Format(theApp.DateFormat));
				SystemMessage(buffer);
				break;
			case bcLogOff:
				active.remove(n.param[0]);
				_stprintf(buffer,L"%s logged off at %s.",username.data(),now.Format(theApp.DateFormat));
				SystemMessage(buffer);
				break;
			}
		}	
		break;
	case bcGroup:
		if(n.param[0]==recipientId){
			std::wstring username;
			db.GetCachedUsername(n.param[1],username);
			switch(n.reason){
			case bcActive:
				active.insert(n.param[1]);
				_stprintf(buffer,L"%s has joined the meeting.",username.data());
				SystemMessage(buffer);
				break;
			case bcIdle:
				active.remove(n.param[1]);
				_stprintf(buffer,L"%s has left the meeting.",username.data());
				SystemMessage(buffer);
				break;
			case bcSubscribe:
				members.insert(n.param[1]);
				_stprintf(buffer,L"%s has subscribed to the group.",username.data());
				SystemMessage(buffer);
				break;
			case bcUnsubscribe:
				members.remove(n.param[1]);
				if(active.find(n.param[1])!=-1){
					active.remove(n.param[1]);
					_stprintf(buffer,L"%s has left the meeting.",username.data());
					SystemMessage(buffer);
				}
				break;
			}
		}
		break;
	}
}

