/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/

#ifndef _SCTS_TRANSPORT_H
#define _SCTS_TRANSPORT_H
#include "SctsThread.h"
#include "SctsURI.h"

#include "xpt.h"
#include <set>
#include <map>
#include <string>

class SctsTransport;
class SctsTransportServer;
class SctsClientTransport;
class SctsServerTransport;
class SctsTransportProfile;
class SctsHttpClientTransport;
class SctsHttpTransportServer;
class SctsHttpServerTransport;
class SctsHttpTransportProfile;
class SctsObexTCPClientTransport;
class SctsObexTCPTransportServer;
class SctsObexTCPServerTransport;
class SctsObexTCPTransportProfile;

typedef enum
{
	HTTP=0,
	OBEXTCP,
	OBEXIR,
	TRANSPORT_COUNT
} SctsSupportedTransport;


typedef enum sctsTransport_s
{
	UNKNOWN_TRANSPORT=0,
#ifdef __SCTS_USING_RTK__
	HTTP_CLIENT,
	HTTP_CLOSE_SERVER,
	HTTP_KEEP_ALIVE_SERVER,
	OBEX_TCP_CLIENT,
	OBEX_TCP_SERVER,
	OBEX_IR_CLIENT,
	OBEX_IR_SERVER
#endif
} SctsTransportType;

#define MAX_SESSION_TIMEOUT 3600000
extern long sctsSessionTimeout;

/******************************************************************/

class SctsTransport
{
public:
	char *mimeType;
	virtual SctsTransportType GetType()=0;
	virtual bool SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo=0)=0;
	virtual bool RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo=0)=0;
	virtual char *GetRespAddr()=0;
	virtual char *GetTransportHdr()=0;
	virtual bool SetRespAddr(SctsURI *respAddr)=0;
	
	SctsTransport(char *_mimeType=0)
	{
		if (_mimeType)
			mimeType=sctsStrdup(_mimeType);
		else
			mimeType=0;
	}
	virtual ~SctsTransport()
	{
		if (mimeType) sctsFree(mimeType);
	}
};

/******************************************************************/
typedef enum
{
	SERVER_RUNNING=0,
	SERVER_STOPPED,
	SERVER_STOPPING,
	SERVER_ERROR
} SctsTransportServerState;

class SctsTransportServer : public SctsThread
{
private:
	static void *uiCallbackData;
	static void (*uiCallback)(void *,SctsTransportServer *,SctsTransportServerState);
protected:
	SctsMutex serverTransportsLock;
	std::set<SctsServerTransport *> serverTransports;
	SctsTransportServerState state;
	void SetState(SctsTransportServerState _state);
public:
	static void SetUICallback(void *_uiCallbackData,void (*)(void *,SctsTransportServer *,SctsTransportServerState));
	void AddServerTransport(SctsServerTransport *transport);
	void RemoveServerTransport(SctsServerTransport *transport);
	void CreateSession(char *mimeType,SctsServerTransport *transport);
	void SetTerminate(bool _terminate);
	virtual ~SctsTransportServer();
	SctsTransportServer::SctsTransportServer();
};

/******************************************************************/

class SctsServerTransport : public SctsTransport
{
protected:
	SctsTransportServer *transportServer;

public:
	SctsServerTransport(char *_mimeType,SctsTransportServer *_transportServer) : SctsTransport(_mimeType)
	{
		SCTSASSERT(_transportServer);
		transportServer=_transportServer;
		transportServer->AddServerTransport(this);
	}

	virtual ~SctsServerTransport()
	{
		SCTSASSERT(transportServer);
		transportServer->RemoveServerTransport(this);
	}
};

/******************************************************************/

class SctsClientTransport : public SctsTransport
{
protected:
	XptHmacInfo_t hmacInfo;
public:
	void FreeHmacInfo()
	{
		sctsFree((char *)hmacInfo.algorithm);
		sctsFree((char *)hmacInfo.username);
		sctsFree((char *)hmacInfo.mac);
		hmacInfo.algorithm=0;
		hmacInfo.username=0;
		hmacInfo.mac=0;
	}
	void SetHmacInfo(XptHmacInfoPtr_t _hmacInfo)
	{
		FreeHmacInfo();
		/* Raj */
		if (!_hmacInfo) return;
		hmacInfo.algorithm=sctsStrdup(_hmacInfo->algorithm);
		hmacInfo.username=sctsStrdup(_hmacInfo->username);
		hmacInfo.mac=sctsStrdup(_hmacInfo->mac);
	}
	void SetMimeType(char *_mimeType) {SCTSASSERT(_mimeType); if (mimeType) sctsFree(mimeType); mimeType=sctsStrdup(_mimeType);}
	SctsClientTransport()
	{
		hmacInfo.algorithm=0;
		hmacInfo.username=0;
		hmacInfo.mac=0;
	}
	virtual ~SctsClientTransport() 
	{
		FreeHmacInfo();
	}
};


/******************************************************************
RTK Transport classes
******************************************************************/
#ifdef __SCTS_USING_RTK__

#include "xpt.h"

/******************************************************************
HTTP
******************************************************************/
class SctsHttpClientTransport : public SctsClientTransport
{
private:
	XptServiceID_t xptServiceID;
	XptProtocolId_t xptProtocolID;
	XptCommunicationID_t xptCommID;
	XptCommunicationInfo_t xptDocInfo;
	SctsURI *serverAddr;
	char *proxyAddr;
public:
	char *lastHttpHeader;
	char *GetRespAddr();
	char *GetTransportHdr();
	bool SetRespAddr(SctsURI *respAddr);
	bool SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo=0);
	bool RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo=0);
	SctsTransportType GetType() {return HTTP_CLIENT;}
	SctsHttpClientTransport(SctsURI *_serverAddr,char *_proxyAddr=0);
	~SctsHttpClientTransport();
};

/******************************************************************/
#ifdef _MSC_VER
extern "C" int xptClose;
#else
extern "C" int xptClose;
#endif


class SctsHttpTransportServer : public SctsTransportServer
{
private:
	XptServiceID_t xptServiceID;
	XptProtocolId_t xptProtocolID;
	XptCommunicationID_t xptCommID;
	int port;
	int Init();
	int Run();
	int Exit()
	{
		xptDeselectProtocol(xptServiceID);
		delete this;
		return 0;
	}
public:
	SctsHttpTransportServer(int _port=80) : xptServiceID(0),xptProtocolID(0),xptCommID(0),port(_port) 
	{	
	}
};

/******************************************************************/
class SctsHttpServerTransport : public SctsServerTransport
{
friend class SctsHttpTransportServer;
private:
	bool firstRecv;
	bool xptClose;
	XptCommunicationID_t xptCommID;
	XptCommunicationID_t nextXptCommID;
	XptCommunicationInfo_t xptDocInfo;
	XptCommunicationInfo_t nextXptDocInfo;
	SctsSemaphore nextXptCommLock;
	SctsURI *respAddr;
public:
	char *lastHttpHeader;
	char *GetRespAddr();
	char *GetTransportHdr();
	bool SetRespAddr(SctsURI *_respAddr);
	bool SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo=0);
	bool RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo=0);
	SctsTransportType GetType() {if (xptClose) return HTTP_KEEP_ALIVE_SERVER;return HTTP_CLOSE_SERVER;}
	SctsHttpServerTransport(char *mimeType,SctsHttpTransportServer *transportServer,XptCommunicationID_t _xptCommID,bool _xptClose,XptCommunicationInfoPtr_t pXptDocInfo);
	~SctsHttpServerTransport();
};

/******************************************************************
OBEX/TCP
******************************************************************/
extern int obexTCPState;
class SctsObexTCPClientTransport : public SctsClientTransport
{
private:
	XptServiceID_t xptServiceID;
	XptProtocolId_t xptProtocolID;
	XptCommunicationID_t xptCommID;
	XptCommunicationInfo_t xptDocInfo;
	SctsURI *respAddr;
	char *hostAddr;
	int port;
public:
	char *GetTransportHdr();
	char *GetRespAddr();
	bool SetRespAddr(SctsURI *respAddr);
	bool SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo=0);
	bool RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo=0);
	SctsTransportType GetType() {return OBEX_TCP_CLIENT;}
	SctsObexTCPClientTransport(char *_hostAddr,int _port);
	~SctsObexTCPClientTransport();
};

/******************************************************************/
class SctsObexTCPTransportServer : public SctsTransportServer
{
friend class SctsObexTCPServerTransport;
private:
	SctsSemaphore obexServerLock;
	XptServiceID_t xptServiceID;
	XptProtocolId_t xptProtocolID;
	XptCommunicationID_t xptCommID;
	int port;
	int Init();
	int Run();
	int Exit()
	{
		xptDeselectProtocol(xptServiceID);
		obexTCPState=0;
		delete this;
		return 0;
	}
public:
	SctsObexTCPTransportServer(int _port) : xptServiceID(0),xptProtocolID(0),xptCommID(0),port(_port),obexServerLock(0,1)
	{
	}
};

#endif

/******************************************************************/
class SctsTransportProfile
{
public:
	SctsSupportedTransport transport;
	virtual char *GetAddress()=0;
	virtual SctsClientTransport *GetTransport()=0;
	virtual void Save(FILE *);
	static SctsTransportProfile *Load(FILE *);
};

/******************************************************************
OBEX/IR
******************************************************************/
extern int obexIRState;
class SctsObexIRClientTransport : public SctsClientTransport
{
private:
	XptServiceID_t xptServiceID;
	XptProtocolId_t xptProtocolID;
	XptCommunicationID_t xptCommID;
	XptCommunicationInfo_t xptDocInfo;
	SctsURI *respAddr;
	char *serviceName;
public:
	char *GetTransportHdr();
	char *GetRespAddr();
	bool SetRespAddr(SctsURI *respAddr);
	bool SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo=0);
	bool RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo=0);
	SctsTransportType GetType() {return OBEX_IR_CLIENT;}
	SctsObexIRClientTransport(char *_serviceName);
	~SctsObexIRClientTransport();
};

/******************************************************************/
class SctsObexIRTransportServer : public SctsTransportServer
{
friend class SctsObexServerTransport;
private:
	SctsSemaphore obexServerLock;
	XptServiceID_t xptServiceID;
	XptProtocolId_t xptProtocolID;
	XptCommunicationID_t xptCommID;
	char *serviceName;
	int Init();
	int Run();
	int Exit()
	{
		xptDeselectProtocol(xptServiceID);
		obexIRState=0;
		delete this;
		return 0;
	}
	~SctsObexIRTransportServer()
	{
		sctsFree(serviceName);
	}
public:
	SctsObexIRTransportServer(char *_serviceName) : xptServiceID(0),xptProtocolID(0),xptCommID(0),obexServerLock(0,1)
	{
		serviceName=sctsStrdup(_serviceName);
	}
};

/******************************************************************/
class SctsObexServerTransport : public SctsServerTransport
{
friend class SctsObexIRTransportServer;
friend class SctsObexTCPTransportServer;
private:
	SctsSemaphore *obexServerLock;
	XptCommunicationID_t xptCommID;
	XptHmacInfoPtr_t xptHmacInfo;
	SctsURI *respAddr;
	bool firstRecv;
public:
	char *GetTransportHdr();
	char *GetRespAddr();
	bool SetRespAddr(SctsURI *_respAddr);
	bool SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo=0);
	bool RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo=0);
	SctsTransportType GetType() {return OBEX_IR_SERVER;}
	SctsObexServerTransport(char *mimeType,SctsTransportServer *transportServer,XptCommunicationID_t _xptCommID,XptHmacInfoPtr_t _xptHmacInfo);
	~SctsObexServerTransport();
};

/******************************************************************/
class SctsHttpTransportProfile  : public SctsTransportProfile
{
public:
	SctsURI serverAddress;
	char *proxyAddress;
	char *GetAddress()
	{
		return serverAddress.Build();
	}
	SctsClientTransport *GetTransport()
	{
		return new SctsHttpClientTransport(&serverAddress,proxyAddress);
	}
	SctsHttpTransportProfile(SctsURI& _serverAddress,char *_proxyAddress=0)
		:serverAddress(_serverAddress)
	{
		transport=HTTP;
		if (_proxyAddress)
			proxyAddress=sctsStrdup(_proxyAddress);
		else
			proxyAddress=0;
	}
	SctsHttpTransportProfile(FILE *);
	void Save(FILE *);
};

/******************************************************************/
class SctsObexTCPTransportProfile  : public SctsTransportProfile
{
public:
	char *hostAddr;
	int port;
	char *GetAddress()
	{
		return sctsStrdup(hostAddr);
	}
	SctsClientTransport *GetTransport()
	{
		return new SctsObexTCPClientTransport(hostAddr,port);
	}
	SctsObexTCPTransportProfile(char *_hostAddr,int _port)
	{
		transport=OBEXTCP;
		hostAddr=sctsStrdup(_hostAddr);
		port=_port;
	}
	SctsObexTCPTransportProfile(FILE *);
	void Save(FILE *);
};

/******************************************************************/
class SctsObexIRTransportProfile  : public SctsTransportProfile
{
public:
	char *serviceName;
	char *GetAddress()
	{
		return sctsStrdup(serviceName);
	}
	SctsClientTransport *GetTransport()
	{
		return new SctsObexIRClientTransport(serviceName);
	}
	SctsObexIRTransportProfile(char *_serviceName)
	{
		transport=OBEXIR;
		serviceName=sctsStrdup(_serviceName);
	}
	SctsObexIRTransportProfile(FILE *);
	void Save(FILE *);
};

#endif
