/**
 * @file
 */
#ifndef UI_UTIL_HTTP_CONNECTION_HPP
#define UI_UTIL_HTTP_CONNECTION_HPP

// STDC++
#include <iostream>
#include <string>
#include <vector>

// C++ Libraries
#include <ui-utilcpp/Socket.hpp>
#include <ui-utilcpp/http/Header.hpp>

namespace UI {
namespace Util {
namespace Http {

class Connection
{
private:
	Socket *        const socket_;
	std::iostream * const stream_;
	bool            const externalStream_;

	/** @brief Helper for constructors to destroy internal data on exception. */
	void destroy();
public:
	/** Connection w/ an existing stream. */
	Connection(std::iostream & stream);

	/** Connection w/ an open (socket) file descriptor. */
	Connection(int fd, bool closeFd=false,
	           long int rcvToSeconds=0, long int rcvToMicroseconds=0,
	           long int sndToSeconds=0, long int sndToMicroseconds=0,
	           bool noBlock=false);

	/** Connection w/ an INet peer. */
	Connection(std::string const & host, unsigned int port,
	           long int rcvToSeconds=0, long int rcvToMicroseconds=0,
	           long int sndToSeconds=0, long int sndToMicroseconds=0,
	           bool noBlock=false);

#ifndef WIN32
	/** Connection w/ an UNIX peer. */
	Connection(std::string const & path,
	           long int rcvToSeconds=0, long int rcvToMicroseconds=0,
	           long int sndToSeconds=0, long int sndToMicroseconds=0,
	           bool noBlock=false);
#endif

	~Connection();

	/** @name Get socket information.
	 * @{ */
	std::string getId() const;
	std::string getPeerId() const;
	std::string getConnId() const;
	/** @} */

	/** @name Get stream for arbitrary use.
	 * @{ */
	std::iostream const & s() const;
	std::iostream       & s();
	/** @} */

private:
	std::streamsize readBlock(char * const buf, std::streamsize const & size, bool doThrow=true);

public:
	/** @name Read utilities.
	 * @{ */
	std::string readLine();
	std::streamsize readBlock(std::string & block, std::streamsize const & size, bool doThrow=true);
	std::string readBlock(std::streamsize const & size);
	std::vector<char> readBlockVec(std::streamsize const & size);
	Header & readHeader(Header & header);
	Header readHeader();
	/** @} */

	/** @name Write utilities.
	 * @{ */
	Connection & writeLine(std::string const & line="");
	Connection & write(std::string const & block);
	Connection & write(StatusLine const & statusLine);
	Connection & write(RequestLine const & requestLine);
	Connection & write(HeaderField const & oHeaderField, std::string const & prefix="");
	Connection & write(Header const & header, std::string const & prefix="");
	/** @} */

	/** @name A simple "default" http request. */
	std::string simpleHttpRequest(std::string const & body);
};

}}}
#endif
