#include <iostream>

using namespace std;

#include <boost/bind.hpp>
#include <boost/asio.hpp>

using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;

class Client
{
public:
	Client(io_service& io_service):
	  _socket(io_service)
	{
	}

	tcp::socket& socket()
	{
		return _socket;
	}

	void startReceive()
	{
		_socket.async_read_some(buffer(_data, max_length),
			bind(&Client::handleRead, this,
				placeholders::error,
				placeholders::bytes_transferred));
	}

	void close()
	{
		_socket.close();
	}

	void send(string message)
	{
		memcpy(_data, message.c_str(), message.length()+1);

		async_write(_socket, buffer(_data, max_length),
			bind(&Client::handleWrite, this,
				placeholders::error,
				placeholders::bytes_transferred));
	}

private:

	void handleRead(const system::error_code& error,
		size_t bytes_transferred)
	{
		cout<<"handleRead"<<endl;

		if (!error)
		{
			cout<<bytes_transferred<<" bytes received"<<endl;

			async_write(_socket,
				buffer(_data, bytes_transferred),
				bind(&Client::handleWrite, this,
					placeholders::error,
					placeholders::bytes_transferred));

			startReceive();
		}
		else
		{
			cout<<"Client disconnected"<<endl;
			delete this;
		}
	}

	void handleWrite(const system::error_code& error,
		size_t bytes_transferred)
	{
		cout<<"handleWrite"<<endl;

		if (!error)
		{
			cout<<bytes_transferred<<" bytes sent"<<endl;
		}
		else
		{
			cout<<"Client disconnected"<<endl;
			delete this;
		}
	}

	tcp::socket _socket;

	static const int max_length = 1024;
	char _data[max_length];
};

class Network
{
public:
	Network():
		_acceptor(_service, tcp::endpoint(tcp::v4(), 1026))
	{
		startAccept();
	}
   
	void update()
	{
		_service.run_one();
	}

private:
	void startAccept()
	{
		Client* client = new Client(_acceptor.io_service());

		_acceptor.async_accept(client->socket(),
			bind(&Network::handleAccept, this, client,
			placeholders::error));
	}

	void handleAccept(Client* client, const system::error_code& error)
	{
		if (!error)
		{
			cout<<"Client connected from "<<client->socket().remote_endpoint().address().to_string()<<endl;

			client->startReceive();
			startAccept();
		}
		else
		{
			cout<<"Accept error"<<endl;
			startAccept();
		}
	}

	io_service _service;
	tcp::acceptor _acceptor;
};

int main()
{
  try
  {
    Network network;

	while(true)
	{
		network.update();
	}
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }

  return 0;
}

