#ifndef _StreamSocket_H
#define _StreamSocket_H

#include "lib/types.h"
#include "ps/Pyrogenesis.h"
#include "Network.h"
#include "SocketBase.h"

/**
 * A class implementing Async I/O on top of the non-blocking event-driven
 * CSocketBase
 */
class CStreamSocket: public CSocketBase
{
	CMutex m_Mutex;
	char *m_pConnectHost;
	int m_ConnectPort;
	
	struct SOperationContext
	{
		bool m_Valid;
		void *m_pBuffer;
		uint m_Length;
		uint m_Completed;

		inline SOperationContext():
			m_Valid(false)
		{}
	};
	SOperationContext m_ReadContext;
	SOperationContext m_WriteContext;

protected:
	friend void *CStreamSocket_ConnectThread(void *);

	CStreamSocket(CSocketInternal *pInt);

	/**
	 * Set the required socket options on the socket.
	 */
	void SetSocketOptions();

	/**
	 * The destructor will disconnect the socket and free any OS resources.
	 */
	virtual ~CStreamSocket();

	virtual void OnRead();
	virtual void OnWrite();

public:
	CStreamSocket();

	/**
	 * The Lock function locks a mutex stored in the CStreamSocket object. None
	 * of the CStreamSocket methods actually use the mutex, it is just there as
	 * a convenience for the user.
	 */
	void Lock();
	/**
	 * The Unlock function unlocks a mutex stored in the CStreamSocket object.
	 * None of the CSocket methods actually use the mutex, it is just there as a
	 * convenience for the user.
	 */
	void Unlock();
	
	/**
	 * Begin a connect operation to the specified host and port. The connect
	 * operation and name resolution is performed in the background and the
	 * ConnectComplete callback is called when the connect is complete/failed
	 *
	 * Note that a PS_OK return only means that the connect operation has been
	 * initiated, not that it is successful.
	 *
	 * @param hostname A hostname or an IP address of the remote host
	 * @param port The TCP port number in host byte order
	 *
	 * @return PS_OK - The connect has been initiated
	 */
	PS_RESULT BeginConnect(const char *hostname, int port);

	/**
	 * Start a read operation. The function call will return immediately and
	 * complete the I/O in the background. OnRead() will be called when it is
	 * complete. Until the Read is complete, the buffer should not be touched.
	 * There can only be one read operation in progress at one time.
	 *
	 * Inputs
	 *	buf		A pointer to the buffer where the data should be written
	 *	len		The length of the buffer. The amount of data the function should
	 *			try to read.
	 *
	 * Returns
	 *	PS_OK	Some or all data was successfully read.
	 *	CONFLICTING_OP_IN_PROGRESS Another Read operation is alread in progress
	 *	CONNECTION_BROKEN	The socket is not connected or a server socket
	 */	
	PS_RESULT Read(void *buf, uint len);
	
	/**
	 * Start a Write operation. The function call will return immediately and
	 * the I/O complete in the background. OnWrite() will be called when i has
	 * completed. Until the Write is complete, the buffer shouldn't be touched.
	 * There can only be one write operation in progress at one time.
	 *
	 * @param buf A pointer to the buffer of data to write
	 * @param len The length of the buffer.
	 *
	 * Returns
	 *	PS_OK	Some or all data was successfully read.
	 *	CONFLICTING_OP_IN_PROGRESS	Another Write operation is in progress
	 *	CONNECTION_BROKEN	The socket is not connected or a server socket
	 */	
	PS_RESULT Write(void *buf, uint len);
	
	// The default implementation of these methods are no-ops
	virtual void ConnectComplete(PS_RESULT errorCode);
	virtual void ReadComplete(PS_RESULT errorCode);
	virtual void WriteComplete(PS_RESULT errorCode);
	virtual void OnClose(PS_RESULT errorCode);
};

#endif
