//
// posix_chat_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include "chat_message.hpp"

#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)

using boost::asio::ip::tcp;
namespace posix = boost::asio::posix;

class posix_chat_client
{
public:
  posix_chat_client(boost::asio::io_service& io_service,
      tcp::resolver::iterator endpoint_iterator)
    : socket_(io_service),
      input_(io_service, ::dup(STDIN_FILENO)),
      output_(io_service, ::dup(STDOUT_FILENO)),
      input_buffer_(chat_message::max_body_length)
  {
    // Try connecting to the first endpoint.
    tcp::endpoint endpoint = *endpoint_iterator;
    socket_.async_connect(endpoint,
        boost::bind(&posix_chat_client::handle_connect, this,
          boost::asio::placeholders::error, ++endpoint_iterator));
  }

private:

  void handle_connect(const boost::system::error_code& error,
      tcp::resolver::iterator endpoint_iterator)
  {
    if (!error)
    {
      // Read the fixed-length header of the next message from the server.
      boost::asio::async_read(socket_,
          boost::asio::buffer(read_msg_.data(), chat_message::header_length),
          boost::bind(&posix_chat_client::handle_read_header, this,
            boost::asio::placeholders::error));

      // Read a line of input entered by the user.
      boost::asio::async_read_until(input_, input_buffer_, '\n',
          boost::bind(&posix_chat_client::handle_read_input, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else if (endpoint_iterator != tcp::resolver::iterator())
    {
      // That endpoint didn't work, try the next one.
      socket_.close();
      tcp::endpoint endpoint = *endpoint_iterator;
      socket_.async_connect(endpoint,
          boost::bind(&posix_chat_client::handle_connect, this,
            boost::asio::placeholders::error, ++endpoint_iterator));
    }
  }

  void handle_read_header(const boost::system::error_code& error)
  {
    if (!error && read_msg_.decode_header())
    {
      // Read the variable-length body of the message from the server.
      boost::asio::async_read(socket_,
          boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
          boost::bind(&posix_chat_client::handle_read_body, this,
            boost::asio::placeholders::error));
    }
    else
    {
      close();
    }
  }

  void handle_read_body(const boost::system::error_code& error)
  {
    if (!error)
    {
      // Write out the message we just received, terminated by a newline.
      static char eol[] = { '\n' };
      boost::array<boost::asio::const_buffer, 2> buffers = {{
        boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
        boost::asio::buffer(eol) }};
      boost::asio::async_write(output_, buffers,
          boost::bind(&posix_chat_client::handle_write_output, this,
            boost::asio::placeholders::error));
    }
    else
    {
      close();
    }
  }

  void handle_write_output(const boost::system::error_code& error)
  {
    if (!error)
    {
      // Read the fixed-length header of the next message from the server.
      boost::asio::async_read(socket_,
          boost::asio::buffer(read_msg_.data(), chat_message::header_length),
          boost::bind(&posix_chat_client::handle_read_header, this,
            boost::asio::placeholders::error));
    }
    else
    {
      close();
    }
  }

  void handle_read_input(const boost::system::error_code& error,
      std::size_t length)
  {
    if (!error)
    {
      // Write the message (minus the newline) to the server.
      write_msg_.body_length(length - 1);
      input_buffer_.sgetn(write_msg_.body(), length - 1);
      input_buffer_.consume(1); // Remove newline from input.
      write_msg_.encode_header();
      boost::asio::async_write(socket_,
          boost::asio::buffer(write_msg_.data(), write_msg_.length()),
          boost::bind(&posix_chat_client::handle_write, this,
            boost::asio::placeholders::error));
    }
    else if (error == boost::asio::error::not_found)
    {
      // Didn't get a newline. Send whatever we have.
      write_msg_.body_length(input_buffer_.size());
      input_buffer_.sgetn(write_msg_.body(), input_buffer_.size());
      write_msg_.encode_header();
      boost::asio::async_write(socket_,
          boost::asio::buffer(write_msg_.data(), write_msg_.length()),
          boost::bind(&posix_chat_client::handle_write, this,
            boost::asio::placeholders::error));
    }
    else
    {
      close();
    }
  }

  void handle_write(const boost::system::error_code& error)
  {
    if (!error)
    {
      // Read a line of input entered by the user.
      boost::asio::async_read_until(input_, input_buffer_, '\n',
          boost::bind(&posix_chat_client::handle_read_input, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else
    {
      close();
    }
  }

  void close()
  {
    // Cancel all outstanding asynchronous operations.
    socket_.close();
    input_.close();
    output_.close();
  }

private:
  tcp::socket socket_;
  posix::stream_descriptor input_;
  posix::stream_descriptor output_;
  chat_message read_msg_;
  chat_message write_msg_;
  boost::asio::streambuf input_buffer_;
};

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 3)
    {
      std::cerr << "Usage: posix_chat_client <host> <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    tcp::resolver resolver(io_service);
    tcp::resolver::query query(argv[1], argv[2]);
    tcp::resolver::iterator iterator = resolver.resolve(query);

    posix_chat_client c(io_service, iterator);

    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

#else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
int main() {}
#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
