// 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:
// IPProto MCPR
// 
//

/**
 @file
 @internalComponent
*/


#include <comms-infras/ss_log.h>
//#include <ss_nodestates.h>
#include <comms-infras/corecprstates.h>
#include <comms-infras/coremcprstates.h>
#include <comms-infras/coremcpractivities.h>
#include <commsdattypesv1_1.h> // CommsDat
#include <comms-infras/ss_tiermanager.h> //TierManagerUtils
#include <comms-infras/ss_tiermanagerutils.h>
#include <comms-infras/netcfgextprov.h>
#include "IPProtoMCpr.h"
#include "idletimer.h"


#if defined __CFLOG_ACTIVE || defined SYMBIAN_TRACE_ENABLE
#define KIPProtoMCprTag KESockMetaConnectionTag
_LIT8(KIPProtoMCprSubTag, "ipprotomcpr");
#endif

#include <comms-infras/ss_msgintercept.h>

using namespace Messages;
using namespace MeshMachine;
using namespace ESock;
using namespace NetStateMachine;
using namespace CommsDat;
using namespace MCprActivities;

//
//CIPProtoMetaConnectionProvider
CIPProtoMetaConnectionProvider* CIPProtoMetaConnectionProvider::NewL(CMetaConnectionProviderFactoryBase& aFactory,
                                                                     const TProviderInfo& aProviderInfo)
	{
	CIPProtoMetaConnectionProvider* self = new (ELeave) CIPProtoMetaConnectionProvider(aFactory,aProviderInfo,IPProtoMCprActivities::ipProtoActivitiesMCpr::Self());
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CIPProtoMetaConnectionProvider::CIPProtoMetaConnectionProvider(CMetaConnectionProviderFactoryBase& aFactory,
                                                               const TProviderInfo& aProviderInfo,
                                                               const MeshMachine::TNodeActivityMap& aActivityMap)
	:	CCoreMetaConnectionProvider(aFactory,aProviderInfo,aActivityMap), iIapLocked(EFalse)
	{
	LOG_NODE_CREATE(KIPProtoMCprTag, CIPProtoMetaConnectionProvider);
	}

CIPProtoMetaConnectionProvider::~CIPProtoMetaConnectionProvider()
	{
	LOG_NODE_DESTROY(KIPProtoMCprTag, CIPProtoMetaConnectionProvider);
	}


void CIPProtoMetaConnectionProvider::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
    {
	__CFLOG_VAR((KIPProtoMCprTag, KIPProtoMCprSubTag, _L8("CIPProtoMetaConnectionProvider %08x:\tReceived() aCFMessage=%d"),
	   this, aMessage.MessageId().MessageId()));

	ESOCK_DEBUG_MESSAGE_INTERCEPT(aSender, aMessage, aRecipient);

	TNodeContext<CIPProtoMetaConnectionProvider> ctx(*this, aMessage, aSender, aRecipient);
    CCoreMetaConnectionProvider::Received(ctx);

    User::LeaveIfError(ctx.iReturn);
	}

void CIPProtoMetaConnectionProvider::ConstructL()
    {
    CMetaConnectionProviderBase::ConstructL(); //This initialises the AccessPointInfo

  	//For construction of IpProto providers (construction only) we use the instance field of TProviderInfo
   	//to carry the IAP id. The IAP id is necessary for the initialisation if IpProto specific data.
    TInt iap = (TInt)ProviderInfo().Instance();
	SetProviderInfo(TProviderInfo(ProviderInfo().TierId(),iap));
    SetConfigL();
    }

void CIPProtoMetaConnectionProvider::SetConfigL()
/**
Setup the provisioning information for the IPProto layer.
*/
    {
    RMetaExtensionContainer mec;
    mec.Open(AccessPointConfig());
    CleanupClosePushL(mec);

    //At this moment our ProviderInfo().APId() points to the IAP this provider represents
    TUint configurationIap = ProviderInfo().APId();
    CCommsDatIapView* iapView = CCommsDatIapView::NewLC(configurationIap);

    // Read Idle timer values
    TIdleTimerValues* timerValues = new (ELeave) TIdleTimerValues;
    CleanupStack::PushL(timerValues);
    iapView->GetTimeoutValuesL(timerValues->iShortTimer, timerValues->iMediumTimer, timerValues->iLongTimer);
    mec.AppendExtensionL(timerValues); //iAccessPointConfig owns timerValues from now on
    CleanupStack::Pop(timerValues);

    // Read NetworkId
    TUint32 net = 0;
    iapView->GetIntL(KCDTIdIAPNetwork, net);

	// Read Protocol list (from IfNetworks field).  This contains a comma seperated list of
	// protocol names and determines the binders instantiated in the lower CFProtocol (typically
	// "ip" or "ip,ip6").

	HBufC* protocolList = NULL;

	if (iapView->GetServiceTableType() == KCDTIdVPNServiceRecord)
		{
		// *** HACK ***
		// Normally, the IfNetworks field is read via the Agent ReadDes() methods.  This
		// allow, for example, the VPNConnAgt to fake up the IfNetworks field to "ip" when,
		// in fact, it does not exist in the CommsDat.  We should somehow be arranging for the
		// provisioning of this field to be from the underlying Agent, but the Agent is
		// only accessible from the Agent Adapter in the AgentSCPr layer.  Perhaps the
		// IPProtoSCPr can do the provisioning of the IfNetworks field, but it would need
		// to get the contents of the field from the AgentSCPr below it.
		_LIT(KVPNIfNetworks, "ip");
		protocolList = HBufC::NewMaxL(4);
		*protocolList = KVPNIfNetworks();
		}
	else
		{
		iapView->GetTableCommonTextFieldL(CCommsDatIapView::EIfNetworks, protocolList);
		}


	HBufC* configdaemonmanager = NULL;
	TRAPD(err, iapView->GetTableCommonTextFieldL(ESock::CCommsDatIapView::EConfigDaemonManagerName,
												  configdaemonmanager));
	if ((err == KErrNone) && (*configdaemonmanager != KNullDesC))
		{
		CleanupStack::PushL(configdaemonmanager);
		CNetCfgExtProvision* netcfg = CNetCfgExtProvision::NewL();
		CleanupStack::PushL(netcfg);
		netcfg->InitialiseConfigL(iapView);
		mec.AppendExtensionL(netcfg);
		CleanupStack::Pop(netcfg);
		CleanupStack::PopAndDestroy(configdaemonmanager);
		}

	CleanupStack::PopAndDestroy(iapView);
	CleanupStack::PushL(protocolList);

    TItfInfoConfigExt* itfInfoConfig = new (ELeave) TItfInfoConfigExt(TConnectionInfo(configurationIap,net));
    CleanupStack::PushL(itfInfoConfig);

	if (itfInfoConfig->iProtocolList.MaxSize() >= protocolList->Size())
		{
		itfInfoConfig->iProtocolList.Copy(*protocolList);
		}
	else
		{
		User::Leave(KErrOverflow);
		}

    mec.AppendExtensionL(itfInfoConfig);
    CleanupStack::Pop(itfInfoConfig);
    CleanupStack::PopAndDestroy(protocolList);

    XInterfaceNames* itfNames = XInterfaceNames::NewL();
    CleanupStack::PushL(itfNames);
    mec.AppendExtensionL(itfNames);
    CleanupStack::Pop(itfNames);

    iAccessPointConfig.Close();
	iAccessPointConfig.Open(mec);
	CleanupStack::PopAndDestroy(&mec);
    }

namespace IPProtoMCprSelectConnPrefListActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivitySelect, IPProtoMCprSelectConnPrefList, TCFSelector::TSelect, CSelectNextLayerActivity::NewL)
	//Reply from TAwaitingSelectNextLayer if no choices, otherwise accept
	FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingSelectNextLayerSuper, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TProcessSimpleSelectionPolicySuper, MCprStates::TSelectedProvider)
	//Start the selection main loop
	NODEACTIVITY_ENTRY(MCprStates::KSelectedProvider, CSelectNextLayerActivity::TFindOrCreateTierManagerSuper, MCprStates::TAwaitingTierManagerCreated, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TJoinTierManager, CoreStates::TAwaitingJoinComplete, MeshMachine::TNoTag)
	//Select next provider and enter the selection internal loop if provider received. Break if SelectComplete(NULL).
	NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TSelectNextLayerSuper, MCprStates::TAwaitingSelectComplete, CSelectNextLayerActivity::TNoTagOrSelectedProviderIsNull)
    NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TAddProviderInfo, MCprStates::TAwaitingSelectComplete, CSelectNextLayerActivity::TNoTagBackwardsOrJoinServiceProvider)
    //Break the selection internal loop if SelectComplete(NULL), otherwise stay in this tripple
    NODEACTIVITY_ENTRY(MCprStates::KJoinServiceProvider, CSelectNextLayerActivity::TJoinServiceProvider, CoreStates::TAwaitingJoinComplete, MeshMachine::TNoTag)
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TSendSelectComplete, CSelectNextLayerActivity::TSelectedProviderIsNullOrJoinServiceProviderBackward)
	//Break the selection main loop if no more choices, otherwise go back again
	THROUGH_NODEACTIVITY_ENTRY(MCprStates::KSelectedProviderIsNull, CSelectNextLayerActivity::TLeaveTierManager, CSelectNextLayerActivity::TNoTagOrSelectedProviderBackwardSuper)
	//Finish the activity
	LAST_NODEACTIVITY_ENTRY(KNoTag, MCprStates::TSendFinalSelectComplete)
NODEACTIVITY_END()
}

namespace IPProtoMCprActivities
{
DEFINE_ACTIVITY_MAP(ipProtoActivitiesMCpr)
	ACTIVITY_MAP_ENTRY(IPProtoMCprSelectConnPrefListActivity, IPProtoMCprSelectConnPrefList)
ACTIVITY_MAP_END_BASE(MCprActivities, coreMCprActivities)
}
