// Copyright (c) 2007-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:
// generic framework node state machine states
// 
//

/**
 @file
 @publishedPartner
 @released
*/

#ifndef SYMBIAN_MM_ACTIVITIES_H
#define SYMBIAN_MM_ACTIVITIES_H

#include <elements/mm_node.h>
#include <elements/mm_nodepeer.h>
#include <elements/mm_activities_internal.h>
#include <elements/nm_address_internal.h>
#include <elements/nm_signatures.h>


#ifdef _DEBUG
// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
// (if it could happen through user error then you should give it an explicit, documented, category + code)
_LIT(KSpecAssert_ElemMeshMachActH, "ElemMeshMachActH");
#endif

//-=========================================================
//
// MACROS
//
//-=========================================================

/**
Declare and export a node activity.

@param name  The name of the activity, which will be used to put it into the node's activity map

@see DECLARE_NODEACTIVITY
*/
#define DECLARE_EXPORT_NODEACTIVITY( name ) \
	struct name \
		{ \
		IMPORT_C static const MeshMachine::TNodeActivity& Self(); \
		IMPORT_C static const NetStateMachine::TStateTriple& FirstTriple(); \
		static const MeshMachine::TNodeActivity iSelf; \
		static const NetStateMachine::TStateTriple iData[]; \
		};

/**
Declares a node activity. A node activity is a state machine. It contains multiple nodeactivity
entries, which respresent the states, transitions and forks of the state machine.

@param name  The name of the activity, which will be used to put it into the node's activity map

@see DEFINE_NODEACTIVITY
@see NODEACTIVITY_ENTRY
*/
#define DECLARE_NODEACTIVITY( name ) \
	struct name \
		{ \
		inline static const MeshMachine::TNodeActivity& Self() {return iSelf;} \
		inline static const NetStateMachine::TStateTriple& FirstTriple() {return iData[1];} \
		static const MeshMachine::TNodeActivity iSelf; \
		static const NetStateMachine::TStateTriple iData[]; \
		};

#ifdef SYMBIAN_TRACE_ENABLE
/**
Define and export a custom node activity.

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity
@param ctor      Constructor for the custom activity class

@see DEFINE_CUSTOM_NODEACTIVITY
*/
	#define DEFINE_EXPORT_CUSTOM_NODEACTIVITY( id, name, msgtype, ctor ) \
		EXPORT_C const MeshMachine::TNodeActivity& name :: Self() {return iSelf;} \
		EXPORT_C const NetStateMachine::TStateTriple& name :: FirstTriple() {return iData[1];} \
		const MeshMachine::TNodeActivity name :: iSelf = {id, msgtype::EId, msgtype::ERealm, name :: iData[1], &ctor, _S8(#name)}; \
		DEFINE_TRIPLES_TABLE( name :: iData )

/**
Define a custom node activity. A custom node activity is a node activity which defines its own
node activity class. This is used, for example, if the activity wishes to share some custom context
information between the states and transition in the activity.

Node activity class must derive from CNodeActivityBase.

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity
@param ctor      Constructor for the custom activity class

@see DEFINE_NODEACTIVITY
@see CNodeActivityBase
*/
	#define DEFINE_CUSTOM_NODEACTIVITY( id, name, msgtype, ctor ) \
		const MeshMachine::TNodeActivity name :: iSelf = {id, msgtype::EId, msgtype::ERealm, name :: iData[1], &ctor, _S8(#name)}; \
		DEFINE_TRIPLES_TABLE( name :: iData )

#else

/**
Define and export a custom node activity.

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity
@param ctor      Constructor for the custom activity class

@see DEFINE_CUSTOM_NODEACTIVITY
*/
	#define DEFINE_EXPORT_CUSTOM_NODEACTIVITY( id, name, msgtype, ctor ) \
		EXPORT_C const MeshMachine::TNodeActivity& name :: Self() {return iSelf;} \
		EXPORT_C const NetStateMachine::TStateTriple& name :: FirstTriple() {return iData[1];} \
		const MeshMachine::TNodeActivity name :: iSelf = {id, msgtype::EId, msgtype::ERealm, name :: iData[1], &ctor, NULL}; \
		DEFINE_TRIPLES_TABLE( name :: iData )

/**
Define a custom node activity. A custom node activity is a node activity which defines its own
node activity class. This is used, for example, if the activity wishes to share some custom context
information between the states and transition in the activity.

Node activity class must derive from CNodeActivityBase.

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity
@param ctor      Constructor for the custom activity class

@see DEFINE_NODEACTIVITY
@see CNodeActivityBase
*/
	#define DEFINE_CUSTOM_NODEACTIVITY( id, name, msgtype, ctor ) \
		const MeshMachine::TNodeActivity name :: iSelf = {id, msgtype::EId, msgtype::ERealm, name :: iData[1], &ctor, NULL}; \
		DEFINE_TRIPLES_TABLE( name :: iData )

#endif

/**
Define and declare a custom node activity

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity
@param ctor      Constructor for the custom activity class

@see DEFINE_CUSTOM_NODEACTIVITY
*/
#define DECLARE_DEFINE_CUSTOM_NODEACTIVITY( id, name, msgtype, ctor ) \
	DECLARE_NODEACTIVITY( name ) \
	DEFINE_CUSTOM_NODEACTIVITY( id, name, msgtype, ctor )

/**
Define and export node activity

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity

@see DEFINE_NODEACTIVITY
*/
#define DEFINE_EXPORT_NODEACTIVITY( id, name, msgtype ) \
	DEFINE_EXPORT_CUSTOM_NODEACTIVITY( id, name, msgtype, MeshMachine::CNodeActivityBase::NewL )

/**
Define the start of a node activity. There must be a matching @c NODEACTIVITY_END to close the
node activity.

The @c id is a unique identifier for the activity. It allows activities to be overridden in an
activity map. When deriving from an activity map, if you specify a node activity in your map
whose id is the same as one in the parent map, the one in the parent map with be overriden.

The @c name of the activity is used to add it to the activity map.

The @c msgtype is the type of message which will initiate this activity. This can be left as the
null message, in which case it will be the first state which decides whether to start the activity
or not.

@code
namespace ExampleActivity {
DEFINE_NODEACTIVITY(EFoobarActivity, SimpleFoobarActivity, TFoobar)
    FIRST_NODEACTIVITY_ENTRY(TAwaitingFoobar, TDoOneThingOrAnother)
	NODEACTIVITY_ENTRY(KDoOneThing, TDoTheThing, TAwaitingResponseToThing, TNoTag)
	NODEACTIVITY_ENTRY(KAnother, TDoTheOtherThing, TAwaitingResponseToThing, TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, TDoFinalThing)
NODEACTIVITY_END()
} // end namespace ExampleActivity
@endcode

A node activity must start with either a @c FIRST_NODEACTIVITY_ENTRY or a @c SINGLE_NODEACTIVITY_ENTRY. In
the latter case there should be no other entries in the node activity.

The activity object (@c CNodeActivityBase) is only created once the second @c NODEACTIVITY_ENTRY is entered.

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity

@see DEFINE_ACTIVITY_MAP
*/
#define DEFINE_NODEACTIVITY( id, name, msgtype ) \
	DEFINE_CUSTOM_NODEACTIVITY( id, name, msgtype, MeshMachine::CNodeActivityBase::NewL )

/**
Define and declare a node activity

@param id        Identifier for the activity
@param name      The name of the activity
@param msgtype   Message which will kickoff this activity

@see DEFINE_ACTIVITY_MAP
*/
#define DECLARE_DEFINE_NODEACTIVITY( id, name, msgtype ) \
	DECLARE_DEFINE_CUSTOM_NODEACTIVITY( id, name, msgtype, MeshMachine::CNodeActivityBase::NewL )

/**
Define an entry in a node activity.

@param transitionTag     Condition on which the entry is entered
@param stateTransition   Transition to be executed
@param state             State to enter after
@param stateFork         Fork to decide which entry to enter next

@see DEFINE_NODEACTIVITY
*/
#define NODEACTIVITY_ENTRY( transitionTag, stateTransition, state, stateFork ) \
	STATE_TRIPLE_ENTRY( transitionTag, stateTransition, state, stateFork )

/**
Define the first entry in a node activity

@param firstState       Initial state of the activity
@param firstStateFork   Fork to decide which entry to enter next

@see DEFINE_NODEACTIVITY
*/
#define FIRST_NODEACTIVITY_ENTRY( firstState, firstStateFork ) \
	FIRST_TRIPLE_ENTRY( firstState, firstStateFork )

/**
Define a through entry. Through entries execute a transition but do not
enter a state. Instead they move onto the next entry in the node activity
using the @c stateFork to decide which entry this is.

@param transitionTag   Condition on which the entry is entered
@param stateTransition Transition to be executed
@param stateFork       Fork to decide which entry to enter next
*/
#define THROUGH_NODEACTIVITY_ENTRY( transitionTag, stateTransition, stateFork ) \
	THROUGH_TRIPLE_ENTRY( transitionTag, stateTransition, stateFork )

/**
Define the final entry in a node activity.

@param transitionTag  Condition on which the entry is entered
@param lastTransition Final transition to be executed

@see DEFINE_NODEACTIVITY
*/
#define LAST_NODEACTIVITY_ENTRY( transitionTag, lastTransition ) \
	LAST_TRIPLE_ENTRY( transitionTag, lastTransition )

/**
Define a single node activity entry. This is the first and last entry in any
node activity in which it is used.

@param state             Initial state of the activity
@param stateTransition   Transition to execute once the state is fulfilled

@see DEFINE_NODEACTIVITY
*/
#define SINGLE_NODEACTIVITY_ENTRY( stateTransition, state ) \
	STATE_TRIPLE_ENTRY( MeshMachine::KNoTag, stateTransition, state, MeshMachine::TNoTag )

/**
Define a routing node activity entry. Routing entries neither execute any
transition, nor wait in any state. These are useful only for redirecting the
path of execution in the state machine.

@param transitionTag  Condition on which the entry is entered
@param stateFork      Fork to decide the next transition to enter
*/
#define ROUTING_NODEACTIVITY_ENTRY( transitionTag, stateFork ) \
	THROUGH_TRIPLE_ENTRY( transitionTag, MeshMachine::TDoNothing, stateFork )

/**
Marks the end of a node activity.

@see DEFINE_NODEACTIVITY
*/
#define NODEACTIVITY_END() \
	TRIPLES_TABLE_END()



/**
Declare and export an activity map

@param map Name of the activity map
@see DECLARE_ACTIVITY_MAP
*/
#define DECLARE_EXPORT_ACTIVITY_MAP( map ) \
	struct map \
		{ \
		IMPORT_C static const MeshMachine::TNodeActivityMap& Self(); \
		static const MeshMachine::TNodeActivityMap iSelf; \
		static const MeshMachine::TNodeActivityMap::TStaticNodeActivity iData[]; \
		};

/**
Define and export the activity map

@param map Name of the activity map
@see DEFINE_ACTIVITY_MAP
*/
#define DEFINE_EXPORT_ACTIVITY_MAP( map ) \
	EXPORT_C const MeshMachine::TNodeActivityMap& map :: Self() {return iSelf;} \
	const MeshMachine::TNodeActivityMap map :: iSelf = {map :: iData[0]}; \
	const MeshMachine::TNodeActivityMap::TStaticNodeActivity map :: iData[] = {

/**
Declare an activity map.

For example,
@code
DECLARE_ACTIVITY_MAP(MyNodeActivityMap)
@endcode

This can then be passed into the constructor of a mesh machine node as follows.

@code
CMyMeshNode::CMyMeshNode(CConnectionProviderFactoryBase& aFactory)
    : CCoreConnectionProvider(aFactory, MyNodeActivityMap::Self())
	{
	...
@endcode

@param map Name of the activity map
*/
#define DECLARE_ACTIVITY_MAP( map ) \
	struct map \
		{ \
		inline static const MeshMachine::TNodeActivityMap& Self() {return iSelf;} \
		static const MeshMachine::TNodeActivityMap iSelf; \
		static const MeshMachine::TNodeActivityMap::TStaticNodeActivity iData[]; \
		}; \

/**
Define an activity map. An activity map is a collection of node activities. The activity map can be
based on another activity map or this macro can be used to define a standalone activity map.

Once defined an activity map can be passed into the constructor of a node, to define
what activities that node is capable of executing.

@code
DECLARE_DEFINE_ACTIVITY_MAP(MyNodeActivityMap)
	ACTIVITY_MAP_ENTRY(MyNodeActivities, MyFirstActivity)
	ACTIVITY_MAP_ENTRY(MyNodeActivities, MySecondActivity)
ACTIVITY_MAP_END_BASE(BaseActivities, BaseActivityMap)
@endcode

@param map Name of the activity map

@see ACTIVITY_MAP_END_BASE
@see ACTIVITY_MAP_END
*/
#define DEFINE_ACTIVITY_MAP( map ) \
	const MeshMachine::TNodeActivityMap map :: iSelf = {map :: iData[0]}; \
	const MeshMachine::TNodeActivityMap::TStaticNodeActivity map :: iData[] = {

/**
Define and declare an activity map.

@param map Name of the activity map

@see DEFINE_ACTIVITY_MAP
*/
#define DECLARE_DEFINE_ACTIVITY_MAP( map ) \
	DECLARE_ACTIVITY_MAP(map) \
	DEFINE_ACTIVITY_MAP(map)

/**
Create an entry in an activity map.

@param name_space Namespace of the activity
@param name       Name of the activity

@see DEFINE_ACTIVITY_MAP
*/
#define ACTIVITY_MAP_ENTRY( name_space, name ) &name_space::name::Self,

/**
Mark the end of an activity map. This macro should be used for standalone activity
maps.

@see DEFINE_ACTIVITY_MAP
*/
#define ACTIVITY_MAP_END() \
	NULL, \
	NULL \
	};

/**
Mark the end of an activity map. This macro should be used for an activity map based
on other activity maps.

@param name_space The namespace of the base map
@param base_map   The name of the base map

@see DEFINE_ACTIVITY_MAP
*/
#define ACTIVITY_MAP_END_BASE( name_space, base_map ) \
	NULL, \
	(MeshMachine::TNodeActivityMap::TStaticNodeActivity)&name_space::base_map::Self \
	};

namespace MeshMachine
{
/**
Base class for all node activity objects. Non custom node activities will use this by default.
**/
class CNodeActivityBase : public CBase,
                          public NetInterfaces::AApiExtBase,
                          protected NetStateMachine::ACore,
                          protected NetInterfaces::TInterfaceControl
	{
    friend class AMMNodeBase;
    friend class AContextStore; //to be able access NetStateMachine::ACore
    friend class AActivitySemaphore; //to be able access NetStateMachine::ACore

public:
	/**
	   Create a new activity. This should never be called by user code.

	   @param aActivitySig Context information about how the activity is to be started
	   @param aNode        The node to which this activity will belong.
	   @return A pointer to the new Activity base object. Ownership is transferred.
	*/
    IMPORT_C static CNodeActivityBase* NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode );

	/**
	Get the @c id of the activity.
	   @return The activity id of the activity
	*/
	IMPORT_C virtual TUint16 ActivityId() const;

	/**
	   Remove an originator from the originator list.

	   @param aIndex Index of originator to remove
	*/
	IMPORT_C void RemoveOriginator(TInt aIndex);

	/**
	Check if the activity is running.
	   @return ETrue if the activity is still running, otherwise EFalse.
	*/
	IMPORT_C virtual TBool IsIdle() const;

	/**
	   Put the activity into the idle state. This stops the activity running and notifies the mesh machine that
	   it's ok to delete this activity.
	*/
	IMPORT_C virtual void SetIdle();

	/**
	   Return the activity signature id of the activity. This may not necessarily be the same as the activity id
	   in the case of parallel activities, where the activity id will be [8 bit unique id|8 bit activity sig]

	   @return The activity signature id
	*/
    TUint ActivitySigId() const
   		{
  		return iActivitySig.iId;
   		}

	/**
	Get the current error state for the activity.
	   @return The activity's current error state. @c KErrNone indicates there is no error.
	*/
	TInt Error() const
		{
		return iError;
		}

	/**
	   Set the error state of the activity.

	   @param aError error code to set
	*/
	void SetError(TInt aError)
		{
		if (iError == KErrNone || aError == KErrNone)
    		{
    		iError = aError;
    		};
		}

	/**
	Get the id of the node that the last request from this activity was sent to.
	   @return Node id of the last node the activity has posted a request to
	*/
	const Messages::TNodeId PostedToId() const
		{
		return iPostedToId;
		}

	/**
	Get the id of the message that started this activity.
	   @return Message id of message that kicked off this activity
	*/
	const Messages::TNodeSignal::TMessageId KickOffMessageId() const
		{
		return Messages::TNodeSignal::TMessageId(iActivitySig.iKickOffMessageId, iActivitySig.iKickOffMessageRealm);
		}

	/**
	Get the id of the node that started this activity.
	   @return Node peer id of the node whose message first kicked off this activity
	*/
	const Messages::TNodePeerId& FirstOriginator() const
		{
		__ASSERT_DEBUG(iOriginators.Count(), User::Panic(KSpecAssert_ElemMeshMachActH, 1));
		return iOriginators[0];
		}

	/**
	In essence the same as FirstOriginator(). This should be used in preference in situations where the activity should
	be run in parallel, and therefore only ever have one originator.
	   @return Node peer id of the node whose message first kicked off this activity
	*/
	const Messages::TNodePeerId& SoleOriginator() const
		{
		__ASSERT_DEBUG(iOriginators.Count() == 1, User::Panic(KSpecAssert_ElemMeshMachActH, 2));
		return iOriginators[0];
		}

	/**
	   Post a request to a node.

	   @param aRecepient Endpoint for the message
	   @param aMessage   Message to send
	   @param aRecipientIdCritical If true, the postedTo id is set to the id of the recipient. If false, the postedTo id is set to null.
	   @see PostedToId
	*/
	IMPORT_C void PostRequestTo(const Messages::RNodeInterface& aRecepient, const Messages::TSignalBase& aMessage, const TBool aRecipientIdCritical = ETrue);
	/**
	   Post a request to a node.

	   @param aRecepient Endpoint for the message
	   @param aMessage   Message to send
	   @param aRecipientIdCritical If true, the postedTo id is set to the id of the recipient. If false, the postedTo id is set to null.
	   @see PostedToId
	*/
	IMPORT_C void PostRequestTo(const Messages::TNodeId& aRecepient, const Messages::TSignalBase& aMessage, const TBool aRecipientIdCritical = ETrue);

	/**
	   Manually set the postedTo id

	   @param aNodeId Node id to set the postedTo id to
	*/
	IMPORT_C void SetPostedTo(const Messages::TNodeId& aNodeId);

	/**
	   Clear the postedTo id
	*/
	IMPORT_C void ClearPostedTo();

#ifdef SYMBIAN_TRACE_ENABLE
	/**
	   @return the human readable name of the activity
	*/
    const TText8* ActivityName() const
        {
        return (iActivitySig.iName)? iActivitySig.iName : _S8("Undefined");
        }

	/**
	   @return the human readable description of the current node activity entry
	*/
    const TText8* CurrentTripleName() const
        {
        return ACore::CurrentTripleName();
        }
#endif

public:
	/**
	Cancels the activity. Only to be called by the meshmachine.
	@param aContext the context in which the activity is being executed
	@internalAll
	*/
	IMPORT_C virtual void Cancel(TNodeContextBase& aContext);

	/**
	Attempt to advance the activity one entry. Only to be called by the mesh machine
	@param aContext the context in which the activity is being executed
	@return Whether the activity advanced
	@internalAll
	*/
	IMPORT_C virtual TBool Next(TNodeContextBase& aContext);

	/**
	Find the originator matching the parameters
	@param aPeerToFind Matching criteria
	@return Index of the matching originator. KErrNotFound if not found.
	@internalAll
	*/
	IMPORT_C TInt FindOriginator(const Messages::RNodeInterface& aPeerToFind) const;

	/**
   	Find the originator matching the parameters
	@param aPeerToFind Matching criteria
	@return Index of the matching originator. KErrNotFound if not found.
	@internalAll
	*/
	IMPORT_C TInt FindOriginator(const Messages::TRuntimeCtxId& aPeerToFind) const;

	/**
   	Find the originator matching the parameters
	@param aOriginator xx
	@return Index of the matching originator. KErrNotFound if not found.

	@internalAll
	*/
	IMPORT_C TInt FindOriginator(const Messages::TNodePeerId& aOriginator) const;

	/**
	Post a message to an originator
	@param aOriginator originator to post the message to
	@param aMessage    message to post
	@return Whether the posting succeeded
	@internalAll
	*/
	IMPORT_C TBool PostToOriginator(const Messages::TNodePeerId& aOriginator, const Messages::TSignalBase& aMessage) const;

	/**
    Post a message to all originators
	@param aMessageSig the message to post
	@param aFlagsToSet Flags to set on the peer as the message is being sent
	@param aFlagsToClear Flags to cleared on the peer as the message is being sent
	@return number of originators the message was posted to
	@internalAll
	*/
	IMPORT_C TInt PostToOriginators(const Messages::TSignalBase& aMessageSig, TUint32 aFlagsToSet = 0, TUint32 aFlagsToClear = 0);

	/**
	Calls cancel on current state. Sends TError to all originators and sets activity idle
	@param aContext the context in which the activity is being executed
	@param aIsNodeBeingDestroyed  indicate to the activity as to whether the node is being destroyed
	@internalAll
	*/
	IMPORT_C void Abort(TNodeContextBase& aContext, TBool aIsNodeBeingDestroyed = EFalse);

	
protected:
	/**
	Constructor for CNodeActivityBase
	@param aActivitySig Signature with which to create the activity
	@param aNode        Node which will own the activity
	*/
	IMPORT_C explicit CNodeActivityBase(const TNodeActivity& aActivitySig, AMMNodeBase& aNode);
	/**
	Destructor. If the Activity is running in error mode, a message is sent to the originator.
	*/
	IMPORT_C virtual ~CNodeActivityBase();

	/**
	Destroy the activity.

	Used primarily by preallocated activities to return extracted space
	*/
    virtual void Destroy()
    	{
    	delete this;
    	};

	/**

	@param aInterfaceId id of requested interface
	@return Interface control for accessing the extension interfaces of the activity
	@see TInterfaceControl
	*/
    IMPORT_C virtual NetInterfaces::TInterfaceControl* DoFetchInterfaceControlL(TInt aInterfaceId);

	/**
	Signal the activity that an event has happened in the mesh machine. Used for waking up sleeping activities
	which use mutexes.

	@param # The context in which the activity is being executed
	@return ETrue if the activity was awoken
	@see AActivitySemaphore
	*/
	virtual TBool Signal(TNodeContextBase& /*aContext*/) { return EFalse; };

protected:
	/**
	Test whether a activity can start given the current context. If it can, the first transition will be executed.
	Note that this is a static method, and as such the activity hasn't been instanciated when this is called

	@param aContext the context in which the activity may be executed
	@param aActivitySig the activity which we are testing for the accept condition
	@param aTransitionTag the condition which must be matched by the first entry for the activity to be accepted. Set to KExecuteAlways to skip this check

	@return the first entry triple for the activity if it's accepted. NULL otherwise
	*/
	static const NetStateMachine::TStateTriple* Accept(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, TInt aTransitionTag);

	/**
	Start a new activity. The first transition should have been run within the @c Accept() method before this is called.

	@param aContext  The context to start the activity in
	@param aOriginator  The peer that requires this activity to start
	@param aFirst       First entry triple in the activity, as returned by @c Accept()
	*/
	IMPORT_C virtual void StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const NetStateMachine::TStateTriple& aFirst);

protected:
	/**
	Append self to the node's list of running activities.

	Should only be accessed from @c Activity::NewL. Generally activities can choose to be inserted or appended
	(if they do not choose they are appended by default). When inserting, extreme caution must be taken, as
	this behavior is reserved for destroying activities.
	*/
	IMPORT_C void AppendActivityL();

	/**
	Append self to the node's list of running activities. This should only be called if you are certain that
	the activity list has space for the append.
	*/
	IMPORT_C void AppendPreallocatedActivity();

	/**
	Insert an activity at the start of the node's list of running activities.
	*/
	IMPORT_C void InsertPreallocatedDestroyActivity();

	/**
	Borrow some preallocated memory from the node. This preallocated memory is used for activities that
	absolutely cannot fail in any scenario, such as for Destroying the node. For this reason, when the
	node is created, some memory is allocated so that a destroying activity can't even fail in an out
	of memory situation.

	This method is static as the memory must be borrowed before the activity object is constructed.

	The memory is returned using @c ReturnPreallocatedSpace().

	@param aNode The node that owns the preallocated space. This must be the node that the activity runs on.
	@param aSize Size of buffer to allocate.

	@return A pointer to the allocated block of memory
	*/
	IMPORT_C static TAny* BorrowPreallocatedSpace(AMMNodeBase& aNode, TUint aSize);

	/**
	Return preallocated space to the node. The node does not have to be passed in as a parameter as it will
	already be a member of the activity.

	@param aSpace Memory buffer to return.
	*/
	IMPORT_C void ReturnPreallocatedSpace(TAny* aSpace);
	
	/**
	Test whether aContext carries a message that is to be expected by 'this' in its current state. 
	The method is effectivelly a filter that hides the messages flowing throught the node, but not
	intended for 'this'. The method will check:
	- if aContext carries a message from PostedToId (if set) then the message should be presented to 'this'.
	- if aContext carries a message from one of the originators then the message should be presented to 'this'.
	@return ETrue if the sender of the current message matches PostedToId if it is set.
	*/
	IMPORT_C TBool MatchSender(const TNodeContextBase& aContext) const;	

protected:
	/**
	The node the activity is running on
	*/
	AMMNodeBase& iNode;

	/**
	All the nodes that have started the same activity
	*/
	RArray<Messages::XNodePeerId> iOriginators;

private: //Shouldn't be accessed directly
	TInt     iError;    //Risk of failure is a generic property of an activity.
	                    //Activities may choose to use external error handling activities,
	                    //or may choose to handle errors locally. In the latter case,
	                    //the activity may want to know it's running an error mode
	                    //(by setting this member).
	                    //iError must be cleared before the activity goes out of scope
	                    //to indicate the error has been handled.

	const TNodeActivity& iActivitySig;

	// Last node a message was sent to
	Messages::TNodeId iPostedToId;
	};


/**
Activity type that generates a unique activity id every time it is instantiated.
The id is generated from the @c <TNodeActivityId::EActivityParallelRangeMin,TCFNodeActivityId::EActivityParallelRangeMax>
range. The id should never be found in a static activity map.
A new instance id is created rather than adding a new originator to the existing activity.
*/
class CNodeParallelActivityBase : public CNodeActivityBase

	{
public:
	/**
    Create a new activity. This should never be called by user code.

	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	@return A pointer to the new activity. Ownership is transfered.
	*/
    IMPORT_C static CNodeActivityBase* NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode );

	/**
	Get the activity id
	@return The activity id of the activity
	*/
   	IMPORT_C virtual TUint16 ActivityId() const;

protected:
	/**
	For use by custom activity NewLs to generate the unique part of the activity id.
	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	@return Generated unique component of activity id
	*/
	IMPORT_C static TUint GetNextActivityCountL( const TNodeActivity& aActivitySig, const AMMNodeBase& aNode );

	/**
	Constructor for CNodeParallelActivityBase
	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	@param aNextActivityCount The unique part of the activity id
	*/
    IMPORT_C CNodeParallelActivityBase( const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aNextActivityCount );

protected:
	/**
	The activity id. The id format is [8 bit unique id|8 bit activity sig].
	*/
    TUint16 iActivityId;
	};

/**
   Base class for parallel activities which store their kickoff message.

   @see CNodeParallelActivityBase
*/
class CNodeParallelMessageStoreActivityBase : public CNodeParallelActivityBase
	{
public:
	IMPORT_C static CNodeActivityBase* NewL( const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode );
	IMPORT_C ~CNodeParallelMessageStoreActivityBase();

	/**
	   @return Kick off message for this activity
	*/
	IMPORT_C Messages::TSignalBase& Message();

protected:
	IMPORT_C virtual void StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const NetStateMachine::TStateTriple& aFirst);
	void SaveMessageL(Messages::TSignalBase& aMessage);
	
	IMPORT_C CNodeParallelMessageStoreActivityBase( const MeshMachine::TNodeActivity& aActivitySig,
		MeshMachine::AMMNodeBase& aNode, TUint aNextActivityCount );

private:
	Messages::TSignalBase* iMsg;
	TBuf8<__Align8(Messages::TSignalBase::KMaxInlineMessageSize + Messages::TSignalBase::KMaxUnstoredOverhead)> iMsgBuf;
	};

/**

If an activity has a transition or fork that is blocked by a mutex, the context must be stored so
that when the transition or fork is unblocked it would be able to continue with the context that
it had before it was blocked. If this aggregate wasn't used in the previous scenario, the context
of the event that triggered the unblocking would be used, and this may have the wrong message, or
event originator set.

Error recovery is another scenario this class is useful in.
*/
class AContextStore
    {
public:
    /**
    Interface id
    */
    static const TInt KInterfaceId = 0x102864DC;

protected:
    /**
    Constructor for AContextStore
    */
    explicit AContextStore()
        {
        }
    /**
    Destructor for AContextStore
    */
    ~AContextStore()
        {
    	iContextDesc.Close();
        }

public:
	/**
	Used for error recovery. If the context is stored, loads the stored context and reruns the last transition that was run.

	@param aActivity The activity to retry
	@param aContext  The context within which the retrying is taking place. NOTE: This is not the stored context

	@see StoreContext
	@see LoadContext
	*/
	IMPORT_C void Retry(CNodeActivityBase& aActivity, TNodeContextBase& aContext);

    /**
	Store context in buffer. Designed to be called from a transition to store the transitions context for error recovery or
	to wait on a mutex.

	@param aContext The context to store
	@return Error code. @c KErrNone if storage is successful.
	*/
	IMPORT_C TInt StoreContext(const TNodeContextBase& aContext);

	/**
	Check of the context is stored.
	@return @c ETrue if a context is stored. @c EFalse otherwise.
	*/
	IMPORT_C TBool IsStored() const;

	/**
	Get the id of the message which requested @c Retry()
	@return Message Id of message which kicked off the @c ::Retry

	@see AContextStore::Retry
	*/
 	IMPORT_C const Messages::TNodeSignal::TMessageId& RetryingForMessageId() const; //Needs to be moved to error-recoverable activity class

protected:
	/**
	Load a stored context. Once the stored context has been loaded the status of @c iContextDesc is undefined and load shouldn't
	be called again until something has been stored.

	The pointer returned uses memory allocated in the @c aCtxBuff that is passed in, and as such, does not need to be freed. However @c aCtxBuff and @c aMsgBuff
	must be cleaned up after use.

	@param aNode The node for the context
	@param aNodeActivity The activity for the context.
	@param aCtxBuff  A memory buffer in which the context will be created.
	@param aMsgBuff  A memory buffer in which the message will be created.
	@param aDummy    Will become the recipient node id in the context.

	@return Pointer to loaded context
	*/
	IMPORT_C TNodeContextBase* LoadContext(AMMNodeBase& aNode, CNodeActivityBase* aNodeActivity, TDes8& aCtxBuff, TDes8& aMsgBuff, const Messages::TNodeId& aDummy);

protected:
	/**
    Buffer to store the context.
	*/
	RBuf8 iContextDesc;
	/**
	Message id of the message which kicked off the retry attempt
	*/
	Messages::TNodeSignal::TMessageId iRetryingForMessageId;
	};

/**
Aggregate class for activities which wish to use mutexes.

After a serialised state or transition has been unblocked, signalled and invoked, AActivitySemaphore
clears all of the synchronisation related information (e.g stored context), assuming that the job has
been done. Sometimes however the serialised state, upon more careful inspection of the environment
(context), may decide that it still does not want to be executed and it wishes to sleep again.

In such case it would call Wait() and return @c EIgnore from its @c TransitionTag(). The same applies to a
serialised transition. It may want to call Wait() instead of, for example sending a request message.

After calling Wait() the serialised state will be woken up when the policy matches, which allows the serialised state
to finish its job.
 */
class AActivitySemaphore : public AContextStore
    {
public:
    /**
    Interface id
    */
    static const TInt KInterfaceId = 10015; //Normally a UID - 10015 for compatibility reasons

public:
	/**
	Park a state.

	@param aContext The context which the state is to run in. This will be stored

	@return @c KErrNone if successful. System wide error code otherwise
	*/
	IMPORT_C static TInt ParkState(const TNodeContextBase& aContext);

	/**
	Unpark a state.

	@param aContext The context which the state is to run in.

	@return @c KErrNone if successful. System wide error code otherwise
	*/
	IMPORT_C static TInt UnparkState(const TNodeContextBase& aContext);

	/**
	Park a transition

	@param aContext The context which the transition is to run in.
	*/
	IMPORT_C static void ParkTransitionL(const TNodeContextBase& aContext);

	/**
	Signals to the activity that an event has occurred. Used for waking up sleeping activities
	which use mutexes. The activity is expected to check if the mutex has now cleared.

	@param aContext Current context in the state machine.

	@return @c ETrue if the state or transition has been unparked
	*/
	IMPORT_C TBool Signal(TNodeContextBase& aContext);

	/**
	Tell the activity to wait. The activity will wait until Signal() is called.
	*/
	IMPORT_C void Wait();

	/**
	Check if the activity is waiting
	@return ETrue if the activity is currently waiting
	*/
	TBool IsWaiting() const
		{
		__ASSERT_DEBUG(!(iFlags&KIsWaiting) || IsStored(), User::Panic(KSpecAssert_ElemMeshMachActH, 3));

		return iFlags&KIsWaiting;
		}

protected:
    /**
    Constructor for AActivitySemaphore
    */
    explicit AActivitySemaphore()
    :   iFlags(0)
		{
        }
    /**
    Destructor for AActivitySemaphore
    */
    ~AActivitySemaphore()
        {
        }

protected:
	/**
	Set the @c isWaiting flag
	*/
	inline void SetIsWaiting() { iFlags|=KIsWaiting; };
	/**
	Clear the @c isWaiting flag
	*/
	inline void ClearIsWaiting() { iFlags&=~KIsWaiting; };

	/**
	Check if the WillWait flag is set. The WillWait flag indicates whether the activity will be in a waiting state at the end of the signal function.
	This is distinct from "is waiting" which indicates whether the activity was waiting on entry to the Signal()
	function.

	@return ETrue if the WillWait flag is set
	*/
	inline TBool WillWait() const { return (iFlags&KWillWait)==KWillWait; };
	/**
	Set the willWait flag
	*/
	inline void SetWillWait() { iFlags|=KWillWait; };
	/**
	Clear the willWait flag
	*/
	inline void ClearWillWait() { iFlags&=~KWillWait; };

private:
	//Is waiting for mutex? == not idle yet, even if last triple
 	//iIsWaiting prevents Idle condition following the last
	//transition (in case the transition has parked the activity
	//and wants to be reexecuted). When reexecuting, the activity
	//mustn't be idle (iIsWaiting has to be true), on the
	//other hand the transition may to park the activity again
	//We need to distinguish the entry value of iIsWaiting from
	//the exit value of iIsWaiting, we hance need this aditional
	//flag.

	inline TBool IsTransition() const { return (iFlags&KIsTransition)==KIsTransition; };
	inline void SetIsTransition() { iFlags|=KIsTransition; };
	inline void ClearIsTransition() { iFlags&=~KIsTransition; };

	enum { KIsWaiting = 0x1, KWillWait = 0x2, KIsTransition = 0x4 };

	TUint8 iFlags;
    };

/**
Activity class base for activities which wish to use synchronisation or retries.
*/
class CNodeRetryActivity : public CNodeActivityBase, public AActivitySemaphore,
                public ITFHIERARCHY_2(CNodeRetryActivity, AContextStore, AActivitySemaphore)
	{
public:
	/**
	Defines a helper list of interfaces.
 	*/
	typedef ITFHIERARCHY_2(CNodeRetryActivity, AContextStore, AActivitySemaphore) TIfStaticFetcherNearestInHierarchy;

public:
	/**
    Create a new activity. This should never be called by user code.

	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	@return A pointer to the new object. Ownership is transfered.
	*/
    IMPORT_C static CNodeActivityBase* NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode );

	/**
	Fetch the context store interface
	@param aInterface pointer into which a pointer to the interface will be placed.
	*/
    IMPORT_C void ReturnInterfacePtrL(AContextStore*& aInterface);

	/**
	Fetch the activity semaphore interface
	@param aInterface On return, contains a pointer to the interface.
	*/
    IMPORT_C void ReturnInterfacePtrL(AActivitySemaphore*& aInterface);

	/**
	Check if the activity has stopped running
	@return @c ETrue if the activity is still running, otherwise @c EFalse.
	*/
    IMPORT_C virtual TBool IsIdle() const;

	/**
	Put the activity into the idle state. This stops the activity running and notifies the mesh machine that
	it is ok to delete this activity.
	*/
    IMPORT_C virtual void SetIdle();

protected:
	/**
	Signal the activity that an event has occurred and that it is worthwhile checking
	to see if the mutex has now cleared.

	@param aContext Current context in the state machine.

	@return @c ETrue if state or transition has been unparked
	*/
	IMPORT_C virtual TBool Signal(TNodeContextBase& aContext);

    /**
    Constructor for CNodeRetryActivity
	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
    */
    IMPORT_C CNodeRetryActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode );
	};

/**
Base class for activities that run in parallel and can be synchronised or retried.
*/
class CNodeRetryParallelActivity : public CNodeParallelActivityBase, public AActivitySemaphore,
                public ITFHIERARCHY_2(CNodeRetryParallelActivity, AContextStore, AActivitySemaphore)
	{
public:
	/**
	Defines a helper list of interfaces.
 	*/
 	typedef ITFHIERARCHY_2(CNodeRetryParallelActivity, AContextStore, AActivitySemaphore) TIfStaticFetcherNearestInHierarchy;

public:
	/**
    Create a new activity. This should never be called by user code.

	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	@return A pointer to the new object. Ownership is transfered.
	*/
    IMPORT_C static CNodeActivityBase* NewL( const TNodeActivity& aActivitySig, AMMNodeBase& aNode );

	/**
	Fetch the context store interface
	@param aInterface On return, contains a pointer to the store interface
	*/
    IMPORT_C void ReturnInterfacePtrL(AContextStore*& aInterface);

	/**
	Fetch the activity semaphore interface
	@param aInterface On return, contains a pointer to the semaphore interface
	*/
    IMPORT_C void ReturnInterfacePtrL(AActivitySemaphore*& aInterface);

	/**
	Check if the activity has stopped
	@return @c ETrue if the activity is still running, otherwise @c EFalse
	*/
    IMPORT_C virtual TBool IsIdle() const;

	/**
	Put the activity into the idle state. This stops the activity running and notifies the mesh machine that
	it is ok to delete this activity.
	*/
    IMPORT_C virtual void SetIdle();

protected:
	/**
	Signal to the activity that an event has occurred and that it is worthwhile checking
	to see if the mutex has now cleared.

	@param aContext Current context in the state machine.

	@return @c ETrue if state or transition has been unparked
	*/
	IMPORT_C virtual TBool Signal(TNodeContextBase& aContext);

	/**
    Constructor for CNodeRetryParallelActivity

	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	@param aActivitiesCount The unique part of the activity id
    */
    IMPORT_C CNodeRetryParallelActivity( const TNodeActivity& aActivitySig, AMMNodeBase& aNode, TUint aActivitiesCount );
	};

/**
Aggregate originator array template for activities that use preallocated space.
This object has a fixed size array to hold the originators which will be allocated from the preallocated space
when the node activity object is created.
*/
template <TInt ORIGINATORSCOUNT>
class APreallocatedOriginators
	{
protected:
	/**
	Initialise the array and ensure it is empty as it should be on creation.
	Generally, iOriginators from the activity will be passed into this as a reference. A new
	RArray will then be created using the preallocated space.

	@param aOriginators Array of originators for which to preallocate space
	*/
	explicit APreallocatedOriginators(RArray<Messages::XNodePeerId>& aOriginators)
	:	iOriginatorsRef(aOriginators)
		{
		iOriginatorsRef = RArray<Messages::XNodePeerId>(sizeof(Messages::XNodePeerId), (Messages::XNodePeerId*)iOriginatorBuf, ORIGINATORSCOUNT);
		for (TInt i = iOriginatorsRef.Count() - 1; i >= 0; --i)
			{
			iOriginatorsRef.Remove(i);
			}
		}
    /**
    Destructor for APreallocatedOriginators.
    */
	~APreallocatedOriginators()
		{
		iOriginatorsRef = RArray<Messages::XNodePeerId>();
		}

private:
	//The originator's list
	RArray<Messages::XNodePeerId>& iOriginatorsRef;
    //Preallocated space in the originator's list
    TUint8 iOriginatorBuf[__Align8(sizeof(Messages::XNodePeerId) * ORIGINATORSCOUNT)];
	};

/**
Base for preallocated node activity class
*/
template <TInt ORIGINATORSCOUNT>
class CPreallocatedNodeActivityBase : public MeshMachine::CNodeActivityBase,
                                      protected MeshMachine::APreallocatedOriginators<ORIGINATORSCOUNT>
/**
@internalTechnology
*/
	{
public:
	/**
    Create a new activity. This should never be called by user code.

	@param aActivitySig Context information about how the activity is to be started
	@param aNode        The node to which this activity will belong.
	*/
    static MeshMachine::CNodeActivityBase* New(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
    	{
   		TAny* space = BorrowPreallocatedSpace(aNode, sizeof(CPreallocatedNodeActivityBase));
		CPreallocatedNodeActivityBase* self = new (space) CPreallocatedNodeActivityBase(aActivitySig, aNode);
		self->AppendPreallocatedActivity();
		return self;
    	}

protected:


	CPreallocatedNodeActivityBase(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
	:	CNodeActivityBase(aActivitySig, aNode),
		APreallocatedOriginators<ORIGINATORSCOUNT>(iOriginators)
		{
		}

	/**
	Destroy the activity. Return the preallocated space and call the destructor directly. i.e. not though delete
	as delete would try and release the memory again
	*/
	virtual void Destroy()
		{
		ReturnPreallocatedSpace(this);
		this->~CPreallocatedNodeActivityBase(); //Run the destructor
		}
private:
	/**
	Private NewL with no implementation to hide the CNodeActivityBase::NewL
	Creation of preallocated activities doesn't fail and hence a non-leaving ::New should be used instead
	*/
    static MeshMachine::CNodeActivityBase* NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode);
	};

//-=========================================================
//
// CPreallocatedNodeActivityBase
//
//-=========================================================
template <TInt ORIGINATORSCOUNT>
class CPreallocatedNodeRetryActivity : public MeshMachine::CNodeRetryActivity,
                                      protected MeshMachine::APreallocatedOriginators<ORIGINATORSCOUNT>
/**
@internalTechnology
*/
	{
public:
    static MeshMachine::CNodeActivityBase* New(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
    	{
   		TAny* space = BorrowPreallocatedSpace(aNode, sizeof(CPreallocatedNodeRetryActivity));
		CPreallocatedNodeRetryActivity* self = new (space) CPreallocatedNodeRetryActivity(aActivitySig, aNode);
		self->AppendPreallocatedActivity();
		return self;
    	}

protected:
	CPreallocatedNodeRetryActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
	:	CNodeRetryActivity(aActivitySig, aNode),
		APreallocatedOriginators<ORIGINATORSCOUNT>(iOriginators)
		{
		}

	virtual void Destroy()
		{
		ReturnPreallocatedSpace(this);
		this->~CPreallocatedNodeRetryActivity(); //Run the destructor
		}
private:
	/*
	Private NewL with no implementation to hide the CNodeActivityBase::NewL
	Creation of preallocated activities doesn't fail and hence a non-leaving ::New should be used instead*/
    static MeshMachine::CNodeActivityBase* NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode);
	};

} //namespace MeshMachine

#endif //SYMBIAN_MM_ACTIVITIES_H

