// Copyright (c) 2003-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:
// Defines the ACL SAP class, and ACL State Classes (using State and Flyweight pattern)
// 
//

#ifndef _ACLSAP_H
#define _ACLSAP_H

#include "debug.h"
#include <es_prot.h>
#include <es_mbuf.h>
#include <bluetooth/aclsockaddr.h>
#include "basebandsap.h"
#include "notification.h"
#include "linkutil.h"

class CLinkMgrProtocol;
class CPhysicalLink;
class CPhysicalLinksManager;

class TACLLinkState;
class CACLLink;
class CACLDataItem;
class CACLDataQController;

/**
   Factory for the ACL Link states

   The states are flyweight classes
**/
NONSHARABLE_CLASS(CACLLinkStateFactory) : public CBase
	{
public:
	static CACLLinkStateFactory* NewL();
	~CACLLinkStateFactory();
	enum TACLLinkStates
		{
		EClosed,
		EListening,
		EAccepting,
		EWaitForLink,
		EWaitForStart,
		EWaitForStartError,
		EWaitForStartParked,
		EOpen,	
		EOpenParked,
		EClosing,
	// *** keep next one last ***
		EACLLinkMaxState,
		};
	
	TACLLinkState& GetState(TACLLinkStates aState);
	TInt StateIndex(const TACLLinkState* aState) const;
private:
	void ConstructL();
	TFixedArray<TACLLinkState*, EACLLinkMaxState> iStates;
	};


NONSHARABLE_CLASS(TACLLinkState)
	{
public:
	TACLLinkState(CACLLinkStateFactory& aFactory);

	virtual void Enter(CACLLink& aContext) const;

	virtual void ActiveOpen(CACLLink& aContext) const;
	virtual TInt PassiveOpen(CACLLink& aContext, TUint aQueSize) const;
	virtual void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	virtual void DataReceived(CACLLink& aContext, TUint8 aFlag, const TDesC8& aData) const;
	virtual TUint Write(CACLLink& aContext, const TDesC8& aData, TUint aOptions, TSockAddr* aAddr) const;
	virtual void Start(CACLLink& aContext) const;
	virtual TBool ConnectRequest(CACLLink& aContext, const TBTConnect& aConnectDetails, const CPhysicalLink& aPhysicalLink) const;
	virtual void ConnectComplete(CACLLink& aContext, const TBTConnect& aConnectDetails) const;
	virtual void Disconnection(CACLLink& aContext) const;
	virtual void Error(CACLLink& aContext, TInt aError) const;

	virtual void Timeout(CACLLink& aContext, TBasebandTimeout aTimeout) const;
	virtual void Exit(CACLLink& aContext) const;
	virtual void Deletion(CACLLink& aContext) const;

	virtual TBool IsIdle() const;
	virtual void Park(CACLLink& aContext) const;
	virtual void Unpark(CACLLink& aContext) const;
protected:
	// Exits old state, sets the new state, and enters it.
	void ChangeState(CACLLink& aContext, CACLLinkStateFactory::TACLLinkStates aState) const;
	void PanicInState(TLinkPanic aPanic) const;

protected:
	CACLLinkStateFactory& iFactory;
#ifdef __FLOG_ACTIVE
	TBuf<48> iName;
#endif
	};

NONSHARABLE_CLASS(TACLLinkStateListening) : public TACLLinkState
	{
public:
	TACLLinkStateListening(CACLLinkStateFactory& aFactory);

	void Enter(CACLLink& aContext) const;

	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	TBool ConnectRequest(CACLLink& aContext, const TBTConnect& aConnect, const CPhysicalLink& aPhysicalLink) const;

	void Deletion(CACLLink& aContext) const;

	void Exit(CACLLink& aContext) const;
	
	void Error(CACLLink& aContext, TInt aError) const;
private:
	void SpawnL(CACLLink& aContext, CPhysicalLink& aPhysicalLink) const;
	};

NONSHARABLE_CLASS(TACLLinkStateAccepting) : public TACLLinkState
	{
public:
	TACLLinkStateAccepting(CACLLinkStateFactory& aFactory);
	void Enter(CACLLink& aContext) const;
	void Exit(CACLLink& aContext) const;
	void ConnectComplete(CACLLink& aContext, const TBTConnect& aConnect) const;
	void Error(CACLLink& aContext, TInt aError) const;
	void Disconnection(CACLLink& aContext) const;
	void Deletion(CACLLink& aContext) const;
	void Timeout(CACLLink& aContext, TBasebandTimeout aTimeout) const;
	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	};

NONSHARABLE_CLASS(TACLLinkStateWaitForLink) : public TACLLinkState
	{
public:
	TACLLinkStateWaitForLink(CACLLinkStateFactory& aFactory);

	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	void ConnectComplete(CACLLink& aContext, const TBTConnect& aConnectDetails) const;
	void Error(CACLLink& aContext, TInt aError) const;
	void Disconnection(CACLLink& aContext) const;
	void Exit(CACLLink& aContext) const;
	};

NONSHARABLE_CLASS(TACLLinkStateWaitForStart) : public TACLLinkState
	{
public:
	TACLLinkStateWaitForStart(CACLLinkStateFactory& aFactory);
	void Enter(CACLLink& aContext) const;
	void Start(CACLLink& aContext) const;
	void Error(CACLLink& aContext, TInt aError) const;
	void Deletion(CACLLink& aContext) const;
	void Disconnection(CACLLink& aContext) const;
	void Park(CACLLink& aContext) const;
	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	};

NONSHARABLE_CLASS(TACLLinkStateWaitForStartError) : public TACLLinkState
	{
public:
	TACLLinkStateWaitForStartError(CACLLinkStateFactory& aFactory);
	void Start(CACLLink& aContext) const;
	void Disconnection(CACLLink& aContext) const;
	void Error(CACLLink& aContext, TInt aError) const;
	void Deletion(CACLLink& aContext) const;
	};

NONSHARABLE_CLASS(TACLLinkStateWaitForStartParked) : public TACLLinkStateWaitForStart
	{
public:
	TACLLinkStateWaitForStartParked(CACLLinkStateFactory& aFactory);
	void Unpark(CACLLink& aContext) const;
	void Start(CACLLink& aContext) const;
	};


NONSHARABLE_CLASS(TACLLinkStateOpen) : public TACLLinkState
	{
public:
	TACLLinkStateOpen(CACLLinkStateFactory& aFactory);
	void Enter(CACLLink& aContext) const;

	TUint Write(CACLLink& aContext, const TDesC8& aData, TUint aOptions, TSockAddr* aAddr) const;
	void DataReceived(CACLLink& aContext, TUint8 aFlag, const TDesC8& aData) const;	
	void Disconnection(CACLLink& aContext) const;
	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	void Park(CACLLink& aContext) const;
	void Error(CACLLink& aContext, TInt aError) const;
	void Exit(CACLLink& aContext) const;
	};

NONSHARABLE_CLASS(TACLLinkStateOpenParked) : public TACLLinkStateOpen
	{
public:
	TACLLinkStateOpenParked(CACLLinkStateFactory& aFactory);
	void Enter(CACLLink& aContext) const;

	TUint Write(CACLLink& aContext, const TDesC8& aData, TUint aOptions, TSockAddr* aAddr) const;
	void DataReceived(CACLLink& aContext, TUint8 aFlag, const TDesC8& aData) const;	
	void Unpark(CACLLink& aContext) const;

	void Exit(CACLLink& aContext) const;
	};

NONSHARABLE_CLASS(TACLLinkStateClosing) : public TACLLinkState
	{
public:
	TACLLinkStateClosing(CACLLinkStateFactory& aFactory);

	void ActiveOpen(CACLLink& aContext) const;
	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;
	void Disconnection(CACLLink& aContext) const;
	void DataReceived(CACLLink& aContext, TUint8 aFlag, const TDesC8& aData) const;
	TUint Write(CACLLink& aContext, const TDesC8& aData, TUint aOptions, TSockAddr* aAddr) const;
	void Enter(CACLLink& aContext) const;
	void Deletion(CACLLink& aContext) const;

	TBool IsIdle() const;
	
	void Error(CACLLink& aContext, TInt aError) const;
	};

NONSHARABLE_CLASS(TACLLinkStateClosed) : public TACLLinkState
	{
public:
	TACLLinkStateClosed(CACLLinkStateFactory& aFactory);

	void Start(CACLLink& aContext) const; // CSockets Start
	void Enter(CACLLink& aContext) const;
	void ActiveOpen(CACLLink& aContext) const;
	TInt PassiveOpen(CACLLink& aContext, TUint aQueSize) const;
	void Shutdown(CACLLink& aContext, CServProviderBase::TCloseType aCloseType) const;

	void Deletion(CACLLink& aContext) const;
	TBool IsIdle() const;
	};


NONSHARABLE_CLASS(CACLLink) : public CBTBasebandSAP, public MLogicalLink
	{
friend class TACLLinkState;
friend class TACLLinkStateOpen;
friend class TACLLinkStateOpenParked;
friend class TACLLinkStateListening;
friend class TACLLinkStateAccepting;
friend class TACLLinkStateWaitForStart;
friend class TACLLinkStateWaitForStartParked;
friend class TACLLinkStateWaitForLink;
friend class TACLLinkStateClosing;
friend class TACLLinkStateClosed;
public:
	static CACLLink* NewL(CPhysicalLinksManager& aLinksMan,
						  CPhysicalLink* aConnection,
						  CLinkMgrProtocol& aProtocol);
	static CACLLink* NewLC(CPhysicalLinksManager& aLinksMan,
						   CPhysicalLink* aConnection,
						   CLinkMgrProtocol& aProtocol);
	~CACLLink();
	// from SAP
	virtual void Start();
	virtual void AutoBind();
	virtual void LocalName(TSockAddr& anAddr) const ;
	virtual TInt SetLocalName(TSockAddr& anAddr);
	virtual void RemName(TSockAddr& anAddr) const ;
	virtual TInt SetRemName(TSockAddr& anAddr);
	virtual TInt GetOption(TUint level,TUint name,TDes8& anOption)const ;
	virtual void Ioctl(TUint level,TUint name,TDes8* anOption);
	virtual void CancelIoctl(TUint aLevel,TUint aName);
	virtual TInt SAPSetOption(TUint level,TUint name,const TDesC8 &anOption);

	virtual void ActiveOpen();
	virtual TInt PassiveOpen(TUint aQueSize);
	virtual void Shutdown(TCloseType option);
	virtual void Shutdown(TCloseType option,const TDesC8& aDisconnectionData);


	TUint Write(const TDesC8& aDesc,TUint aOptions, TSockAddr* aAddr);

	void GetData(TDes8& aDesc,TUint aOptions,TSockAddr* anAddr=NULL);
	TInt GetData(RMBufChain& aData, TUint aLength, TUint aOptions, TSockAddr* aAddr=NULL);

	void Timeout(TBasebandTimeout aTimeout);

	TBool IsIdle() const;
	TBool IsLocallyInitiated() const;

	void ACLDataReceived(THCIConnHandle aConnH, TUint8 aFlag, const TDesC8& aData);

// from MLogicalLink
	virtual TBool ConnectRequest(const TBTConnect& aConnect, const CPhysicalLink& aPhysicalLink);
	virtual void ConnectComplete(const TBTConnect& aConnect);
	virtual void Disconnection();
	virtual void Error(TInt aError);
	virtual void DataReceived(THCIConnHandle aConnH, TUint8 aFlag, const TDesC8& aData);
	
	void PacketsSent(THCIConnHandle aConnH, TUint16 aNumPackets);
	void PhysicalLinkChange(const TBTBasebandEventNotification& aEvent, CPhysicalLink& aPhysicalLink);
	void TryToSend();
	
private:
	CACLLink(CPhysicalLinksManager& aManager,
			 CPhysicalLink* aConnection,
			 CLinkMgrProtocol& aProtocol);
	void ConstructL();
	void NotifyDataToSocket(TUint8 aFlag, const TDesC8& aData);
	void CloseLogicalLink();
	TInt OpenLogicalLink();
	void ParkLogicalLink();
	void UnparkLogicalLink();
	void BindAndConnectPhysicalLinkL();
	void ClearPhysicalLink();
	TInt DoACLGetOption(TUint aName,TDes8& aOption) const;
	TInt DoACLSetOption(TUint aName, const TDesC8& aOption);
	TUint DoWrite(CACLDataItem& aFrame, CACLDataQController& aQctrl,
		   	   const TDesC8& aData, TUint8 aOptions);
	TBool CanHandleFlags(TUint8 aFlag) const;
	
	TInt ProcessFlush();
	
private: // from MAccessRequestResponseHandler
	void AccessRequestComplete(TInt aResult);
	
private:
	enum TInitiationState
		{
		EInvalidInitiationState	= 0x00,
		ELocallyInitiated		= 0x01,
		ERemotelyInitiated		= 0x02,
		};
	void SetInitiationState(TInitiationState aState);
	void ClearInitiationState();
	
private:
	CLinkMgrProtocol&		iProtocol;
	TACLLinkState*			iState;

	RMBufPktQ				iInboundBuffer;

	TACLPort			iLocalPort;		// based on PB flags
	TBool				iSocketBlocked;

	TInitiationState	iInitiationState; // simpler than modelling in state machine.
	};

#ifdef __FLOG_ACTIVE
#define STATENAME(x)  iName=_L(x)
#else
#define STATENAME(x)
#endif

#endif // _ACLSAP_H
