//SmallSocket.cpp
/*
Copyright (C) 2004  Anders Hedstrom

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

//#include <stdio.h>
#include <Parse.h>
#include "SmallHandler.h"
#include "World.h"
#include "cstring.h"
#include "ItemFactory.h"
#include "SmallSocket.h"




SmallSocket::SmallSocket(SocketHandler& h)
:TcpSocket(h)
,m_state(STATE_LOGIN)
,m_name("")
,m_x(0)
,m_y(0)
,m_player(NULL)
{
	SetLineProtocol();
}


SmallSocket::~SmallSocket()
{
}


void SmallSocket::Send(const std::string& str)
{
	cstring q;
	q = str;
	TcpSocket::Send( q.c_str() );
}


void SmallSocket::OnAccept()
{
	Send("&WWelcome.&n\n");
	SendPrompt();
}


void SmallSocket::OnLine(const std::string& line)
{
	switch (m_state)
	{
	case STATE_LOGIN:
		// check player
		//  exist - ask password STATE_PASSWORD
		//  don't exist - ask new player question STATE_NEW_PLAYER_QUESTION
		m_player = GetPlayerF().FindPlayer(line, "");
		if (m_player)
		{
			m_state = STATE_PASSWORD;
		}
		else
		{
			m_name = line;
			m_state = STATE_NEW_PLAYER_QUESTION;
		}
		SendPrompt();
		break;
	case STATE_PROMPT:
		if (line.size())
		{
			Parse pa(line);
			std::string cmd = pa.getword();

			if (line[0] == 34 || line[0] == '\'')
			{
				static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " says '" + line.substr(1) + "'\n",this);
				Send("You say '" + line.substr(1) + "&n'\n");
			}
			else
			if (line[0] == '!')
			{
				static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " shouts '" + line.substr(1) + "'\n",this,true);
				Send("You shout '" + line.substr(1) + "&n'\n");
			}
			else
			if (line == "n" || line == "s" || line == "e" || line == "w")
			{
				try_move(line);
				static_cast<SmallHandler&>(Handler()).ShowCell(this);
			}
			else
			if (line == "l")
			{
				static_cast<SmallHandler&>(Handler()).ShowCell(this);
			}
			else
			if (line == "who")
			{
				static_cast<SmallHandler&>(Handler()).Who(this);
			}
			else
			if (line == "quit")
			{
				m_state = STATE_QUIT;
			}
			else
			if (cmd == "get")
			{
				TryGet(this, pa.getrest());
			}
			else
			if (cmd == "drop")
			{
				TryDrop(this, pa.getrest());
			}
			else
			if (line == "i")
			{
				m_player -> DisplayInventory(this);
			}
			else
			if (line == "status")
			{
				static_cast<SmallHandler&>(Handler()).ShowStatus(this);
			}
			else
			if (line == "help")
			{
				Send("n / s / e / w - move around\n");
				Send("l - look around\n");
				Send("get / drop <item>\n");
				Send("i - display inventory\n");
				Send("' / \" - talk ( as in >\"hi )\n");
				Send("! - shout ( as in >!Hello anyone??? )\n");
				Send("who - is online\n");
				Send("status - show game status\n");
				Send("help\nquit\n");
			}
			else
			{
				Send("Command not recognized - try '&Whelp&n'\n");
			}
		}
		SendPrompt();
		break;
	case STATE_QUIT:
		break;
	case STATE_PASSWORD:
		if (line == m_player -> m_passwd)
		{
			std::string str;
			m_name = m_player -> m_name;
			m_state = STATE_PROMPT;
			GetWorld().GetRandomLocation(m_x,m_y,str);
			Send("Welcome back, " + m_player -> m_name + ".\n");
			Send("You wake up in a room: " + str + "\n");
		}
		else
		{
			m_state = STATE_LOGIN;
		}
		SendPrompt();
		break;
	case STATE_NEW_PLAYER_QUESTION:
		if (!line.size() || line[0] == 'y' || line[0] == 'Y')
		{
			m_state = STATE_PASSWORD_1;
		}
		else
		{
			m_state = STATE_LOGIN;
		}
		SendPrompt();
		break;
	case STATE_PASSWORD_1:
		if (line.size() > 3)
		{
			m_passwd = line;
			m_state = STATE_PASSWORD_2;
		}
		else
		{
			Send("Enter at least 4 characters.\n");
		}
		SendPrompt();
		break;
	case STATE_PASSWORD_2:
		if (line == m_passwd)
		{
			m_player = GetPlayerF().AddPlayer(m_name,m_passwd);
			m_state = STATE_PASSWORD;
			OnLine(line);
			GetPlayerF().Save();
		}
		else
		{
			Send("Password mismatch - try again\n");
			m_state = STATE_NEW_PLAYER_QUESTION;
			SendPrompt();
		}
		break;
	}
}


void SmallSocket::SendPrompt()
{
	switch (m_state)
	{
	case STATE_LOGIN:
		Send("Enter name: ");
		break;
	case STATE_PROMPT:
		Send("> ");
		break;
	case STATE_QUIT:
		Send("Goodbye!\n");
		SetCloseAndDelete();
		break;
	case STATE_PASSWORD:
		Send("Enter password: ");
		break;
	case STATE_NEW_PLAYER_QUESTION:
		Send("Create a new player (Y,n)? ");
		break;
	case STATE_PASSWORD_1:
		Send("Enter new player password: ");
		break;
	case STATE_PASSWORD_2:
		Send("Repeat password: ");
		break;
	}
}


bool SmallSocket::IsAt(int x,int y)
{
	if (m_x == x && m_y == y)
		return true;
	return false;
}


void SmallSocket::try_move(const std::string& dir)
{
	std::string name;
	bool n,s,e,w;
	GetWorld().GetAt(m_x,m_y,name,n,s,e,w);
	if (dir == "n")
	{
		if (n && GetWorld().FindAt(m_x,m_y - 1,name))
		{
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " leaves north\n",this);
			m_y--;
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " enters from the south\n",this);
			return;
		}
	}
	else
	if (dir == "s")
	{
		if (s && GetWorld().FindAt(m_x,m_y + 1,name))
		{
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " leaves south\n",this);
			m_y++;
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " enters from the north\n",this);
			return;
		}
	}
	else
	if (dir == "e")
	{
		if (e && GetWorld().FindAt(m_x + 1,m_y,name))
		{
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " leaves east\n",this);
			m_x++;
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " enters from the west\n",this);
			return;
		}
	}
	else
	if (dir == "w")
	{
		if (w && GetWorld().FindAt(m_x - 1,m_y,name))
		{
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " leaves west\n",this);
			m_x--;
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " enters from the east\n",this);
			return;
		}
	}
	Send("&ROuch!&n\n");
}


void SmallSocket::TryGet(SmallSocket *sendto,const std::string& item)
{
	item_v& ref = static_cast<SmallHandler&>(Handler()).GetItems(m_x,m_y);
	item_v& ref_to = m_player -> GetInventory();
	for (item_v::iterator it = ref.begin(); it != ref.end(); it++)
	{
		ITEM *i = *it;
		bool ok;
		if (i -> m_amount > 1)
		{
			ok = !strcmp(i -> m_plural.uc_str(), item.c_str());
		}
		else
		{
			ok = !strcmp(i -> m_name.uc_str(), item.c_str());
		}
		if (ok)
		{
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " picks up " + i -> GetDescription() + "\n",this);
			Send("You pick up " + i -> GetDescription() + "\n");
			static_cast<SmallHandler&>(Handler()).MergeItem(ref_to,i);
			ref.erase(it);
			break;
		}
	}
}


void SmallSocket::TryDrop(SmallSocket *sendto,const std::string& item)
{
	item_v& ref = m_player -> GetInventory();
	item_v& ref_to = static_cast<SmallHandler&>(Handler()).GetItems(m_x,m_y);
	for (item_v::iterator it = ref.begin(); it != ref.end(); it++)
	{
		ITEM *i = *it;
		bool ok;
		if (i -> m_amount > 1)
		{
			ok = !strcmp(i -> m_plural.uc_str(), item.c_str());
		}
		else
		{
			ok = !strcmp(i -> m_name.uc_str(), item.c_str());
		}
		if (ok)
		{
			static_cast<SmallHandler&>(Handler()).Event(m_x,m_y,m_name + " drops " + i -> GetDescription() + "\n",this);
			Send("You drop " + i -> GetDescription() + "\n");
			static_cast<SmallHandler&>(Handler()).MergeItem(ref_to,i);
			ref.erase(it);
			break;
		}
	}
}