#ifndef _xbSOCKETITF_
#define _xbSOCKETITF_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbSocketItf
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbPTR_
#	include "xbPtr.h"
#endif

#ifndef _xbHOTPLUG_
#	include "xbHotPlug.h"
#endif

enum xbSocketCtx
{
	xbSocketUnknown = 0,
	xbSocketConnect = 1,
	xbSocketRead = 2,
	xbSocketWrite = 3,
	xbSocketAccept = 4,
	xbSocketClose = 5,
	xbSocketCloseSig = 6 //Close signal (socket already closed)
};

extern xbHotPlugType xbEXPORT	g_xbSocketPlugType;
extern xbMsg xbEXPORT			xbWMCTRL_WINSOCK_NOTIF;

xbEXPORT extern int xbSocketGetPort(const xbString &szPort,xbString *pRes = NULL,xbOpMode opMode = xbOp_Required);

interface __declspec(uuid("{83BA60F2-9A11-487d-B12C-D5D1E567D984}"))
	xbEXPORT sIxbNotifLock
{
	virtual void NotifLock() = 0;
	virtual void NotifUnlock() = 0;
};

interface __declspec(uuid("{963E2717-C00C-4ed6-B20D-F9F4A9510E2D}")) 
	xbEXPORT IxbSocketEv:public IxbObject
{
	virtual void Set() = 0;
	virtual void Reset() = 0;
	virtual bool IsAutoReset() const = 0;
	virtual void Pulse() = 0;
	virtual HANDLE GetHandle() = 0;
};

enum xbSocketType
{
	xbSocketType_STREAM = 0,
	xbSocketType_MESSAGE = 1
};

interface __declspec(uuid("{301BE619-5B6E-42ad-BD39-FD187B475F8F}")) 
	xbEXPORT IxbSocket:public IxbObject
{
	virtual bool GetEvents(bool bResetEvent = true) = 0; 
	virtual bool HasConnectEvent() = 0;
	virtual int GetConnectError() = 0;
	virtual bool HasAcceptEvent() = 0;
	virtual int GetAcceptError() = 0;
	virtual bool HasCloseEvent() = 0;
	virtual int GetCloseError() = 0;
	virtual bool HasReadEvent() = 0;
	virtual int GetReadError() = 0;
	virtual bool HasWriteEvent() = 0;
	virtual int GetWriteError() = 0;

	virtual int	GetReceivedDataSize() = 0;
	virtual int ReadData(void *ptr, int sz, int flags) = 0;

	virtual int	WriteData(const void *ptr, int sz, int flags) = 0;
	virtual bool WriteFlush(bool *pbFlushPartial) = 0;
	virtual bool WriteNoDelay(bool bFlg) = 0;

	virtual int ReadDataFrom(void *ptr, int sz, int flags,xbString *pAddrFrom) = 0;
	virtual int	WriteDataTo(const void *ptr, int sz, int flags,const xbString &addrTo) = 0;
	virtual xbSocketType	GetSocketType() const = 0;
	virtual int	GetSocketMessageMaxSize() const = 0;

	//...Event... functions return :
	//	-2 -> IO_COMPLETION
	//	-1 -> TimeOut
	//	0 -> Socket event signaled (if any)
	//n:1 to cEv or arrEv.Length -> ppEv[n-1] or arrEv[n] signaled. 
	virtual int EventWait(long timeout,HANDLE *pEv,int cEv,bool bProcessMsg = true) = 0;

	virtual void AttachEvent(IxbSocketEv *pEvSock) = 0;
	virtual bool SignalEvent() = 0;

	virtual xbString	GetPeerIP(xbString *pPort = NULL) = 0;
	virtual xbString	GetSockIP(xbString *pPort = NULL) = 0;

	virtual void askDestroy(LPCSTR pReason) = 0;
	virtual void askClose(LPCSTR pReason) = 0;
	virtual bool askShutDown(LPCSTR pReason) = 0;

	virtual xbString getCloseReason() const = 0;
	virtual xbString getShutDownReason() const = 0;

	virtual bool GetErrorMsg(LPCSTR pFmt,xbString *pErrorMsg, xbString *pErrorCtx = NULL,bool bReset = true) = 0;

	virtual xbString	closeReasonLabel(bool bLfAfter = true) const
	{
		xbString ret(getCloseReason());
		if (ret.IsEmpty())
			return ret;
		return "(reason: "+ret+(bLfAfter?")\n":")");
	}

	virtual bool SocketOptionGet(LPCSTR pOptionName,xbString *pOptionValue,xbOpMode opm =xbOp_Required,int cRawByteOrArg = 0) const = 0;
	virtual bool SocketOptionSet(LPCSTR pOptionName,LPCSTR pOptionValue,xbOpMode opm =xbOp_Required,int cRawByteOrArg = 0) = 0;
};

interface __declspec(uuid("{AFF88638-14EE-47a7-B8B0-A7C58596AAE4}")) 
	xbEXPORT IxbSocketPlug:public IxbObject
{
	virtual xbString GetHostName() const = 0;
	virtual xbString GetHostNameByAddr(const xbString &addr,xbOpMode opm =xbOp_Required) const = 0;
	virtual xbString GetHostAddrByName(const xbString &name,xbOpMode opm =xbOp_Required) const = 0;
	virtual int GetHostNameByAddr(const xbString &addr,xbArray<xbString> *pArrName,xbOpMode opm =xbOp_Required) const = 0;
	virtual int GetHostAddrByName(const xbString &name,xbArray<xbString> *pArrAddr,xbOpMode opm =xbOp_Required) const = 0;

	virtual void EventCreate(xbRefPtr<IxbSocketEv> *ppEv,bool bAutoReset = false) = 0;
	
	virtual bool CanWorkWithPort(const xbString &szPort) const = 0;

	virtual void SocketConnect(IxbSocketEv *pEvSock,const xbString &szHost,const xbString &szPort,xbRefPtr<IxbSocket> *ppSock,LPCSTR pszHostSrce = NULL,LPCSTR pszPortSrce = NULL) = 0;
	virtual void SocketListen(IxbSocketEv *pEvSock,const xbString &szPort,LPCSTR pszHost,xbRefPtr<IxbSocket> *ppSock) = 0;
	virtual bool SocketAccept(IxbSocketEv *pEvSock,IxbSocket *pSockListening,xbRefPtr<IxbSocket> *ppSock,xbString *pAcceptedIP = NULL,xbString *pAcceptedPort = NULL) = 0;

	virtual void askClose(LPCSTR pReason) = 0;
	virtual xbString getCloseReason() const = 0;
	virtual xbString	closeReasonLabel(bool bLfAfter = true) const
	{
		xbString ret(getCloseReason());
		if (ret.IsEmpty())
			return ret;
		return "(reason: "+ret+(bLfAfter?")\n":")");
	}

	virtual bool SocketOptionGet(LPCSTR pOptionName,xbString *pOptionValue,xbOpMode opm =xbOp_Required,int cRawByteOrArg = 0) const = 0;
	virtual bool SocketOptionSet(LPCSTR pOptionName,LPCSTR pOptionValue,xbOpMode opm =xbOp_Required,int cRawByteOrArg = 0) = 0;

	virtual void Duplicate(xbRefPtr<IxbSocketPlug> *pPlug) = 0;
};

class xbEXPORT xbNotifLock
{
public:
	xbNotifLock()
	{
		m_pSock = NULL;
	}
	xbNotifLock(sIxbNotifLock *pSock)
	{
		m_pSock = NULL;
		Lock(pSock);
	}
	~xbNotifLock()
	{
		eProtect(Unlock());
	}
	void Lock(sIxbNotifLock *pSock)
	{
		if (m_pSock) Unlock();
		pSock->NotifLock();
		m_pSock = pSock;
	}
	void Unlock()
	{
		if (!m_pSock) return;
		sIxbNotifLock	*pSock = m_pSock;
		m_pSock = NULL;
		pSock->NotifUnlock();
	}
protected:
	sIxbNotifLock	*m_pSock;
};

//Exception xbEsocket: to use by sockets to signal system errors
xbEdclStart(xbEsocket,xbEadv,{5BB5C690-6D64-411a-8357-4A4419C31197},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Network system error";} 
xbEdclEnd(xbEsocket);

//Exception xbEsocketUser: to use by sockets to signal "user" errors (host not reachable, connection closed, ...)
xbEdclStart(xbEsocketUser,xbEsocket,{F93DBE12-2AC2-47c6-939B-257F5BA90AD7},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Exclamation;}
	virtual const char *GetMBoxTitle() const {return "Network error";} 
xbEdclEnd(xbEsocketUser);

#endif
