// PNSocket.h: interface for the CPNSocket class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_PNSOCKET_H__1A3533C8_EA58_11D3_9F5C_080009EE62AA__INCLUDED_)
#define AFX_PNSOCKET_H__1A3533C8_EA58_11D3_9F5C_080009EE62AA__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#pragma warning(disable: 4786)
#include <map>
// disable warning C4786: symbol greater than 255 character,
// okay to ignore

using namespace std;

// The MSocket class
class CPNSocket
{
public:
	CPNSocket( int nFamily=AF_INET, int nType=SOCK_STREAM, int nProtocol=0 );
	CPNSocket( const CPNSocket& msSrc );	// Copy Constructor
	~CPNSocket();

	int Close();

	// Socket operations (Client)
	int Connect( struct sockaddr * sapSrvrAdrs, int nLenAddr ) const;
	int Connect( const char* szHostAddr, short sPort  ) const;

	// Socket operation (Server)
	int Bind( struct sockaddr * sapSrvrAdrs, int nLenAddr ) const;
	int Bind( int nPort, int nFamily=AF_INET, int nAddr=INADDR_ANY) const;
	int Listen( int nBackLog=5 ) const;
	int Server( int nPort ) const; // Helper Function
	int Accept( CPNSocket& msrRet, struct sockaddr* sapClientAddr=0, int* npLen=0 ) const;

	// Atributes for normal- or exception-mode error reporting
	static bool m_bThrowException;
	static bool SetExceptions( bool bMode );

	// Operators
	CPNSocket& operator=( CPNSocket& msrSrc );
	CPNSocket& operator=( int Socket );

	// I/O functions
	int SetTimeOut( int MilliSeconds );
	int Receive( char *cpDest, int nSize, char Term='\r' ) const;
	int CPNSocket::ReceiveLine( char *cpDest, int nSize ) const;
	int Send( const char *cpSrc, int Len ) const;
	int SendLine( const char* cpSrc, char Term='\n' ) const;

	// Helper functions
	void ThrowErrMsg( const char* cpMsg, int nCode=0 ) const;
	void ThrowErrMsg( const char* cpMsg, const char* cpInfo ) const { ThrowErrMsg( cpMsg, (int) cpInfo); }
	static bool WasConTermErr( const char* ErrMsg );
	const char* CPNSocket::GetErrMsg() const;
	
	// Typecast operator, so you can use this class anywhere you need a normal socket handle.
	operator int() { return( m_nSocket ); }
protected:
	SOCKET m_nSocket;
	long m_nTimeOut;
	char HostName[128];

	enum toMode { toRead, toWrite, toError };
	int TimedOut( toMode Mode ) const;

	// Support for reference counting, using STL map class
	static map<int,int> RefCount;
	void IncRef()
	{ if( RefCount.find( m_nSocket )!=RefCount.end() ) RefCount[m_nSocket]++; else RefCount[m_nSocket]=1; }
	void DecRef()
	{ if( RefCount.find( m_nSocket )!=RefCount.end() ) RefCount[m_nSocket]--; }
	bool GetRef()
	{ return( RefCount.find(m_nSocket)!=RefCount.end()? (RefCount[m_nSocket]?true:false): false ); }

};


#endif // !defined(AFX_MSOCKET_H__1A3533C8_EA58_11D3_9F5C_080009EE62AA__INCLUDED_)
