// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#ifndef _GAVDPINTERNAL_H
#define _GAVDPINTERNAL_H

#include <gavdp.h>
#include "gavdpinterface.h"
#include "e32debug.h"

class CGavdpHelper;

NONSHARABLE_CLASS(CGavdp) : public CBase
{
friend class CGavdpHelper;
friend class CGavdpDiscover;
friend class CGavdpStart;
friend class CGavdpGetCaps;
friend class CGavdpAbort;
friend class CGavdpSuspend;
friend class CGavdpSelectSEP;
friend class CGavdpConnector;
//friend class CGavdpPassiveSignallingConnector;
friend class CGavdpIndicator;
friend class CGavdpUPlaneConnector;

public:
	static CGavdp* NewL(MGavdpUser& aServiceUser, RSocketServ& aSocketServer, RGavdp& aHandle);
	~CGavdp();

	TInt Listen();

	void Cancel();
	
	void Connect(const TBTDevAddr& aRemoteAddr);
	void DiscoverRemoteSEPs();
	void GetRemoteSEPCapabilities(TSEID aSEID, const TAvdtpServiceCategories& aInterestedCategories);

	TInt RegisterSEP(TAvdtpSEPInfo& aInfo); // SEID will be written back

	TInt BeginConfiguringRemoteSEP(TSEID aRemoteSEID, TSEID aLocalSEID);
	TInt BeginConfiguringLocalSEP(TSEID aSEID);
	TInt AddSEPCapability(const TAvdtpServiceCapability& aCapability);
	void CommitSEPConfiguration();
	
	void StartStream(TSEID aSEID);
	void SuspendStream(TSEID aSEID);
	void AbortStream(TSEID aSEID);
	
	void SendSecurityControl(TSEID aSEID, const TDesC8& aSecurityData);
	
	TInt CreateBearerSockets(TSEID aSEID);

	inline RSocket&	AvdtpRequester(); // not available for use outside DLL because we define the inline in the cpp
	inline RSocket&	AvdtpIndicator(); // not available for use outside DLL because we define the inline in the cpp
	inline RSocketServ& AvdtpSession(); // not available for use outside DLL because we define the inline in the cpp
	
	TInt Shutdown();
private:
	CGavdp(MGavdpUser& aServiceUser, RSocketServ& aSocketServer, RGavdp& aHandle);
	void ConstructL();	
	void ConstructSocketsAndHelpersL();
	void DeAllocSocketsAndHelpers();
	void SendResponse(TInternalAvdtpAirIndication aIndication,
					  TInt aResult,
					  const TAny* aResponseData=NULL,
					  TInt aResponseDataLen=0);
	void ServiceComplete(TInt aResult); // cleans up helpers and shift RGavdp statemachine
	void BindSignallingL(const TBTDevAddr& aRemoteAddr);
	void BindBearersL(TSEID aSEID, TBool aRequireReporting, TBool aRequireRecovery);
	inline TBool CheckSEID(TSEID aSEID);
	void Error(TInt aError);
	void FatalError();
private:
	enum TGavdpState
		{
		EIdle,
		EConfiguringLocalSEP,
		EConfiguringRemoteSEP,
		EListening,
		EConnecting,
		EConnected,
		};
private:
	RSocketServ		iSocketServer;
	RSocket			iAvdtpRequester;
	RSocket			iAvdtpIndicator;
	CGavdpHelper*	iRequesterHelper;
	CGavdpHelper*	iIndicatorHelper;
	TGavdpState		iState;
	RSocketServ&	iClientSocketServer;
	MGavdpUser&		iServiceUser;
	TInt			iNumSEPsRegistered;
	RGavdp&			iHandle;
	};

/**
Faults - GAVDP itself has failed
**/	
enum TGavdpFault
	{
	EGavdpHelperTryingToUseNullGavdp,
	EGavdpUnexpectedAvdtpError,
	EGavdpHelperCompletingBadly,
	};
	
static void Panic(TGavdpPanic aPanic)
// Panic client due to programming error.
	{
	_LIT(KGavdpPanicName, "GAVDP Usage error");
	RDebug::Print(_L("%S panic=%d"), &KGavdpPanicName, aPanic);
	User::Panic(KGavdpPanicName, aPanic);
	}

static void Fault(TGavdpFault aFault)
// Panic due to GAVDP fault
	{
	_LIT(KGavdpFaultName, "GAVDP fault");
	User::Panic(KGavdpFaultName, aFault);
	}


NONSHARABLE_CLASS(CGavdpHelper) : public CActive
	{
public:
	virtual void Begin() =0;
protected:
	CGavdpHelper(CGavdp& aGavdp, MGavdpUser& aUser);
	TInt RunError(TInt aError);
	inline RSocket& AvdtpRequester();
	inline RSocket& AvdtpIndicator();
	inline RSocketServ& AvdtpSession();
	void CheckFailedL();
	void DetachFromGavdp(TInt aError);
	inline CGavdp& Gavdp(); // not const because of return
	inline MGavdpUser& User(); // not const because of return
private:
	CGavdp*			iGavdp;	// NULL once helper s free-running
	MGavdpUser&		iUser;
	};
	
/**
Helper that enables indications to be raised by AVDTP
As a current imlpementation, this constantly queues ioctls
(AVDTP assists by queing them too)
@internalComponent
*/
NONSHARABLE_CLASS(CGavdpIndicator) : public CGavdpHelper
	{
public:
	static CGavdpIndicator* NewL(CGavdp& aGavdp, MGavdpUser& aUser);
	virtual void Begin();
	~CGavdpIndicator();
private:
	CGavdpIndicator(CGavdp& aGavdp, MGavdpUser& aUser);
	void RunL();
	TInt RunError(TInt aError);
	void DoCancel();
	void CheckClientResult(TInt aResult);
private:
	TBuf8<KAvdtpMaxInternalIndicationSize> iIndication;
	};
	
	
NONSHARABLE_CLASS(CGavdpDiscover) : public CGavdpHelper
	{
public:
	static CGavdpDiscover* NewL(CGavdp& aGavdp, MGavdpUser& aUser);
	virtual void Begin();
	~CGavdpDiscover();
private:
	CGavdpDiscover(CGavdp& aGavdp, MGavdpUser& aUser);
	void RunL();
	void DoCancel();
private:
	TPckgBuf<TAvdtpInternalDiscoverConfirm>	iConfirm;
	};
	

NONSHARABLE_CLASS(CGavdpGetCaps) : public CGavdpHelper
	{
public:
	static CGavdpGetCaps* NewL(CGavdp& aGavdp,
				 			  MGavdpUser& aUser,
				 			  TSEID aSEID,
				 			  TAvdtpServiceCategories aInterestingCategories);
	virtual void Begin();
	~CGavdpGetCaps();
private:
	CGavdpGetCaps(CGavdp& aGavdp, MGavdpUser& aUser,
					TSEID aSEID, TAvdtpServiceCategories aInterestingCategories);
	void ConstructL();
	void RunL();
	void DoCancel();
private:
	HBufC8*					iSEPCapBuf; // general input and output from socket, hence not typed
	TPtr8					iSEPCapPtr;
	TSEID					iSEID;
	TAvdtpServiceCategories iInteresting;
	};
	

NONSHARABLE_CLASS(CGavdpAbort) : public CGavdpHelper
	{
public:
	static CGavdpAbort* NewL(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSEID);
	
	virtual void Begin();
	~CGavdpAbort();
private:
	CGavdpAbort(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSEID);
	void RunL();
	void DoCancel();
private:
	TPckgBuf<TSEID> iSEID;
	};


NONSHARABLE_CLASS(CGavdpStart) : public CGavdpHelper
	{
public:
	static CGavdpStart* NewL(CGavdp& aGavdp,
					  		  MGavdpUser& aUser,
					  		  TSEID aSeid);
					  		   			  
	virtual void Begin();
	~CGavdpStart();
private:
	CGavdpStart(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSeid);
	void RunL();
	void DoCancel();
private:			
	TPckgBuf<TSEID>	iSeidPckg;
	};


NONSHARABLE_CLASS(CGavdpSuspend) : public CGavdpHelper
	{
public:
	static CGavdpSuspend* NewL(CGavdp& aGavdp,
					  			  MGavdpUser& aUser,
					  			  TSEID aSeid);
					  		   			  
	virtual void Begin();
	~CGavdpSuspend();
private:
	CGavdpSuspend(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSeid);
	void RunL();
	void DoCancel();
private:			
	TPckgBuf<TSEID>	iSeidPckg;
	};

NONSHARABLE_CLASS(CGavdpSecurityControl) : public CGavdpHelper
	{
public:
	static CGavdpSecurityControl* NewL(CGavdp& aGavdp,
					  		  MGavdpUser& aUser,
					  		  TSEID aSeid,
					  		  const TDesC8& aSecurityControl);
					  		   			  
	virtual void Begin();
	~CGavdpSecurityControl();
private:
	CGavdpSecurityControl(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSeid,
					  		  const TDesC8& aSecurityControl);
	void RunL();
	void DoCancel();
private:			
	TPckgBuf<TAvdtpInternalSendSecurityControl>	iSecurityControlPckgBuf;
	};

NONSHARABLE_CLASS(CGavdpSelectSEP) : public CGavdpHelper
	{
public:
	static CGavdpSelectSEP* NewL(CGavdp& aGavdp, MGavdpUser& aUser);
	
	virtual void Begin();
	~CGavdpSelectSEP();
private:
	CGavdpSelectSEP(CGavdp& aGavdp, MGavdpUser& aUser);
	void RunL();
	void DoCancel();
private:
	TPckgBuf<TAvdtpConfigReject> iRejDataBuf; // in case we get rejected by peer
	};


NONSHARABLE_CLASS(CGavdpConnector) : public CGavdpHelper
	{
public:
	static CGavdpConnector* NewL(CGavdp& aGavdp, MGavdpUser& aUser, const TBTDevAddr& aAddr);
	
	virtual void Begin();
	~CGavdpConnector();
private:
	CGavdpConnector(CGavdp& aGavdp, MGavdpUser& aUser, const TBTDevAddr& aAddr);
	void RunL();
	void DoCancel();
private:
	TAvdtpSockAddr	iSocketAddress;
	};

class CGavdpUPlaneConnector;

NONSHARABLE_CLASS(CSocketConnector) : public CActive
	{
public:
	static CSocketConnector* NewL(CGavdpUPlaneConnector& aParent,
									RSocketServ& aSocketServer,
									const TAvdtpSockAddr& aSockAddr);
	inline RSocket& Socket(); // return type => non-const method
	inline const TAvdtpSockAddr& Address() const;
	virtual void RunL();
	virtual void DoCancel();
	~CSocketConnector();
	void Begin();
private:
	CSocketConnector(CGavdpUPlaneConnector& aParent,
									RSocketServ& aSocketServer,
									const TAvdtpSockAddr& aSockAddr);
	void ConstructL();
private:
	CGavdpUPlaneConnector& iParent;
	RSocket iSocket;
	RSocketServ& iSocketServer;
	TAvdtpSockAddr iSockAddr;
	};
	
inline RSocket& CSocketConnector::Socket()
	{
	return iSocket;
	}
	
inline const TAvdtpSockAddr& CSocketConnector::Address() const
	{
	return iSockAddr;
	}

	
NONSHARABLE_CLASS(CGavdpUPlaneConnector) : public CGavdpHelper
	{
public:
	static CGavdpUPlaneConnector* NewL(CGavdp& aGavdp, MGavdpUser& aUser,
								 	   const TAvdtpSockAddr& aAddr,
									   TBool aRequireReporting,
									   TBool aRequireRecovery,
						  			   RSocketServ& aClientSession);
	
	virtual void Begin();
	void ConnectComplete(TInt aErr);
	~CGavdpUPlaneConnector();
private:
	CGavdpUPlaneConnector(CGavdp& aGavdp,
						  MGavdpUser& aUser,
						  const TAvdtpSockAddr& aAddr,
						  TBool aRequireReporting,
						  TBool aRequireRecovery,
						  RSocketServ& aClientSession);
	void RunL();
	void DoConnectComplete(TInt aErr);
	void DoCancel();
	void AllBearersReadyL();
	void ConstructL(TBool aRequireReporting, TBool aRequireRecovery);
private:
	TFixedArray<CSocketConnector*,ENumStreamTypes> iSocketConnectors;
	RSocketServ&	iClientSession;
	TInt			iNumBearersRequired;
	TAvdtpSockAddr	iAddress; // just has remote BT Addr and SEID
	};
	
inline RSocket& CGavdp::AvdtpRequester()
	{
	return iAvdtpRequester;
	}

inline RSocket& CGavdp::AvdtpIndicator()
	{
	return iAvdtpIndicator;
	}
	
inline RSocketServ& CGavdp::AvdtpSession()
	{
	return iSocketServer;
	}

inline RSocket& CGavdpHelper::AvdtpRequester()
	{
	return Gavdp().AvdtpRequester();
	}

inline RSocket& CGavdpHelper::AvdtpIndicator()
	{
	return Gavdp().AvdtpIndicator();
	}
	
inline RSocketServ& CGavdpHelper::AvdtpSession()
	{
	return Gavdp().AvdtpSession();
	}
		
inline CGavdp& CGavdpHelper::Gavdp()
	{
	// free running helpers cannot interact with GAVDP
	__ASSERT_ALWAYS(iGavdp, Fault(EGavdpHelperTryingToUseNullGavdp));
	return *iGavdp;
	}
	
#endif // _GAVDPINTERNAL_H

