#include "main.h"



size_t TUser::NextId = 0;


//HIMKI
float BaseLon = 37.443195f;
float BaseLat = 55.888869f;
int BaseZoom = 12;

/*
//SPB
float BaseLon = 30.2158f;
float BaseLat = 60.0052f;
int BaseZoom = 12;

*/

TUser::TUser(TServer& server)
	: Id(NextId++)
	, Server(server)
	, Socket(server.Service)
{

}

void TUser::Delete()
{
	std::vector<boost::shared_ptr<TUser> >::iterator i = std::find(Server.UserArr.begin(), Server.UserArr.end(), shared_from_this());

	Server.UserArr.erase(i);
}

void TUser::HandleReadUserLoginResponce(const boost::system::error_code& error)
{
	if (!error)
	{

		if (check_func(LoginQuestion) == LoginQuestionResult)
		{
			//Autorization ok

			boost::asio::async_write(Socket, boost::asio::buffer(&CONST_OK[0], 2), boost::bind(&TUser::HandleCheckError, shared_from_this(), boost::asio::placeholders::error));
		
			boost::asio::async_write(Socket, boost::asio::buffer(&CONST_OK[0], 2), boost::bind(&TUser::HandleCheckError, shared_from_this(), boost::asio::placeholders::error));
			boost::asio::async_write(Socket, boost::asio::buffer(&BaseLon, 4), boost::bind(&TUser::HandleCheckError, shared_from_this(), boost::asio::placeholders::error));
			boost::asio::async_write(Socket, boost::asio::buffer(&BaseLat, 4), boost::bind(&TUser::HandleCheckError, shared_from_this(), boost::asio::placeholders::error));
			boost::asio::async_write(Socket, boost::asio::buffer(&BaseZoom, 4), boost::bind(&TUser::HandleCheckError, shared_from_this(), boost::asio::placeholders::error));
		

			boost::asio::async_read(Socket, boost::asio::buffer(&LastSignal, 4), boost::bind(&TUser::HandleReadSignal, shared_from_this(), boost::asio::placeholders::error));
	
		}
		else
		{
			//Force close

			Socket.close();
			Delete();
		}

	}
	else
	{
		Delete();
	}
}

void TUser::HandleCheckError(const boost::system::error_code& error)
{
	if (error)
	{
		Delete();
	}
}

void TUser::HandleReadSignal(const boost::system::error_code& error)
{
	if (!error)
	{
		if (LastSignal == 3 || LastSignal == 4 || LastSignal == 5) 
		{
			boost::asio::async_read(Socket, boost::asio::buffer(&ReadDataLenLong, 4), boost::bind(&TUser::HandleReadDataLen, shared_from_this(), boost::asio::placeholders::error));
		}
		if (LastSignal == 1)
		{
			std::vector<char> mapData = Server.CreateMapData();

			boost::shared_ptr<TMessageSender>(new TMessageSender(Socket, 1, mapData))->Send();

			boost::asio::async_read(Socket, boost::asio::buffer(&LastSignal, 4), boost::bind(&TUser::HandleReadSignal, shared_from_this(), boost::asio::placeholders::error));
		}
		if (LastSignal == 2)
		{
			std::vector<char> mapData = Server.CreateAlarmMapData();

			boost::shared_ptr<TMessageSender>(new TMessageSender(Socket, 2, mapData))->Send();

			boost::asio::async_read(Socket, boost::asio::buffer(&LastSignal, 4), boost::bind(&TUser::HandleReadSignal, shared_from_this(), boost::asio::placeholders::error));

		}
		if (LastSignal == 100)
		{
			boost::asio::async_read(Socket, boost::asio::buffer(&ReadDataLenLong, 4), boost::bind(&TUser::HandleReadDataLen, shared_from_this(), boost::asio::placeholders::error));
		}
	}
	else
	{
		Delete();
	}
}

void TUser::HandleReadDataLen(const boost::system::error_code& error)
{
	if (!error)
	{
		ReadData.resize(ReadDataLenLong);
		if (ReadDataLenLong == 0)
		{
			boost::asio::async_read(Socket, boost::asio::buffer(&LastSignal, 4), boost::bind(&TUser::HandleReadSignal, shared_from_this(), boost::asio::placeholders::error));
		}
		else
		{
			boost::asio::async_read(Socket, boost::asio::buffer(ReadData), boost::bind(&TUser::HandleReadData, shared_from_this(), boost::asio::placeholders::error));
		}
	}
	else
	{
		Delete();
	}
}

void TUser::HandleReadData(const boost::system::error_code& error)
{
	if (!error)
	{
		if (LastSignal == 4)
		{
			std::string msg;
			DecodeMessage(ReadData, UserInfo, msg);
			Server.BroadcastMessage(CONST_SIGNAL_MESSAGE, ReadData);
		}
		if (LastSignal == 3)
		{
			DecodeProfileUpdateQuery(ReadData, UserInfo);
		}
		if (LastSignal == 5)
		{
			DecodeHeartBeatQuery(ReadData, UserInfo);
		}
		if (LastSignal == 100)
		{
			std::string lastName;
			std::string firstName;
			std::string middleName;
			DecodeKickPlayerSignal(ReadData, lastName, firstName, middleName);

			if (IsAdmin())
			{
				if (lastName != "" || firstName != "" || middleName != "")
				{
					int playerToDelete = -1;
					for (int i=0; i<Server.UserArr.size(); i++)
					{
						if ((lastName == "" || Server.UserArr[i]->UserInfo.LastName == lastName) &&
							(firstName == "" || Server.UserArr[i]->UserInfo.FirstName == firstName) &&
							(middleName == "" || Server.UserArr[i]->UserInfo.MiddleName == middleName))
						{
							playerToDelete = i;
							
							
						}
					}

					if (playerToDelete != -1)
					{
						//Server.UserArr[playerToDelete]->ForceClose();
						
						//If kick himself
						if (Server.UserArr[playerToDelete] == shared_from_this())
						{
							Server.UserArr.erase(Server.UserArr.begin()+playerToDelete);
							return;
						}
						else
						{
							Server.UserArr.erase(Server.UserArr.begin()+playerToDelete);
						}
					}
				}
			}

		}
		boost::asio::async_read(Socket, boost::asio::buffer(&LastSignal, 4), boost::bind(&TUser::HandleReadSignal, shared_from_this(), boost::asio::placeholders::error));
	}
	else
	{
		Delete();
	}
}


bool TUser::IsAdmin()
{
	//Call-Center
	if (UserInfo.LastName.size() <= 11)
	{
		return false;
	}

	std::string lastName_part1 = std::string(UserInfo.LastName.begin(), UserInfo.LastName.begin()+11);
	
	std::string lastName_part2 = std::string(UserInfo.LastName.begin()+11, UserInfo.LastName.end());

	if (lastName_part1 == "Call-Center")
	{
		if (lastName_part2 == UserInfo.FirstName)
		{
			return true;
		}
	}

	return false;
}

void TUser::ForceClose()
{
	Socket.close();
	Delete();
}

void TServer::StartAccept()
{
	boost::shared_ptr<TUser> newUser(new TUser(*this));
	
	Acceptor.async_accept(newUser->Socket, boost::bind(&TServer::HandleAccept, this, newUser, boost::asio::placeholders::error));
}


void TServer::HandleAccept(boost::shared_ptr<TUser> user, const boost::system::error_code& error)
{
	if (!error)
    {
		UserArr.push_back(user);

		user->LoginQuestion = rand();

		boost::asio::async_write(user->Socket, boost::asio::buffer(&(user->LoginQuestion), 4), boost::bind(&TUser::HandleCheckError, user, boost::asio::placeholders::error));

		boost::asio::async_read(user->Socket, boost::asio::buffer(&(user->LoginQuestionResult), 4), boost::bind(&TUser::HandleReadUserLoginResponce, user, boost::asio::placeholders::error));

    }

    StartAccept();
}

void TServer::BroadcastMessage(int messageType, std::vector<char> messageData)
{
	for (std::vector<boost::shared_ptr<TUser> >::iterator i = UserArr.begin(); i != UserArr.end(); ++i)
	{
		boost::shared_ptr<TMessageSender>(new TMessageSender((*i)->Socket, messageType, messageData))->Send();
	}
}

std::vector<char> TServer::CreateMapData()
{
	std::vector<char> result;

	for (std::vector<boost::shared_ptr<TUser> >::iterator i = UserArr.begin(); i != UserArr.end(); ++i)
	{
		std::vector<char> beatQuery(CreateHeartBeatQuery((*i)->UserInfo));
		result.insert(result.end(), beatQuery.begin(), beatQuery.end());
	}

	return result;
}

std::vector<char> TServer::CreateAlarmMapData()
{
	std::vector<char> result;

	for (std::vector<boost::shared_ptr<TUser> >::iterator i = UserArr.begin(); i != UserArr.end(); ++i)
	{
		//if ((*i)->UserInfo.MapState >= CONST_MAP_STATE_ALARM)
		{
			std::vector<char> beatQuery(CreateProfileUpdateQuery((*i)->UserInfo));
			result.insert(result.end(), beatQuery.begin(), beatQuery.end());
		}
	}

	return result;
}

int main()
{
	srand(static_cast<unsigned int>(time(0)));

	std::cout<<"K-observer server started"<<std::endl;

	#ifndef _WIN32
	daemonize();
	#endif

	boost::asio::io_service io_service;

	boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 1984);

	boost::shared_ptr<TServer> Server(new TServer(io_service, endpoint));

	io_service.run();

	return 0;
}