// Local configuration
#include "config.h"

// STDC++
#include <string>
#include <memory>
#include <iostream>
#include <exception>
#include <cassert>

// C++ library
#include <ui-utilcpp/auto_ptr_compat.hpp>
#include <ui-utilcpp/Socket.hpp>
#include <ui-utilcpp/Thread.hpp>

std::string const unSock("/tmp/ui-utilcpp-echoserver.sock");
std::string const inHost("localhost");
unsigned int const inPort(9999);

void client(UI::Util::Socket & client)
{
	std::cout << "Connected: " << client.getId() << "->" << client.connect().getPeerId() << std::endl;

	UI::Util::FDTypeStream<UI::Util::Socket> clientStream(client.getFd());
	clientStream << "12345" << std::flush;
	clientStream.clear();
	std::string response;
	clientStream >> response;
	std::cout << "Response: \"" << response << "\"" << std::endl;
}

void server(UI::Util::Socket & server)
{
	std::cout << "Listening: " << server.bind().listen().getId() << std::endl;
	std::cout << "Echoing first 5 bytes on each connect." << std::endl;

	while (1)
	{
		UI::Util::Socket connection(server.accept());
		assert(connection.getFd() != -1);
		std::cout << "Connection: " << connection.getId() << "<-" << connection.getPeerId() << " (setting snd/rcv timeout on connections 5 seconds)" << std::endl;
		connection.
			setRcvTimeout(5).
			setSndTimeout(5);

		UI::Util::FDTypeStream<UI::Util::Socket> stream(connection.getFd(), true);
		char line[6];
		stream.read(line, 5);
		assert(stream.gcount() == 5);
		line[5] = '\0';

		std::cout << "ECHOING: " << line << std::endl;

		stream.write(line, 5);
	}
}

int main(int argc, char *argv[])
{
	try
	{
		if (argc < 3) { throw UI::Exception("Wrong usage"); };

		UI::Util::auto_ptr<UI::Util::Socket> socket((std::strcmp(argv[1], "unix") == 0) ?
		                                            (UI::Util::Socket *) new UI::Util::UnixSocket(unSock, true) :
		                                            (UI::Util::Socket *) new UI::Util::INetSocket(inHost, inPort, true, true));

		std::strcmp(argv[2], "server") == 0 ? server(*socket.get()) : client(*socket.get());
	}
	catch (std::exception const & e)
	{
		std::cerr << "Error: " << e.what() << "." << std::endl;
		std::cerr << "Usage: ui-utilcpp-echoserver inet|unix client|server" << std::endl;
		return 1;
	}
	return 0;
}
