#ifndef __SOCKET_WRAPPER_H_INCLUDED__
#define __SOCKET_WRAPPER_H_INCLUDED__

class tcp_base_socket;
class tcp_socket;
class output_formatter;
class input_formatter;

// The sock_wrapper class encapsulates a socket handle and I/O
// formatters. It includes a reference count so that the socket will
// be closed and the formatters deleted when the last reference is
// deleted. This class is all private because it may only be
// manipulated by its friends.

using namespace std;

class socket_wrapper {

  private:
	socket_handle sockhand;	// Socket handle
	int refcount;			// Reference count

	output_formatter *outf;	// Output formatter, if any
	input_formatter *inf; 	// Input formatter, if any
	int abort_recv_socket;		// Write 1 to this socket to abort recv operation
	int abort_send_socket;		// Write 1 to this socket to abort send operation
	int recv_abortable(void *buf, std::size_t len, int flags);
	int send_abortable(const void *buf, std::size_t len, int flags);

  public:
	// CONSTRUCTORS

	// Create from a socket handle (-1 indicates an unopen socket)
	socket_wrapper(socket_handle s = -1);


	// DESTRUCTOR

	~socket_wrapper();


	// METHODS

	// Increment or decrement the reference count
	void inc_refcount();
	int dec_refcount();

	// Create the underlying socket
	void open();

	// Is the socket open?
	bool is_open() const;

	// Test if socket is open, throw an exception if not
	void test_open() const;

	// Close the socket handle if it is open
	void close_if_open();

	// Fetch the socket handle
	socket_handle get_socket_handle() const;

	// Read data from the socket, using the input formatter
	int recv_format(void *buf, std::size_t len, int flags);

	// Send data to the socket, using the output formatter
	int send_format(const void *buf, std::size_t len, int flags);

	// Read raw data from the socket
	int recv_noformat(void *buf, std::size_t len, int flags);

	// Send raw data to the socket
	int send_noformat(const void *buf, std::size_t len, int flags);

	// Set an output formatter
	void set_output_formatter(output_formatter *outform);

	// Set an input formatter
	void set_input_formatter(input_formatter *inform);

	// Abort operation, if possible
	void abort();

	// PREVENT COPYING

  private:
	// Copy constructor. Must not be implemented because
	// this object must never be copied.
	socket_wrapper(socket_wrapper& sw);

	// Assignment operator. Must not be implemented
	// because this object must never be copied.
	const socket_wrapper& operator=(const socket_wrapper& rhs);
};

#endif  // __SOCKET_WRAPPER_H_INCLUDED__
