/*************************************************************************
 *
 *  $RCSfile: simplecm.hxx,v $
 *
 *  $Revision: 1.19 $
 *
 *  last change: $Author: hr $ $Date: 2003/03/27 17:03:27 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SIMPLECM_HXX
#define _SIMPLECM_HXX

#ifndef _LINK_HXX //autogen
#include <tools/link.hxx>
#endif
#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif
#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#ifndef _VOS_SOCKET_HXX_ //autogen
#include <vos/socket.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif
#ifndef _DATETIME_HXX //autogen
#include <tools/datetime.hxx>
#endif

#include <tools/commdefines.hxx>

// CM steht für CommunicationManager
#define CM_UNLIMITED_CONNECTIONS	0xffff

typedef USHORT CM_NameType;
#define CM_DOTTED	( (CM_NameType) 01 )
#define CM_FQDN		( (CM_NameType) 02 )

typedef USHORT CM_InfoType;
// nur eines dieser 3 defines darf verwendet werden
#define CM_NO_TEXT		( (CM_InfoType) 01 )
#define CM_SHORT_TEXT	( (CM_InfoType) 02 )
#define CM_VERBOSE_TEXT	( (CM_InfoType) 03 )

#define CM_OPEN			( (CM_InfoType) 0x0004 )
#define CM_CLOSE		( (CM_InfoType) 0x0008 )
#define CM_RECEIVE		( (CM_InfoType) 0x0010 )
#define CM_SEND			( (CM_InfoType) 0x0020 )
#define CM_ERROR		( (CM_InfoType) 0x0040 )
#define CM_MISC			( (CM_InfoType) 0x0080 )

#define CM_USER_1		( (CM_InfoType) 0x0100 )
#define CM_USER_2		( (CM_InfoType) 0x0200 )
#define CM_USER_3		( (CM_InfoType) 0x0400 )
#define CM_USER_4		( (CM_InfoType) 0x0800 )

#define CM_ALL			( CM_OPEN | CM_CLOSE | CM_RECEIVE | CM_SEND | CM_ERROR | CM_MISC )
#define CM_NONE			( 0 )

#define CByteString( constAsciiStr ) ByteString( RTL_CONSTASCII_STRINGPARAM ( constAsciiStr ) )

#define INFO_MSG( Short, Long, Type, CLink ) \
{ \
	if ( (Type & GetInfoType()) > 0 ) \
	{ \
		switch ( GetInfoType() & 03 ) \
		{ \
		    case CM_NO_TEXT: \
                { \
       		        ByteString aByteString; \
        	        CallInfoMsg( InfoString( aByteString, Type, CLink ) ); \
                } \
	            break; \
		    case CM_SHORT_TEXT: \
                { \
       		        ByteString aByteString( Short ); \
	                CallInfoMsg( InfoString( aByteString, Type, CLink ) ); \
                } \
	            break; \
		    case CM_VERBOSE_TEXT: \
                { \
       		        ByteString aByteString( Long ); \
	                CallInfoMsg( InfoString( aByteString, Type, CLink ) ); \
                } \
	            break; \
    		default: \
    	        break; \
		} \
	} \
}\

class CommunicationLink;

/*#undef  PRV_SV_DECL_REF_LOCK
#define PRV_SV_DECL_REF_LOCK(ClassName, Ref)	\
protected:										\
    ClassName * pObj;							\
public:											\
PRV_SV_DECL_REF_SIGNATURE(ClassName, Ref)		\
    inline               ClassName##Ref( void * pObjP ){ClassName##Ref ((ClassName *) pObjP);}			\
*/

SV_DECL_REF( CommunicationLink );

class InfoString : public ByteString
{
public:
	InfoString( ByteString &nMsg, CM_InfoType nIT, CommunicationLink *pCL = NULL ): ByteString( nMsg ), nInfoType( nIT ), pCommLink( pCL ) {;}
	CM_InfoType GetInfoType(){ return nInfoType; }
	CommunicationLinkRef GetCommunicationLink(){ return pCommLink; }
private:
	CM_InfoType nInfoType;
	CommunicationLinkRef pCommLink;
};

class PacketHandler;
class CommunicationManager;
class SingleCommunicationManager;
class MultiCommunicationManager;
class CommunicationManagerServerAcceptThread;
class CommunicationLink : public SvRefBase
{
protected:
	friend class CommunicationManager;
	friend class SingleCommunicationManager;
	friend class MultiCommunicationManager;
	friend class CommunicationManagerServerAcceptThread;
	// Darf nicht abgeräumt werden zwischen Empfang des Streams und ende des Callbacks

protected:	// so daß nur über Ref gelöscht werden kann
	virtual ~CommunicationLink();
	void InvalidateManager() { pMyManager = NULL; }

	PacketHandler* pPacketHandler;

public:
	CommunicationLink( CommunicationManager *pMan );

	virtual BOOL StopCommunication()=0;
	virtual BOOL IsCommunicationError()=0;
	CommunicationManager* GetCommunicationManager(){ return pMyManager; }

//	Der Name oder die IP-Adresse oder sonstwas um den Communikationspartner zu identifizieren
	virtual ByteString GetCommunicationPartner( CM_NameType eType )=0;

//	Der Name oder die IP-Adresse oder sonstwas um den Communikationspartner zu identifizieren
	virtual ByteString GetMyName( CM_NameType eType )=0;

//	Liefert einen neuen Stream zum Versenden von Daten.
	virtual SvStream* GetBestCommunicationStream()=0;

	/** will call virtual function DoTransferDataStream to do actual work
		Purpos is to allow housekeeping
	**/
	BOOL TransferDataStream( SvStream *pDataStream, CMProtocol nProtocol = CM_PROTOCOL_OLDSTYLE );

	// Liefert die ID, die vom Sender angegeben wurde.
	// Dadurch lassen sich virtuelle Kommunikationen über einen physikalischen Link realisiren.
	// Da die Kommunikation zu älteren Versionen kompatibel bleiben muß, muß der Empfänger raten,
	// die neue oder die alte verwendet wird, da sich der Kopf eines Auftrages dann ändert.
	UINT16 GetProtocol(){ return nServiceProtocol; }

	// Der Stream wird hier übergeben. Der Aufrufer ist für dessen Löschung zuständig
	// Die Methode MUSS gerufen werden, da sonst keine weiteren Daten empfangen werden.
	SvStream* GetServiceData(){ SvStream *pTemp = pServiceData; pServiceData = NULL; return pTemp; }

	/// Ermöglicht das Auslösen des nächsten Callbacks. Wird auch Implizit gerufen.
	void FinishCallback(){ bIsInsideCallback = FALSE; }

	/// Syncrones Empfangen der Daten. Nur für Kommandozeile, sonst leer implementiert
	virtual BOOL ReceiveDataStream(){ return FALSE; }

	/// Statistics
	DateTime GetStart() { return aStart; }
	ULONG GetTotalBytes() { return nTotalBytes; }
	DateTime GetLastAccess() { return aLastAccess; }
	const ByteString& GetApplication() { return aApplication; }
	virtual void SetApplication( const ByteString& aApp );

protected:
	void CallInfoMsg( InfoString aMsg );
	CM_InfoType GetInfoType();
	CommunicationManager *pMyManager;
// Diese Methoden werden im Main Kontext gerufen und an den Manager weitergereicht.
	virtual DECL_LINK( ConnectionClosed, void* = NULL );
    virtual DECL_LINK( DataReceived, void* = NULL );

	virtual BOOL DoTransferDataStream( SvStream *pDataStream, CMProtocol nProtocol = CM_PROTOCOL_OLDSTYLE );

	SvStream *pServiceData;
	UINT16 nServiceProtocol;
	UINT16 nServiceHeaderType;

	/// Verhindert das vorzeitige Auslösen des nächsten Callbacks.
	void StartCallback(){ bIsInsideCallback = TRUE; }
	BOOL bIsInsideCallback;

	virtual BOOL SendHandshake( HandshakeType aHandshakeType, SvStream* pData = NULL)=0;

	virtual BOOL ShutdownCommunication() = 0;	/// Really stop the Communication

	/// Statistics
	DateTime aStart;
	ULONG nTotalBytes;
	DateTime aLastAccess;
	ByteString aApplication;
};

SV_IMPL_REF( CommunicationLink );

class CommonSocketFunctions;
class CommunicationManager
{
    friend class CommunicationLink;
	friend class CommonSocketFunctions;
public:
	CommunicationManager( BOOL bUseMultiChannel = FALSE );
	virtual ~CommunicationManager();

	virtual BOOL StartCommunication()=0;
	virtual BOOL StartCommunication( String aApp, String aParams ) { return FALSE; }
	virtual BOOL StartCommunication( ByteString aHost, ULONG nPort ){ return FALSE;}
	virtual BOOL StopCommunication()=0;		// Hält alle CommunicationLinks an
	virtual BOOL IsCommunicationRunning() { return bIsCommunicationRunning; }
//	virtual BOOL IsCommunicationError();

//	Der Name oder die IP-Adresse oder sonstwas um den Communikationspartner zu identifizieren
	virtual ByteString GetMyName( CM_NameType eType );

	virtual BOOL IsLinkValid( CommunicationLink* pCL )=0;	// Notwendig für call im Destruktor

	virtual USHORT GetCommunicationLinkCount()=0;
	virtual CommunicationLinkRef GetCommunicationLink( USHORT nNr )=0;

	// Liefert den letzten neuen Link oder NULL wenn dieser schon wieder geschlossen ist.
	CommunicationLinkRef GetLastNewLink() { return xLastNewLink; }

	void SetConnectionOpenedHdl( Link lConnectionOpened ){ mlConnectionOpened = lConnectionOpened; }
	void SetConnectionClosedHdl( Link lConnectionClosed ){ mlConnectionClosed = lConnectionClosed; }
	void SetDataReceivedHdl( Link lDataReceived ){ mlDataReceived = lDataReceived; }
	void SetInfoMsgHdl( Link lInfoMsg ){ mlInfoMsg = lInfoMsg; }

	void SetInfoType( CM_InfoType nIT ){ nInfoType = nIT; }
	CM_InfoType GetInfoType(){ return nInfoType; }

	BOOL IsMultiChannel(){ return bIsMultiChannel; }
	void SetApplication( const ByteString& aApp, BOOL bRunningLinks = FALSE );

protected:
	// Diese Methoden werden innerhalb gerufen. Sie erledigen eventuelles Housekeeping
	// und rufen dann die entsprechende Methode
	virtual void CallConnectionOpened( CommunicationLink* pCL );
	virtual void CallConnectionClosed( CommunicationLink* pCL );
	void CallDataReceived( CommunicationLink* pCL );
	void CallInfoMsg( InfoString aMsg );

	CM_InfoType nInfoType;

	// 	Diese Routinen rufen den Link oder sind überladen
	virtual void ConnectionOpened( CommunicationLink* pCL ){ mlConnectionOpened.Call( pCL ); }
	virtual void ConnectionClosed( CommunicationLink* pCL ){ mlConnectionClosed.Call( pCL ); }
	virtual void DataReceived( CommunicationLink* pCL ){ mlDataReceived.Call( pCL ); }
	virtual void InfoMsg( InfoString aMsg ){ mlInfoMsg.Call( &aMsg ); }

	BOOL bIsCommunicationRunning;

	virtual void DestroyingLink( CommunicationLink *pCL )=0;	// Link trägt sich im Destruktor aus
	ByteString aApplication;

private:
	Link mlConnectionOpened;
	Link mlConnectionClosed;
	Link mlDataReceived;
	Link mlInfoMsg;
	CommunicationLinkRef xLastNewLink;

	BOOL bIsMultiChannel;
};

class SingleCommunicationManager : public CommunicationManager
{
public:
	SingleCommunicationManager( BOOL bUseMultiChannel = FALSE );
	virtual ~SingleCommunicationManager();
	virtual BOOL StopCommunication();		// Hält alle CommunicationLinks an
	virtual BOOL IsLinkValid( CommunicationLink* pCL );
	virtual USHORT GetCommunicationLinkCount();
	virtual CommunicationLinkRef GetCommunicationLink( USHORT nNr );

protected:
	virtual void CallConnectionOpened( CommunicationLink* pCL );
	virtual void CallConnectionClosed( CommunicationLink* pCL );
	CommunicationLinkRef xActiveLink;
	CommunicationLink *pInactiveLink;
	virtual void DestroyingLink( CommunicationLink *pCL );	// Link trägt sich im Destruktor aus
};

class ICommunicationManagerClient
{
	friend class CommonSocketFunctions;
protected:
	virtual BOOL RetryConnect() { return FALSE; }	// Kann dann eventuell die Applikation starten
};

class TCPIO;
class SimpleCommunicationLinkViaSocket : public CommunicationLink
{
public:
	virtual BOOL IsCommunicationError();
	virtual BOOL StopCommunication();

	virtual ByteString GetCommunicationPartner( CM_NameType eType );
	virtual ByteString GetMyName( CM_NameType eType );
	virtual SvStream* GetBestCommunicationStream();
	virtual void SetApplication( const ByteString& aApp );

private:
	ByteString aCommunicationPartner;
	ByteString aMyName;

	TCPIO* pTCPIO;

protected:
	SimpleCommunicationLinkViaSocket( CommunicationManager *pMan, NAMESPACE_VOS(OStreamSocket) *pSocket );
	virtual ~SimpleCommunicationLinkViaSocket();

	NAMESPACE_VOS(OStreamSocket) *pStreamSocket;
	SvStream *pReceiveStream;
	BOOL DoReceiveDataStream();				/// Recieve DataPacket from Socket
	virtual BOOL SendHandshake( HandshakeType aHandshakeType, SvStream* pData = NULL);
	void SetFinalRecieveTimeout();
	BOOL bIsRequestShutdownPending;
	virtual void WaitForShutdown()=0;
	void SetNewPacketAsCurrent();
};

class SimpleCommunicationLinkViaSocketWithReceiveCallbacks : public SimpleCommunicationLinkViaSocket
{
public:
	SimpleCommunicationLinkViaSocketWithReceiveCallbacks( CommunicationManager *pMan, NAMESPACE_VOS(OStreamSocket) *pSocket );
	~SimpleCommunicationLinkViaSocketWithReceiveCallbacks();
	virtual BOOL ReceiveDataStream();
protected:
	virtual BOOL ShutdownCommunication();	/// Really stop the Communication
	virtual void WaitForShutdown();
};

class CommonSocketFunctions
{
public:
	BOOL DoStartCommunication( CommunicationManager *pCM, ICommunicationManagerClient *pCMC, ByteString aHost, ULONG nPort );
protected:
	virtual CommunicationLink *CreateCommunicationLink( CommunicationManager *pCM, NAMESPACE_VOS(OConnectorSocket) *pCS )=0;
};

class SingleCommunicationManagerClientViaSocket : public SingleCommunicationManager, public ICommunicationManagerClient, CommonSocketFunctions
{
public:
	SingleCommunicationManagerClientViaSocket( ByteString aHost, ULONG nPort, BOOL bUseMultiChannel = FALSE );
	SingleCommunicationManagerClientViaSocket( BOOL bUseMultiChannel = FALSE );
	virtual BOOL StartCommunication(){ return DoStartCommunication( this, (ICommunicationManagerClient*) this, aHostToTalk, nPortToTalk );}
	virtual BOOL StartCommunication( ByteString aHost, ULONG nPort ){ return DoStartCommunication( this, (ICommunicationManagerClient*) this, aHost, nPort );}
private:
	ByteString aHostToTalk;
	ULONG nPortToTalk;
protected:
	virtual CommunicationLink *CreateCommunicationLink( CommunicationManager *pCM, NAMESPACE_VOS(OConnectorSocket) *pCS ){ return new SimpleCommunicationLinkViaSocketWithReceiveCallbacks( pCM, pCS ); }
};

#endif
