// Copyright (c) 2005-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:
// Dummy implementation file for a SubConnection Provider
// 
//

/**
 @file
 @internalComponent
*/

#include <comms-infras/ss_log.h>
#include <comms-infras/corescpractivities.h>
#include <cs_subconparams.h>
#include <cs_subconevents.h>

#include "dummypr_subconnprov.h"
#include "dummypr_metaconnprov.h"
#include "activityTest.h"

#include <elements/sd_mintercept.h>

#ifdef __CFLOG_ACTIVE
	#define KDummySCPRTag KESockConnectionTag
#endif

using namespace ESock;
using namespace MeshMachine;

//We reserve space for two preallocated activities that may start concurrently on the SCPR
//node: destroy and data client stop.
static const TUint KDefaultMaxPreallocatedActivityCount = 2;
static const TUint KMaxPreallocatedActivitySize = sizeof(MeshMachine::CNodeRetryParallelActivity) + sizeof(MeshMachine::APreallocatedOriginators<4>);
static const TUint KDummySCPRPreallocatedActivityBufferSize = KDefaultMaxPreallocatedActivityCount * KMaxPreallocatedActivitySize;

namespace DummySCPRStates
{
DEFINE_SMELEMENT(TRaiseGranted, NetStateMachine::MStateTransition, DummySCPRStates::TContext)
void TRaiseGranted::DoL()
	{
	if (iContext.Node().incomingStatus == TRUE)
		{
		//generate paramsgranted.
		CSubConGenEventParamsGranted* grantedevent = CSubConGenEventParamsGranted::NewL();
	    grantedevent->SetFamily(KSubConQoSFamily);
	    iContext.Node().NotifyClientsL(*grantedevent);
	    iContext.Node().incomingStatus = FALSE;
		}
	}

DEFINE_SMELEMENT(TAwaitingReBindTo, NetStateMachine::MState, DummySCPRStates::TContext)
TBool TAwaitingReBindTo::Accept()
	{
	const TLayerSelectionInfo* selectionInfo = static_cast<const TLayerSelectionInfo*>(
		iContext.Node().AccessPointConfig().FindExtension(TLayerSelectionInfo::TypeId()));
	ASSERT(selectionInfo); // should always be there
	
	TCFDataClient::TBindTo* bindToMsg = Messages::message_cast<TCFDataClient::TBindTo>(&iContext.iMessage);
	if (bindToMsg && iContext.Node().ServiceProvider() && bindToMsg->iNodeId != iContext.Node().ServiceProvider()->RecipientId())
	    {
	    if (TCprConfigModifier::Is(selectionInfo->CprConfig(), TCprConfigModifier::ESCPRHangOnRebind))
	        {
	        return ETrue;
	        }
	    else if (TCprConfigModifier::Is(selectionInfo->CprConfig(), TCprConfigModifier::ESCPRFailOnRebind))
	        {
	        iContext.iMessage.ClearMessageId();
	        Messages::RClientInterface::OpenPostMessageClose(iContext.NodeId(), iContext.iSender, 
                Messages::TEBase::TError(KErrAbort).CRef());
	        }
	    }
	return EFalse;
	}

DEFINE_SMELEMENT(TAwaitingBrokenStart, NetStateMachine::MState, DummySCPRStates::TContext)
TBool TAwaitingBrokenStart::Accept()
	{
	const TLayerSelectionInfo* selectionInfo = static_cast<const TLayerSelectionInfo*>(
		iContext.Node().AccessPointConfig().FindExtension(TLayerSelectionInfo::TypeId()));
	ASSERT(selectionInfo); // should always be there

	return (iContext.iMessage.IsMessage<TCFDataClient::TStart>() && 
			TCprConfigModifier::Is(selectionInfo->CprConfig(), TCprConfigModifier::ESCPRHangOnStart));
	}

DEFINE_SMELEMENT(TCancelPreviousSelfRequest, NetStateMachine::MStateTransition, DummySCPRStates::TContext)
void TCancelPreviousSelfRequest::DoL()
    {
    iContext.iNodeActivity->PostRequestTo(iContext.Node().Id(), Messages::TEBase::TCancel().CRef());
    }

DEFINE_SMELEMENT(TRebindSelf, NetStateMachine::MStateTransition, DummySCPRStates::TContext)
void TRebindSelf::DoL()
    {
    iContext.iNodeActivity->PostRequestTo(iContext.Node().Id(), TCFDataClient::TBindTo(Messages::TNodeId::NullId()).CRef());
    }




CrazyIdle::~CrazyIdle()
    {
    ASSERT(PostedToNodeId()==Messages::TNodeId::NullId());
    }

MeshMachine::CNodeActivityBase* CrazyIdle::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
    {
    return new(ELeave)CrazyIdle(aActivitySig, aNode);
    }

DEFINE_SMELEMENT(CrazyIdle::TAwaitingCancelled, NetStateMachine::MState, DummySCPRStates::TContext)
TBool CrazyIdle::TAwaitingCancelled::Accept()
    {
    if (iContext.iMessage.IsMessage<Messages::TEBase::TError>())
        {
        ASSERT(iContext.iNodeActivity);
        iContext.iNodeActivity->SetPostedTo(iContext.iNodeActivity->SoleOriginator().Peer().RecipientId());
        }
    return EFalse;
    }
}



namespace DummySCprParamsRequest
{
#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
DECLARE_DEFINE_NODEACTIVITY(ECFActivityParamRequest, dummySCprParamRequest, TCFScpr::TSetParamsRequest)
	NODEACTIVITY_ENTRY(KNoTag, PRStates::TRespondWithCurrentParams, PRStates::TAwaitingParamRequest,  MeshMachine::TNoTag)
#else
DECLARE_DEFINE_NODEACTIVITY(ECFActivityParamRequest, dummySCprParamRequest, TCFScpr::TParamsRequest)
	NODEACTIVITY_ENTRY(KNoTag, SCprStates::TRespondWithCurrentParams, SCprStates::TAwaitingParamRequest,  MeshMachine::TNoTag)
#endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
NODEACTIVITY_END()
}

namespace DummyBindToActivity
{
DECLARE_DEFINE_NODEACTIVITY(ECFActivityBindTo, dummyBindTo, TCFDataClient::TBindTo)
	FIRST_NODEACTIVITY_ENTRY(DummySCPRStates::TAwaitingReBindTo, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, CoreStates::TNeverAccept,  MeshMachine::TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
NODEACTIVITY_END()
}

namespace DummyBreakStartActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityStart, dummyBreakSCPrStart, TCFDataClient::TStart, PRActivities::CStartActivity::NewL)
    FIRST_NODEACTIVITY_ENTRY(DummySCPRStates::TAwaitingBrokenStart, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, CoreStates::TNeverAccept,  MeshMachine::TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
NODEACTIVITY_END()
}

namespace DummyStartActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityStart, dummySCPrStart, TCFServiceProvider::TStart, PRActivities::CStartActivity::NewL)
    FIRST_NODEACTIVITY_ENTRY(CoreNetStates::TAwaitingStart, MeshMachine::TNoTag)
 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSendStarted, MeshMachine::TNoTag)
 	LAST_NODEACTIVITY_ENTRY(KNoTag, DummySCPRStates::TRaiseGranted)
NODEACTIVITY_END()
}

namespace CrazyIdleActivity
{
//CrazyIdleActivity is used to test yet another angle of the meshmachine cancelling behaviour.
//What it does is:
//(1) responds to TIdle with an attempt to bind the sender, then, without waiting for the bind to complete
//(2) responds to TIdle normally (by deleting the sender)
//(3) cancells the bind request
//What it tests is:
//For two related nodes and upon the teardown of their relation there is an obligation to synchronise the activities
//running on the nodes and awaiting responses from each other. This obligation is put on the requestee, i.e.: a node that perfomes
//an activity on behalf of a leaving node should gracefully terminate that activity (by having the activity respond to the requestor. 
//That obligation therefore doesn't rest on the requestor (someone, but not everyone, needs to do something).
//There's trivial race condition arising from this distribution of responsibility, i.e.: the requestor activity may decide to 
//cancel when the relation is being terminated and TCancel may hit void. Activities must be resilient to this and not send
//TCancels to disappearing nodes. CrazyIdleActivity tests precislely this: it initaites an activity (TBindTo), then tears down the
//relation and cancels the previously initiated activity (TBindTo). CrazyIdleActivity must wrap up gracefully. 
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityDataClientIdle, crazyIdle, TCFControlProvider::TIdle, DummySCPRStates::CrazyIdle::NewL)
    FIRST_NODEACTIVITY_ENTRY(CoreNetStates::TAwaitingDataClientIdle, MeshMachine::TNoTag)
    //Issue TBindTo to self (this will then bind the data client reporting TIdle). Wait for BindTo activity to start before 
    //telling the dataclient to go away (TDestroy) as otherwise TBindTo won't make it in sending TBindTo to the dataclient.
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, DummySCPRStates::TRebindSelf, DummySCPRStates::TNoTagWaitForBindTo)
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::THandleDataClientIdle, MeshMachine::TNoTag)
    //There's an additional test peformed by DummySCPRStates::CrazyIdle::TAwaitingCancelled. The state sets the postedto of CrazyIdle
    //to point at the dataclient and CrazyIdle::~CrazyIdle asserts that that postedto is cleared. Currently PostedTo isn't cleared automatically - some people
    //argued that it shouldn't and that activities should clear postedto whenever it's good for them. Unfortunatelly some activities are
    //a bit lousy doing this and in result they can store a postedto pointing a node that has responded to the request a long time ago
    //and above all a node that may have a long time ago left. A facility has been added to meshmachine to clear postedto when the node pointed
    //at it actually leaves. This facility is tested collectivelly by DummySCPRStates::CrazyIdle::TAwaitingCancelled and CrazyIdle::~CrazyIdle
    NODEACTIVITY_ENTRY(KNoTag, DummySCPRStates::TCancelPreviousSelfRequest, DummySCPRStates::CrazyIdle::TAwaitingCancelled, DummySCPRStates::TNoTagWaitNoDataClients)
    LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
NODEACTIVITY_END()
}



// Activity Map For test-code ridden scpr
namespace DummySCPRStates
{
DEFINE_ACTIVITY_MAP(stateMap)
   ACTIVITY_MAP_ENTRY(DummySCprParamsRequest, dummySCprParamRequest)
   ACTIVITY_MAP_ENTRY(DummyBindToActivity, dummyBindTo)
   ACTIVITY_MAP_ENTRY(DummyBreakStartActivity, dummyBreakSCPrStart)   
   ACTIVITY_MAP_ENTRY(DummyStartActivity, dummySCPrStart)
   ACTIVITY_MAP_ENTRY(CrazyIdleActivity, crazyIdle)     
ACTIVITY_MAP_END_BASE(SCprActivities, coreSCprActivities)
}

// Activity Map For vanilla cpr
namespace VanillaDummySCPRStates
{
DECLARE_DEFINE_ACTIVITY_MAP(stateMap)
        ACTIVITY_MAP_ENTRY(CancelTestBindToActivity, CancelBindTo)   
ACTIVITY_MAP_END_BASE(SCprActivities, coreSCprActivities)
}

CDummySubConnectionProvider* CDummySubConnectionProvider::NewL(ESock::CSubConnectionProviderFactoryBase& aFactory)
    {
    CDummySubConnectionProvider* self = new (ELeave) CDummySubConnectionProvider(aFactory, DummySCPRStates::stateMap::Self());
    CleanupStack::PushL(self);
    self->ConstructL(KDummySCPRPreallocatedActivityBufferSize);
    CleanupStack::Pop(self);
    return self;
    }

CDummySubConnectionProvider* CDummySubConnectionProvider::NewVanillaL(ESock::CSubConnectionProviderFactoryBase& aFactory)
    {
    CDummySubConnectionProvider* self = new (ELeave) CDummySubConnectionProvider(aFactory, VanillaDummySCPRStates::stateMap::Self());
    CleanupStack::PushL(self);
    self->ConstructL(KDummySCPRPreallocatedActivityBufferSize);
    CleanupStack::Pop(self);
    return self;
    }


CDummySubConnectionProvider::CDummySubConnectionProvider(CSubConnectionProviderFactoryBase& aFactory, const MeshMachine::TNodeActivityMap& aActivityMap)
:CCoreSubConnectionProvider(aFactory, aActivityMap)
	{
	LOG_NODE_CREATE(KDummySCPRTag, CDummySubConnectionProvider);
	}

CDummySubConnectionProvider::~CDummySubConnectionProvider()
	{
	LOG_NODE_DESTROY(KDummySCPRTag, CDummySubConnectionProvider);
	}


void CDummySubConnectionProvider::SetToIncomingL()
	{
 	_LIT(KName,"Test1");
 	TBuf<5> paramName(KName);

 	const int qosParams = 128;

	//RCFParameterFamilyBundle& pfb = CreateParameterBundleL();
	//RParameterFamily family = pfb.CreateFamilyL(KSubConQoSFamily); //PJLEFT
	RCFParameterFamilyBundle newBundle;
	newBundle.CreateL();
	iParameterBundle.Open(newBundle);
	RParameterFamily family = newBundle.CreateFamilyL(KSubConQoSFamily);

	// Create the generic set
	CSubConQosGenericParamSet* isubConQosGenParSet = CSubConQosGenericParamSet::NewL(family, RParameterFamily::EGranted);

    isubConQosGenParSet->SetHeaderMode(0);
    isubConQosGenParSet->SetName(paramName);
    isubConQosGenParSet->SetDownlinkBandwidth(qosParams);
    isubConQosGenParSet->SetDownLinkMaximumBurstSize(qosParams);
    isubConQosGenParSet->SetDownLinkAveragePacketSize(qosParams);
    isubConQosGenParSet->SetDownLinkDelay(qosParams);
    isubConQosGenParSet->SetDownLinkDelayVariation(qosParams);
   	isubConQosGenParSet->SetDownLinkMaximumBurstSize(qosParams);
   	isubConQosGenParSet->SetDownLinkPriority(qosParams);
   	isubConQosGenParSet->SetDownLinkMaximumPacketSize(qosParams);

   	isubConQosGenParSet->SetUpLinkAveragePacketSize(qosParams);
   	isubConQosGenParSet->SetUpLinkDelay(qosParams);
   	isubConQosGenParSet->SetUplinkBandwidth(qosParams);
   	isubConQosGenParSet->SetUpLinkDelayVariation(qosParams);
   	isubConQosGenParSet->SetUpLinkMaximumBurstSize(qosParams);
   	isubConQosGenParSet->SetUpLinkMaximumPacketSize(qosParams);
   	isubConQosGenParSet->SetUpLinkPriority(qosParams);

 	incomingStatus = ETrue;
	}








