// 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:
// Implements the signalling state machine for an L2Cap Channel
// 
//

#ifndef L2CAPSIGSTATES_H
#define L2CAPSIGSTATES_H


#include <e32base.h>
#include <bt_sock.h>
#include <es_prot.h>

#include "L2CapChannelConfig.h"

class CL2CapSAPSignalHandler;
class CL2CAPSignalStateFactory;
class CL2CAPConnectionSAP;
class TL2CAPSigState;

class HConnectionResponse;
class HConfigureRequest;
class HConfigureResponse;


// Factory class for the L2CAP state machine.
NONSHARABLE_CLASS(CL2CAPSignalStateFactory) : public CBase
	{
public:
	enum TSigStates
		{
		EClosed,
		EWaitConnectRsp,
		EWaitConnect,
		EWaitConfig,
		EWaitSendConfig,
		EWaitConfigReqRsp,
		EWaitConfigRsp,
		EWaitConfigReq,
		EOpen,
		EWaitDisconnect,
		EMaxState,
		};

	TL2CAPSigState& GetState(const TSigStates aState) const;
	TInt StateIndex(const TL2CAPSigState* aState) const;
	
	static CL2CAPSignalStateFactory* NewL();
	~CL2CAPSignalStateFactory();

private:
	CL2CAPSignalStateFactory();
	void ConstructL();

private:	
	TFixedArray<TL2CAPSigState*, EMaxState> iSigStates;
	};


// Base class for the L2CAP state machine.
NONSHARABLE_CLASS(TL2CAPSigState)
	{
public:
	friend class CL2CapSAPSignalHandler;

	TL2CAPSigState(const CL2CAPSignalStateFactory& aFactory);
	
	// Events from the SAP
	virtual void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	virtual void OpenChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	virtual void ConnectRequestReceived(CL2CapSAPSignalHandler& aSignalHandler) const;
	virtual void ConfigureChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	virtual TInt UpdateChannelConfig(CL2CapSAPSignalHandler& aSignalHandler, const TL2CapConfig& aAPIConfig) const;

	virtual TInt GetNegotiatedChannelMode(const CL2CapSAPSignalHandler& aSignalHandler, TL2CapChannelMode& aMode) const;

	// L2CAP commands received from the peer.
	virtual void ConnectResponse(CL2CapSAPSignalHandler& aSignalHandler,
								 HConnectionResponse* aConnectionResponse) const;
	
	virtual void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
							   HConfigureRequest* aConfigRequest) const;
	virtual void ConfigResponse(CL2CapSAPSignalHandler& aSignalHandler,
 		                        HConfigureResponse* aConfigResponse) const;
	virtual void DisconnectRequest(CL2CapSAPSignalHandler& aSignalHandler, TUint8 aId) const;
	virtual void DisconnectResponse(CL2CapSAPSignalHandler& aSignalHandler) const;

	// Events from the Mux
	virtual void Error(CL2CapSAPSignalHandler& aSignalHandler,
	                   TInt aErrorCode, 
	                   MSocketNotify::TOperationBitmasks aErrorAction) const;

	// Change of state events
	virtual void Enter(CL2CapSAPSignalHandler& aSignalHandler) const;
	virtual void Exit(CL2CapSAPSignalHandler& aSignalHandler) const;
	
	// Signal command queue event
	virtual void PendingCommandsDrained(CL2CapSAPSignalHandler& aSignalHandler) const;

	// Timers
	virtual void ConfigurationTimerExpiry(CL2CapSAPSignalHandler& aSignalHandler) const;

	// Helpers
	virtual TBool IsChannelClosed() const;
	virtual TBool IsChannelOpen() const;
	void HandleDisconnectRequest(CL2CapSAPSignalHandler& aSignalHandler, TUint8 aId) const;
	void HandleSAPDisconnect(CL2CapSAPSignalHandler& aSignalHandler) const;
	TInt SendConfigRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	TInt SendConfigResponse(CL2CapSAPSignalHandler& aSignalHandler, TConfigResponseResult aResult) const;
	void DisconnectWithError(CL2CapSAPSignalHandler& aSignalHandler, TInt aError) const;

protected:
	void PanicInState(TL2CAPPanic aPanic) const;

protected:
	const CL2CAPSignalStateFactory& iFactory;  // Get states
	};


/**
   The closed state.

   This is the state that newly created signal handlers start in, and the state
   they end in after a communication has closed down or a connection
   failed.
*/
NONSHARABLE_CLASS(TL2CAPSigStateClosed) : public TL2CAPSigState
	{
public:
	TL2CAPSigStateClosed(const CL2CAPSignalStateFactory& aFactory);

	// Events from the SAP
	void OpenChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	void ConnectRequestReceived(CL2CapSAPSignalHandler& aSignalHandler) const;
	void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;

	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
					   HConfigureRequest* aConfigRequest) const;

	// Change of state state events
	void Enter(CL2CapSAPSignalHandler& aSignalHandler) const;

	// Helpers
	TBool IsChannelClosed() const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitConnectRsp) : public TL2CAPSigState
/*
   Waiting for a response to our ConnectRequest.
*/
	{
public:
	TL2CAPSigStateWaitConnectRsp(const CL2CAPSignalStateFactory& aFactory);

	// Events from the SAP
	void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;

	// L2CAP commands received from the peer.
	void ConnectResponse(CL2CapSAPSignalHandler& aSignalHandler,
						 HConnectionResponse* aConnectionResponse) const;
	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
						 HConfigureRequest* aConfigRequest) const;				 
	
	// Change of state state events
	void Enter(CL2CapSAPSignalHandler& aSignalHandler) const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitConnect) : public TL2CAPSigState
 	{
public:
	TL2CAPSigStateWaitConnect(const CL2CAPSignalStateFactory& aFactory);	

	// Events from the SAP
	void OpenChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	
	// L2CAP commands received from the peer.
	void DisconnectRequest(CL2CapSAPSignalHandler& aSignalHandler, TUint8 aId) const;

	// Change of state state events
	void PendingCommandsDrained(CL2CapSAPSignalHandler& aSignalHandler) const;
	
	};
	
NONSHARABLE_CLASS(TL2CAPSigStateConfigBase) : public TL2CAPSigState
/*
	This is the base class for the config states. It will NEVER be instantiated itself.
*/
	{
public:
	using TL2CAPSigState::ConfigRequest;
	using TL2CAPSigState::ConfigResponse;
	TL2CAPSigStateConfigBase(const CL2CAPSignalStateFactory& aFactory);	

	// L2CAP commands received from the peer.
	void DisconnectRequest(CL2CapSAPSignalHandler& aSignalHandler, TUint8 aId) const;

	void Error(CL2CapSAPSignalHandler& aSignalHandler,
	           TInt aErrorCode, 
	           MSocketNotify::TOperationBitmasks aErrorAction) const;

	// Events from the SAP
	void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	TInt UpdateChannelConfig(CL2CapSAPSignalHandler& aSignalHandler, const TL2CapConfig& aAPIConfig) const;

	// Timer Events
	void ConfigurationTimerExpiry(CL2CapSAPSignalHandler& aSignalHandler) const;

	// Common handling of Config Request and Response commands.
	virtual void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
					   HConfigureRequest* aConfigRequest,
					   CL2CAPSignalStateFactory::TSigStates aConfigSuccessState) const;
	virtual void ConfigResponse(CL2CapSAPSignalHandler& aSignalHandler,
 		                HConfigureResponse* aConfigResponse,
 		                CL2CAPSignalStateFactory::TSigStates aConfigSuccessState) const;
	};

	
NONSHARABLE_CLASS(TL2CAPSigStateWaitConfig) : public TL2CAPSigStateConfigBase
/*
	No config requests/responses sent or received.
	Waiting to receive peer L2Cap supported features.
*/
	{
public:
	TL2CAPSigStateWaitConfig(const CL2CAPSignalStateFactory& aFactory);	

	// Events from the SAP
	void ConfigureChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;

	// L2CAP commands received from the peer.
	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
					   HConfigureRequest* aConfigRequest) const;

	// Change of state state events
	void Enter(CL2CapSAPSignalHandler& aSignalHandler) const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitSendConfig) : public TL2CAPSigStateConfigBase
/*
	Remote's config request received and responded to with 'success'.
	Waiting to send outgoing config request...
	...waiting to receive peer L2Cap supported features.
*/
	{
public:
	TL2CAPSigStateWaitSendConfig(const CL2CAPSignalStateFactory& aFactory);	

	// Events from the SAP
	void ConfigureChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitConfigReqRsp) : public TL2CAPSigStateConfigBase
/*
	Outgoing config request sent.
	Waiting for remote's config request, and remote's config response.
*/
	{
public:
	TL2CAPSigStateWaitConfigReqRsp(const CL2CAPSignalStateFactory& aFactory);	

	// L2CAP commands received from the peer.
	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
					   HConfigureRequest* aConfigRequest) const;
	void ConfigResponse(CL2CapSAPSignalHandler& aSignalHandler,
 	                    HConfigureResponse* aConfigResponse) const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitConfigRsp) : public TL2CAPSigStateConfigBase
/*
	Remote's config request received and responded to with 'success'.
	Outgoing config request sent.
	Waiting for remote's config response.
*/
	{
public:
	TL2CAPSigStateWaitConfigRsp(const CL2CAPSignalStateFactory& aFactory);	

	// L2CAP commands received from the peer.
	void ConfigResponse(CL2CapSAPSignalHandler& aSignalHandler,
 	                    HConfigureResponse* aConfigResponse) const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitConfigReq) : public TL2CAPSigStateConfigBase
/*
	Outgoing config request sent, and responded to with 'success'.
	Waiting for remote's config request.
*/
	{
public:
	TL2CAPSigStateWaitConfigReq(const CL2CAPSignalStateFactory& aFactory);	

	// L2CAP commands received from the peer.
	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
					   HConfigureRequest* aConfigRequest) const;
	};
	

NONSHARABLE_CLASS(TL2CAPSigStateOpen) : public TL2CAPSigState
/*
	L2Cap logical link open. Data can be sent and received.
*/
	{
public:
	TL2CAPSigStateOpen(const CL2CAPSignalStateFactory& aFactory);	

	// Events from the SAP
	void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;

	// L2CAP commands received from the peer.
	void DisconnectRequest(CL2CapSAPSignalHandler& aSignalHandler, TUint8 aId) const;
	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,HConfigureRequest* aConfigRequest) const; 

	// Config state events
	TInt UpdateChannelConfig(CL2CapSAPSignalHandler& aSignalHandler, const TL2CapConfig& aAPIConfig) const;

	// Change of state state events
	void Enter(CL2CapSAPSignalHandler& aSignalHandler) const;

	TBool IsChannelOpen() const;
	TInt GetNegotiatedChannelMode(const CL2CapSAPSignalHandler& aSignalHandler, TL2CapChannelMode& aMode) const;
	};

NONSHARABLE_CLASS(TL2CAPSigStateWaitDisconnect) : public TL2CAPSigState
/*
	Logical link still exists but is waiting to be disconnected. 
	NB Signalling can still be received, and should be handled.
*/
	{
public:
	TL2CAPSigStateWaitDisconnect(const CL2CAPSignalStateFactory& aFactory);	

	// Events from the SAP
	void CloseChannelRequest(CL2CapSAPSignalHandler& aSignalHandler) const;
	TInt UpdateChannelConfig(CL2CapSAPSignalHandler& aSignalHandler, const TL2CapConfig& aAPIConfig) const;

	// State changes from the Mux
	void DisconnectRequest(CL2CapSAPSignalHandler& aSignalHandler, TUint8 aId) const;
	void DisconnectResponse(CL2CapSAPSignalHandler& aSignalHandler) const;

	// Change of state state events
	void Enter(CL2CapSAPSignalHandler& aSignalHandler) const;
	void PendingCommandsDrained(CL2CapSAPSignalHandler& aSignalHandler) const;
	void ConnectResponse(CL2CapSAPSignalHandler& aSignalHandler,
					   HConnectionResponse* aConnectionResponse) const;
	void ConfigRequest(CL2CapSAPSignalHandler& aSignalHandler,
					   HConfigureRequest* aConfigRequest) const;

	void ConfigResponse(CL2CapSAPSignalHandler& /*aSignalHandler*/,
 	                	HConfigureResponse* /*aConfigResponse*/) const;
	void ConfigureChannelRequest(CL2CapSAPSignalHandler& /*aSignalHandler*/) const;
	};

#endif
