// Copyright (c) 2006-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 PHYSICALLINKSMANAGER_H_
#define PHYSICALLINKSMANAGER_H_

#include "MBtHostControllerEventInternalNotifier.h"
#include "linkmuxer.h"
#include "linkmgr.h"
#include "bluetooth/physicallinksstate.h"
#include "RegistryHelpers.h"
#include "pairingscache.h"

#include <bt_sock.h>

static const TInt KBTBasebandConnectionArrayGranularity = 4;
static const TInt KBTStateChangeSubscriberArrayGranularity = 2;

class CBTBasebandModel;
class CHCIFacade;
class CBTSecMan;
class RBTRegServ;
class CPhysicalLink;
class CBTProxySAP;
class MPINCodeResponseHandler;
class MLinkKeyResponseHandler;
class MLogicalLink;

struct TLogicalLinkListener;
class CRoleSwitcher;
class CRoleSwitcherStateFactory;

NONSHARABLE_CLASS(TPageTimeoutController) : public MHCICommandQueueClient
	{
public:
	TPageTimeoutController(MHCICommandQueue& aCommandQueue);
	void Abort();

	void WritePageTimeout(TBasebandTime aPageTimeout);

private:	// events from MHCICommandQueueClient
	virtual void MhcqcCommandEventReceived(const THCIEventBase& aEvent, const CHCICommandBase* aRelatedCommand);
	virtual void MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand);

private:
	void WritePageTimeoutL(TBasebandTime aPageTimeout);

private:
	MHCICommandQueue&	iCommandQueue;
	TInt				iOutstandingCommands;
	TInt				iLastCommandId;
	};


NONSHARABLE_CLASS(CBluetoothPrefetchManager)
	: public CBase
	, public MPINCodeResponseHandler
	{
public:
	static CBluetoothPrefetchManager* NewL();
	~CBluetoothPrefetchManager();

	TInt HandleOverPinRequester(const TBTDevAddr& aAddr, CBTPinRequester* aPinRequester);
	TInt RegisterForPrefetching(const TBTDevAddr& aAddr, MBluetoothPrefetchNotifier& aNotifier);

	TBool GetPrefetch(const TBTDevAddr& aAddr, TBTPinCode& aPinCode) const;
	void RemovePrefetch(const TBTDevAddr& aAddr);

private:
	NONSHARABLE_CLASS(RPinRequest)
		{
	friend class CBluetoothPrefetchManager;
	public:
		RPinRequest();
		TInt Create(const TBTDevAddr& aAddr, CBTPinRequester* aPinRequester);
		void AddNotifier(MBluetoothPrefetchNotifier& aNotifier);
		TBool NotifiersWaiting() const;
		void CompleteRequest(TInt aResult);

	private:
		TBTDevAddr							iAddr;
		CBTPinRequester*					iPinRequester;
		TDblQue<TPrefetchNotifierQLink>*	iNotifiers;
		};

	NONSHARABLE_STRUCT(TPrefetchedPin)
		{
		TBTDevAddr		iAddr;
		TBTPinCode		iPin;
		};

private:
	CBluetoothPrefetchManager();

	static TBool CompareAddressInRequest(const TBTDevAddr* aDevAddr, const RPinRequest& aRequest);
	static TBool CompareAddressInStore(const TBTDevAddr* aDevAddr, const TPrefetchedPin& aRequest);
	
	TInt IsPrefetchAvailable(const TBTDevAddr& aAddr) const;

private: // from MPINCodeResponseHandler
	TInt PINCodeRequestReply(const TBTDevAddr& aDevAddr, const TDesC8& aPin) const;
	TInt PINCodeRequestNegativeReply(const TBTDevAddr& aDevAddr) const;

private:
	mutable RArray<RPinRequest>		iPinRequesters;
	mutable RArray<TPrefetchedPin>	iPrefetchedPins;
	};


NONSHARABLE_CLASS(CPhysicalLinksManager) : public CBase,
							  public MBtHostControllerEventInternalNotifier,
							  public MBTPairingsCacheObserver
/**
	Manages CPhysicalLink objects.
	One connections manager exists to take care of all CPhysicalLink objects.
*/
	{
public:

	static CPhysicalLinksManager* NewL(CLinkMgrProtocol& aLinkMgrProtocol,
									   CHCIFacade& aHCIFacade,
									   CRegistrySession& aRegSess,
									   CBTSecMan& aSecMan,
									   CBTCodServiceMan& aCodMan);
	~CPhysicalLinksManager();
	inline CBTSecMan& SecMan() const;
	inline CBTCodServiceMan& CodMan() const;
	inline CBTBasebandModel& Baseband() const;
	CPhysicalLink& NewPhysicalLinkL(const TBTDevAddr& aDevice);			// factory function
	CPhysicalLink& NewPhysicalLinkL(const TBTNamelessDevice& aDevice);	// factory function
	void AuthenticateL(const TBTDevAddr& aBDAddr);
	void EncryptL(const TBTDevAddr& aBDAddr);

	void RemovePhysicalLink(const CPhysicalLink& aConnection);
	TInt AddListener(MLogicalLink& aLogicalLink, TPhysicalLinkPort aPort);
	void RemoveListener(MLogicalLink& aLogicalLink);
	void ClearTerminatingProxy(CBTProxySAP* aProxySAP);
	TInt TerminateAllPhysicalLinks(CBTProxySAP* aProxySAP, THCIErrorCode aErrorCode);
	TInt TerminatePhysicalLink(CPhysicalLink* aConnection, CBTProxySAP* aProxySAP);

	void FatalError(TInt aErr);
	void UpdateRemoteDevicesDetails();
	TInt RefreshPairedBDAddrs();
	
	void SetAcceptPairedOnlyMode(TBool aOn);
	void SetSimplePairingDebugMode(TBool aOn);
	
	void SimplePairingDebugModeChanged(TBool aOn);

	inline TInt NumberOfPhysicalLinks() const;
	void EnumeratePhysicalLinks(TDes8& aPackagedArray);
	void DumpPhysicalLinks();
	TBool IsAcceptPairedOnlyMode();
	
	void RequireSlotSpace();	// for HostResolver (or others) who need to reduce connection commitments
	TBasebandTime TryToChangePageTimeout(TBasebandTime aPageTimeout);
	
	// role change methods to control locally initiated requests
	void AddRoleSwitcher(CRoleSwitcher& aRoleSwitcher);
	// This method must be called only from the D'tor of CRoleSwitcher	
	void RemoveRoleSwitcher(CRoleSwitcher& aRoleSwitcher);
	// to enable to generate BTBaseband event, RoleChange error in case of RoleChange
	// command was 'not allowed' by HW
	void RoleChangeRejectedByHW(THCIErrorCode aErr);
	CRoleSwitcherStateFactory& RoleSwitcherStateFactory() const;
	
public:	
			
	
// events from MBtHostControllerEventInternalNotifier
	virtual void ConnectionComplete(THCIErrorCode aErr, const TBTConnect& aConn);
	virtual void ConnectionRequest(const TBTConnect& aConn);
	virtual void Disconnection(THCIErrorCode aErr, THCIConnHandle aConnH, THCIErrorCode aResult);
	virtual void CompletedPackets(THCIConnHandle aConnH, TUint16 aNumPackets);
	virtual void AuthenticationComplete(THCIErrorCode aErr, THCIConnHandle aConnH);
	virtual void EncryptionChange(THCIErrorCode aErr, THCIConnHandle aConnH,TBool aEncrypted);
	virtual void ACLDataReceived(THCIConnHandle aConnH, TUint8 aFlag, const TDesC8& aData);
	virtual void SCODataReceived(THCIConnHandle aConnH, const TDesC8& aData);
	virtual void SynchronousConnectionComplete(THCIErrorCode aErr, const TBTConnect& aConn, const TBTSyncConnectOpts& aSyncOpts);
	virtual void PinRequest(const TBTDevAddr& aBDAddr, MPINCodeResponseHandler& aRequester);
	virtual void NewLinkKey(const TBTDevAddr& aBDAddr, const TBTLinkKey& aLinkKey, THCILinkKeyType aLinkKeyType);
	virtual void LinkKeyRequest(const TBTDevAddr& aBDAddr, MLinkKeyResponseHandler& aRequester);
	virtual void ReadRemoteSupportedFeaturesComplete(THCIErrorCode aErr, THCIConnHandle aConnH, const TBTFeatures& aBitMask);
	virtual void ReadRemoteExtendedFeaturesComplete(THCIErrorCode aErr, THCIConnHandle aConnH, TUint64 aBitMask, TUint8 aPageNumber, TUint8 aMaximimPageNumber);
	virtual void ReadRemoteVersionInfoComplete(THCIErrorCode aErr, THCIConnHandle aConnH, const TBTDevRemoteHwVersion& aVer);
	virtual void PacketTypeChange(THCIErrorCode aErr, THCIConnHandle aConnH, TUint16 aNewPacket);
	virtual void LinkSupervisionTimeoutChange(THCIErrorCode aErr, THCIConnHandle aConnH, TUint16 aNewTimeout);
	virtual void MaxSlotsChange(THCIConnHandle aConnH, TUint8 aSlots);
	virtual void ModeChange(THCIErrorCode aErr, THCIConnHandle aConnH, TBTLinkMode aMode, TBasebandTime aInterval);
	virtual void WriteLinkPolicySettingsCompleteEvent(THCIErrorCode aErr, THCIConnHandle aConnH);
	virtual void RoleChange(THCIErrorCode aErr, const TBTDevAddr& aAddr, TBTBasebandRole aRole);
	virtual void ClockOffset(THCIErrorCode aErr, THCIConnHandle aConnH, TBasebandTime aClockOffset);
	virtual void RemoteName(THCIErrorCode aErr, const TBTDevAddr& aAddr, const TBTDeviceName8& aName);
	virtual void SimplePairingComplete(const TBTDevAddr& aBDAddr, THCIErrorCode aErr);

// events from MBTPairingsCacheObserver
	virtual void MbpcoDeferredDecisionResolved(TInt aError);

// Getters
	inline CHCIFacade& HCIFacade() const;
	inline CLinkMgrProtocol& LinkManagerProtocol() const;
	inline CBTPairingsCache& PairingsCache() const;
	inline CBluetoothPrefetchManager& PrefetchMan() const;

	CPhysicalLink* FindPhysicalLink() const;	// mainly for finding random coonected PHY for proxy SAP
	CPhysicalLink* FindPhysicalLink(THCIConnHandle aConnH) const; // mainly for LinkMgrProtocol
	CPhysicalLink* FindPhysicalLink(const TBTDevAddr& aBDAddr) const;
	TLogicalLinkListener* FindListener(TPhysicalLinkPort aPort);

	TInt ChangeMode(TBTLinkMode aMode, THCIConnHandle aConnHandle);
	TInt ExitMode(TBTLinkMode aMode, THCIConnHandle aConnHandle);
	TInt ChangeRole(TBTBasebandRole aRole, CPhysicalLink& aPhysicalLink);
	TInt Encrypt(TBool aEnable, CPhysicalLink& aPhysicalLink);
	
	TBool ActiveConnectRoleSwitchAllowed() const;
	TBool PassiveConnectBecomeMaster() const;
	TBool RoleSwitchAllowed() const;
	
	void ArbitrateAllPhysicalLinks();

	TInt GetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType) const;
	TInt GetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType) const;
	TInt GetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const;
	TInt GetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const;
	TInt GetRemoteAddress(TBTDevAddr& aBDAddr, THCIConnHandle aConnectionHandle) const;
	TInt GetRemoteDeviceClass(TBTDeviceClass& aDeviceClass, const TBTDevAddr& aBDAddr) const;
	TInt GetRemoteSupportedFeatures(TBTFeatures& aRemoteSupportedFeatures, const TBTDevAddr& aBDAddr) const;
	TInt GetLinkPolicySettings(TLinkPolicy& aLinkPolicySettings, const TBTDevAddr& aBDAddr) const;
	TInt GetBasebandLinkState(TBTBasebandLinkState& aBasebandLinkState, const TBTDevAddr& aBDAddr) const;

private:

	CPhysicalLinksManager(CLinkMgrProtocol& aLinkMgrProtocol,
						  CHCIFacade& aHCIFacade,
						  CRegistrySession& aRegSess, CBTSecMan& aSecMan, CBTCodServiceMan& aCodMan);
	void ConstructL();
	void CancelPendingConnections(THCIErrorCode aErr, const TBTConnect& aConn);
	void DoConnectionRequestL(const TBTConnect& aConn);
	static TBool ListenerMatch(const TLogicalLinkListener& aA, const TLogicalLinkListener& aB);
	void UpdateTerminatingProxy(CBTProxySAP* aProxySAP);

	TBasebandTime CheckPageTimeoutAgainstLSTO(TBasebandTime aPageTimeout);

private:
	RPointerArray<CPhysicalLink>	iPhysicalLinks;

	CHCIFacade&						iHCIRequestHandler;
	CRegistrySession&				iRegSess;	// we don't "own" an "access".
	CBTSecMan&						iSecMan;
	CBTCodServiceMan&				iCodMan;
	CLinkMgrProtocol&				iLinkManagerProtocol;

	CBTProxySAP*					iTerminatingProxy; // unowned
	CPhysicalLink*					iTerminatingConnection; // unowned
	
	CBTBasebandModel*				iBaseband;
	RArray<TLogicalLinkListener>	iListeners;

	// role change control variables
	TSglQue<CRoleSwitcher> 			iRoleSwitchersQ;
	CRoleSwitcherStateFactory*		iRoleSwitcherStateFactory;
	
	TBool							iAcceptPairedOnlyMode;
	CBTPairingsCache*				iPairingsCache;

	TPageTimeoutController			iPageTimeoutController;
	CBluetoothPrefetchManager*		iPrefetchMan;
	};

inline CLinkMgrProtocol& CPhysicalLinksManager::LinkManagerProtocol() const
	{
	return iLinkManagerProtocol;
	}

inline CHCIFacade& CPhysicalLinksManager::HCIFacade() const
	{
	return iHCIRequestHandler;
	}

inline CBTSecMan& CPhysicalLinksManager::SecMan() const
	{
	return iSecMan;
	}

inline CBTBasebandModel& CPhysicalLinksManager::Baseband() const
	{
	return *iBaseband;
	}

inline TInt CPhysicalLinksManager::NumberOfPhysicalLinks() const
	{
	return iPhysicalLinks.Count();
	}

inline CBTCodServiceMan& CPhysicalLinksManager::CodMan() const
	{
	return iCodMan;
	}

inline CBTPairingsCache& CPhysicalLinksManager::PairingsCache() const
	{
	return *iPairingsCache;
	}

inline CRoleSwitcherStateFactory& CPhysicalLinksManager::RoleSwitcherStateFactory() const
	{
	return *iRoleSwitcherStateFactory;
	}

inline CBluetoothPrefetchManager& CPhysicalLinksManager::PrefetchMan() const
	{
	return *iPrefetchMan;
	}

#endif //PHYSICALLINKSMANAGER
