/*
   net/netconnection.cc
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#ifndef __INCLUDED_CORE_NETCONNECTION_H__
#define __INCLUDED_CORE_NETCONNECTION_H__

#include "core/net.h"

#include <unistd.h>
#include <errno.h>

#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/select.h>
#include <netdb.h>
#endif

#include <string>
#include <deque>
#include <map>

#include "core/entity.h"
#include "core/net.h"
#include "core/info.h"

namespace core
{

/**
 * @brief client-side network methods
 * This class contains the necessary methods for the client-side
 * of network communication. It handles both sending and receiving.
 **/
class NetConnection
{
public:
	NetConnection();
	virtual ~NetConnection();

	/// connect to a remote host
	virtual void connect(std::string const &to_host, int to_port);

	/// disconnect from a remote host
	virtual void disconnect();

	/// process pending incoming messages
	void frame();

	/// send a connect message to the remote server
	void send_connect();

	/// send a player info message to the remote server
	void send_playerinfo();

	/// send a client update message to the remote server
	void send_client_update(Entity *entity);

	/// send an entity request
	void send_entity_request(Entity *entity);

	/// send a local chat message
	void send_say(std::string const &text);
	
	/// send a public chat message
	void send_shout(std::string const &text);

	/// send a private message
	void send_private_message(std::string const &text);

	/// send a command line to the remote server
	void send_command(std::string const &cmdline);

	/// send a console command to the remote server
	void send_rcon(std::string const &cmdline);

	/// send an info request
	void send_info_request(Info *info);
	
	/// send an inventory udpate request
	void send_inventory_request(Entity *entity);

	/// transmit messages in the send queue to the remote server
	void transmit();

	void abort();

	inline int fd() const {
		return connection_fd;
	}

	inline std::string host() const {
		return connection_host;
	}

	inline int port() const {
		return connection_port;
	}

	inline bool valid() const {
		return (connection_fd != -1);
	}

	inline bool invalid() const {
		return (connection_fd == -1);
	}

	inline bool error() const {
		return connection_error;
	}

	inline bool connected() const {
		return ((connection_fd != -1) && !connection_error);
	}

	enum State {Connecting = 0, Pending = 1, Connected = 2};

	inline State state() const {
		return connection_state;
	}

	State connection_state;

	/// return the current game time
	inline unsigned long timestamp() const {
		return connection_timestamp;
	}

protected:
	/// send a ping reply
	void send_ping_reply(unsigned long timestamp);

	/// add a raw network message to the send queue
	void send_raw(std::string const &msg);

	/// receive incoming data and store messages
	void receive();

	/// return true if there are incoming messages
	bool has_messages() const;

	/// retreive an incoming message
	void retreive(std::string & message);

	/// parse an incoming message
	void parse_incoming_message(const std::string & message);

private:
	std::string		messageblock;
	std::deque<std::string>	recvq;
	std::string		sendq;
	fd_set			clientset;

	float			connection_timeout;
	float			connection_keepalive;
	int			connection_fd;
	bool			connection_error;
	std::string		connection_host;
	int			connection_port;
	struct sockaddr_in 	server_addr;
	char			recvbuf[BLOCKSIZE];

	bool			receive_compressed;
	size_t			received_compressed_size;
	size_t			compressed_size;
	char			zrecvbuf[BLOCKSIZE];

	unsigned long		connection_timestamp;
};

}

#endif // __INCLUDED_CORE_NETCONNECTION_H__