/*
* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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: 
* Implementation of utility functions for copying and streaming RArray/RpointerArray. 
*
*/


/**
 @file 
 @internalTechnology
 @prototype
*/

#ifndef STREAMINGARRAY_INL
#define STREAMINGARRAY_INL

#include <s32mem.h>
#include <scs/streamingarray.h>
#include <scs/nullstream.h>
#include <scs/streamingarray.h>

// Traits classes - internally required by RArray/RPointerArray functions

template <class T>
class TTraits
	{
public:
	static T* CopyL(const T& aRight) { return T::NewL(aRight);}
	static T* ReadFromStreamL(RReadStream& aStream) { return T::NewL(aStream); }
	static T* ReadFromStreamLC(RReadStream& aStream) { return T::NewLC(aStream); }
	static void WriteToStreamL(const T& aItem, RWriteStream& aStream) { aStream << aItem; }
	};

// Specialisation for HBufC
template <>
class TTraits<HBufC16>
	{
public:
	static HBufC16* CopyL(const HBufC16& aOther) { return aOther.AllocL();}
	static HBufC16* ReadFromStreamL(RReadStream& aStream) { return HBufC16::NewL(aStream, KMaxTInt); }
	static HBufC16* ReadFromStreamLC(RReadStream& aStream) { return HBufC16::NewLC(aStream, KMaxTInt); }
	static void WriteToStreamL(const HBufC16& aItem, RWriteStream& aStream) { aStream << aItem; }
	};
		
template <>
class TTraits<HBufC8>
	{
public:
	static HBufC8* CopyL(const HBufC8& aOther) { return aOther.AllocL();}
	static HBufC8* ReadFromStreamL(RReadStream& aStream) { return HBufC8::NewL(aStream, KMaxTInt); }
	static HBufC8* ReadFromStreamLC(RReadStream& aStream) { return HBufC8::NewLC(aStream, KMaxTInt); }
	static void WriteToStreamL(const HBufC8& aItem, RWriteStream& aStream) { aStream << aItem; }
	};

// Size calculator - internally required by RPointerArray functions

template <typename T>
TInt GetObjectBufferSizeL(const T& aObject)
	{
	TInt size(0);
	RNullWriteStream nullstream;
	CleanupClosePushL(nullstream);
	nullstream << aObject;
	nullstream.CommitL();
	size = nullstream.BytesWritten();
	CleanupStack::PopAndDestroy(&nullstream);
	return size;
	}

template <class T>
TInt ExternalizedBufferSizeL(const RPointerArray<T>& aArray)
/**
	Calculates how much buffer is required for a pointers array to be externalized.
	@param aArray The pointer array whose buffer size will be calculated.
	@return Returns the number of bytes occupied by the elements of the pointer array.
 */
	{
	TInt totalSize(1);	// 1-byte is reserved for the array count
	TInt count = aArray.Count();
	
	for (TInt i = 0; i < count; ++i)
			{
			totalSize += GetObjectBufferSizeL(*aArray[i]);
			}
	return totalSize;
	}


// RPointerArray utilities

template <class T>
void CopyPointerArrayL(RPointerArray<T>& aTarget, const RPointerArray<T>& aSource)
	{
	TInt arrayCount =  aSource.Count();
	for (TInt i = 0; i < arrayCount; ++i)
		{
		T* item = TTraits<T>::CopyL(*aSource[i]);
		CleanupStack::PushL(item);
		User::LeaveIfError(aTarget.Append(item));
		CleanupStack::Pop(item);
		}
	}
	
template <class T>
HBufC8* ExternalizePointersArrayLC(const RPointerArray<T>& aArray, TBool aAddLength)
	{
	TInt arraySize = ExternalizedBufferSizeL(aArray);
	HBufC8 *arrayBuf = HBufC8::NewLC(arraySize + sizeof(TInt32));
	TPtr8 arrayPtr(arrayBuf->Des());
	
	RDesWriteStream stream(arrayPtr);
	stream.PushL();
	ExternalizePointersArrayL(aArray, stream, aAddLength);
	stream.Pop();
	stream.Release();
	return arrayBuf;
	}

template <class T>
void ExternalizePointersArrayL(const RPointerArray<T>& aArray, RWriteStream& aStream, TBool aAddLength)
	{
	TInt arrayCount = aArray.Count();
	if(aAddLength)
		aStream << TCardinality(arrayCount);
	for (TInt i = 0; i < arrayCount; ++i)
		{
		TTraits<T>::WriteToStreamL(*aArray[i], aStream);
		}
	aStream.CommitL();
	}

template <class T>
void InternalizePointersArrayL(RPointerArray<T>& aArray, RReadStream& aStream, TBool aAddLength)
	{
	TInt count (0);
	if(aAddLength)
		{
		TCardinality c;
		aStream >> c;
		count = c;
		}
	for (TInt i = 0; i < count; ++i)
		{
		T* item = TTraits<T>::ReadFromStreamL(aStream);
		CleanupStack::PushL(item);
		User::LeaveIfError(aArray.Append(item));
		CleanupStack::Pop(item);
		}
	}


// Size calculator - internally required by RArray/RPointerArray functions

template <class T>
TInt ExternalizedBufferSizeL(const RArray<T>& aArray)
/**
	Calculates how much buffer is required for a fixed length array to be externalized.
	@param aArray The array whose buffer size will be calculated.
	@return Returns the number of bytes of the array's dynamic memory.
 */
	{
	TInt totalSize(1); // 1-byte is reserved for the array count
	TInt count = aArray.Count();

	for (TInt i = 0; i < count; ++i)
			{
			totalSize += GetObjectBufferSizeL(TPckgC<T>(aArray[i]));
			}
	return totalSize;
	}


// RArray utilities

template <class T>
void CopyFixedLengthArrayL(RArray<T>& aTarget, const RArray<T>& aSource)
	{
	TInt arrayCount = aSource.Count();
	for (TInt i = 0; i < arrayCount; ++i)
		{
		User::LeaveIfError(aTarget.Append(aSource[i]));
		}
	}

template <class T>
HBufC8* ExternalizeFixedLengthArrayL(const RArray<T>& aArray)
	{
	TInt arraySize = ExternalizedBufferSizeL(aArray, arraySize);
	HBufC8 *arrayBuf = HBufC8::NewLC(arraySize + sizeof(TInt32));
	TPtr8 arrayPtr(arrayBuf->Des());
	
	RDesWriteStream stream(arrayPtr);
	stream.PushL();
	ExternalizeFixedLengthArrayL(aArray, stream);
	stream.Pop();
	stream.Release();
	return arrayBuf;
	}

template <class T>
void ExternalizeFixedLengthArrayL(const RArray<T>& aArray, RWriteStream& aStream)
	{
	TInt arrayCount = aArray.Count();
	aStream << TCardinality(arrayCount);
	for (TInt i = 0; i < arrayCount; ++i)
		{
		aStream.WriteL(TPckgC<T>(aArray[i]));
		}
	aStream.CommitL();
	}


template <class T>
void InternalizeFixedLengthArrayL(RArray<T>& aArray, RReadStream& aStream)
	{
	TCardinality c;
	aStream >> c;
	TInt count = c;
	for (TInt i = 0; i < count; ++i)
		{
		T item;
		TPckg<T> itemPckg(item);
		aStream.ReadL(itemPckg);
		User::LeaveIfError(aArray.Append(item));
		}
	}

#endif /* STREAMINGARRAY_INL*/
