// 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:
// sblpapi.cpp - SBLP QoS API
//

#include "sblpextn.h"
#include "qosextn_constants.h"
#include "qosextn_log.h"
#include <networking/qosparameters.h>

// Buffer size
const TUint KSblpApiBufSize = 8192;
const TUint KNumberOfElementsPerFlowId = 2;
// Note that KAuthorizationTokenAdjustedStringLength value should be calculated 
// very carefully to fit the string inside the config block used by the pfqoslib.
// if KAuthorizationTokenActualStringLength = 255, KAuthorizationTokenAdjustedStringLength should
// be 260.
const TUint KAuthorizationTokenActualStringLength = 255;
const TUint KAuthorizationTokenStringZeroTerminated = KAuthorizationTokenActualStringLength + 1;
const TUint KAuthorizationTokenAdjustedStringLength = KAuthorizationTokenStringZeroTerminated + 4;


EXPORT_C CSblpParameters::CSblpParameters()
	{
	iAuthorizationToken = KNullDesC8;
	}

EXPORT_C CSblpParameters::~CSblpParameters()
	{
	iFlowIds.Reset();
	}

EXPORT_C CSblpParameters& CSblpParameters::operator= (const CSblpParameters& f)
	{
	if (this != &f)
		{
		SetMAT(f.iAuthorizationToken);
		SetFlowIds(f.iFlowIds);
		}
	return *this;
	}

EXPORT_C TInt CSblpParameters::GetMAT(TAuthorizationToken &aAuthToken) const
	{
	aAuthToken = iAuthorizationToken;
	return KErrNone;
	}

EXPORT_C void CSblpParameters::SetMAT(const TAuthorizationToken &aAuthToken )
	{
	iAuthorizationToken = aAuthToken;
	}

EXPORT_C CSblpParameters::TFlowIdentifier& CSblpParameters::GetFlowId(TInt aIndex)
	{
	__ASSERT_DEBUG(aIndex<iFlowIds.Count(),User::Panic(_L("Sblp"),KErrArgument));
	return iFlowIds[aIndex];
	}

EXPORT_C void CSblpParameters::SetFlowIds(const RArray<TFlowIdentifier> &aFlowIds)
	{
    //in case of low memory the function might not set all the ids
	iFlowIds.Reset();
	TInt i;
	for(i=0; i<aFlowIds.Count();i++)
		{
		TInt errorCode = this->iFlowIds.Append(aFlowIds[i]);
		if (errorCode != KErrNone) 
		    {
            LOG(Log::Printf(_L("CSblpParameters::SetFlowIds - Not Enough Memory!!!\n"));)
		    }
		}
	}

EXPORT_C TInt CSblpParameters::GetFlowIds(RArray<TFlowIdentifier>& aFlowIds)
	{
    //in case of low memory the function might not get all the ids and returns an error code
	aFlowIds.Reset();
	TInt i;
	TInt errorCode = KErrNone;
	for(i=0; i<iFlowIds.Count();i++)
		{
        errorCode = aFlowIds.Append(this->iFlowIds[i]);
        if (errorCode != KErrNone) 
            {
            LOG(Log::Printf(_L("CSblpParameters::GetFlowIds - Not Enough Memory!!!\n"));)
            return errorCode;
            }
		}
	return KErrNone;
	}

EXPORT_C TInt CSblpParameters::NrOfFlowIds()
	{
	return iFlowIds.Count();
	}

//
// CSblpPolicy
//
EXPORT_C CSblpPolicy* CSblpPolicy::NewL()
	{
	CSblpPolicy* policy = new (ELeave) CSblpPolicy();
	CleanupStack::PushL(policy);
	policy->ConstructL();
	CleanupStack::Pop();
	return policy;
	}

CSblpPolicy::CSblpPolicy()
	{
	iType = KPfqosExtensionSBLP;
	}

void CSblpPolicy::ConstructL()
	{
	iData = HBufC8::NewL(KSblpApiBufSize);
	iSblp = new (ELeave) CSblpParameters;
	}

EXPORT_C CSblpPolicy::~CSblpPolicy()
	{
	delete iSblp;
	//iData is deleted in the base
	}

static void SetIntValue(pfqos_configblock_int& data, TInt aValue,
						const TDesC8& aName)
	{
	data.len = sizeof(pfqos_configblock_int)/8;
	data.padding = data.reserved = 0;
	data.type = KPfqosTypeInteger;
	data.value = aValue;
	Mem::FillZ(data.id, KPfqosMaxName);
	Mem::Copy(data.id, aName.Ptr(), aName.Length());
	}



static void SetStringBlockHeader(pfqos_configblock& data,
								 TDesC8& /*aValue*/, const TDesC8& aName)
	{
	data.len = (sizeof(pfqos_configblock) + KAuthorizationTokenAdjustedStringLength )/8;
	data.padding = data.reserved = 0;
	data.type = KPfqosTypeString;
	Mem::FillZ(data.id, KPfqosMaxName);
	Mem::Copy(data.id, aName.Ptr(), aName.Length());
	}

EXPORT_C TDesC8& CSblpPolicy::Data()
	{
	TPtr8 bufPtr = iData->Des();
	bufPtr.SetLength(0);
	const TInt byte_len = (sizeof(pfqos_configure)+
						  sizeof(pfqos_extension)+
						  sizeof(pfqos_configblock)+
						  KAuthorizationTokenAdjustedStringLength+
			                          KNumberOfElementsPerFlowId * iSblp->NrOfFlowIds() *
						  sizeof(pfqos_configblock_int));

	pfqos_configure header;
	header.pfqos_configure_len = (TUint16)((byte_len + 7) / 8);
	header.pfqos_ext_type = EPfqosExtExtension;
	header.reserved = 0;
	header.protocol_id = 0;
	bufPtr.Append((TUint8*)&header, sizeof(pfqos_configure));

	pfqos_extension extensionType;
	extensionType.pfqos_ext_len = 0;
	extensionType.pfqos_ext_type = EPfqosExtExtension;
	extensionType.pfqos_extension_type = KPfqosExtensionSBLP;
	bufPtr.Append((TUint8*)&extensionType, sizeof(pfqos_extension));

	/* MAT
	
	MAT is a string
	The string is put after pfqos_configblock
	The pfqos_configblock length is the size of pfqos_configblock
	plus the string length
	*/
	TAuthorizationToken authToken; 
	pfqos_configblock stringBlock;
	iSblp->GetMAT(authToken);
	SetStringBlockHeader(stringBlock,authToken,KDescSblpMediaAuthorizationToken);
	bufPtr.Append((TUint8*)&stringBlock, sizeof(pfqos_configblock));
	// put the string now
	authToken.ZeroTerminate();
	bufPtr.Append((TUint8*)authToken.Ptr(),KAuthorizationTokenAdjustedStringLength);


	// Flowids
	pfqos_configblock_int ext;
	TInt i;
	for(i=0; i<iSblp->NrOfFlowIds();i++)
		{
		CSblpParameters::TFlowIdentifier& flowId = iSblp->GetFlowId(i);
		SetIntValue(ext,flowId.iMediaComponentNumber,KDescSblpMediaComponentNumber);
		bufPtr.Append((TUint8*)&ext, sizeof(pfqos_configblock_int));
		SetIntValue(ext,flowId.iIPFlowNumber,KDescSblpIPFlowNumber);
		bufPtr.Append((TUint8*)&ext, sizeof(pfqos_configblock_int));
		}

	bufPtr.AppendFill(0, header.pfqos_configure_len * 8 - byte_len);
	return *iData;
	}

EXPORT_C TInt CSblpPolicy::ParseMessage(const TDesC8& /*aData*/)
	{
	return KErrNone;
	}

EXPORT_C CExtensionBase* CSblpPolicy::CreateL()
	{
	CSblpPolicy *extension = CSblpPolicy::NewL();
	return extension;
	}

EXPORT_C TInt CSblpPolicy::Copy(const CExtensionBase& aExtension)
	{
	if (aExtension.Type() != iType)
		return KErrArgument;
	const CSblpPolicy& policy = (CSblpPolicy&)aExtension;
	policy.GetSblpParameters(*iSblp);
	return KErrNone;
	}

EXPORT_C void CSblpPolicy::SetSblpParameters(const CSblpParameters& aSblp)
	{
	
	*iSblp = aSblp;

	LOG(
	// following code is to create logs
	TAuthorizationToken authToken;
	iSblp->GetMAT (authToken);
	RArray<CSblpParameters::TFlowIdentifier> flowIds;
	iSblp->GetFlowIds(flowIds);
	// in case of low memory GetFlowIds might return an error and flowIds might not have all the ids, but we still try to log as much as we can
	TBuf<KAuthorizationTokenSize> label;
	label.Copy(authToken);
		
	Log::Printf(_L("<------------------------------------------------\n"));
	Log::Printf(_L("CSblpPolicy::SetSblpParameters"));
	Log::Printf(_L("\n"));
	Log::Printf(_L("SBLP VALUES SUPPLIED BY CLIENT IS \n"));
	Log::Printf(_L("\n"));
	Log::Printf(_L("[MAT string			 :	 = %S]\n"),&label);
	
	TInt i;
	for(i=0; i<flowIds.Count();i++)
		{
		Log::Printf(_L("Media component number  :	 = %d]\n"),flowIds[i].iMediaComponentNumber);
		Log::Printf(_L("IP flow number		  :	 = %d]\n"),flowIds[i].iIPFlowNumber);
		}
	Log::Printf(_L("------------------------------------------------>\n"));
	flowIds.Close();
	)
	
	}

EXPORT_C void CSblpPolicy::GetSblpParameters(CSblpParameters& aSblp) const
	{
	aSblp = *iSblp;
	}
