/*
* Copyright (c) 2007 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:  Utility class to hold data for predictive search.
*                Used to marshal data between the client, server and data
*                plugins.
*
*/


// INCLUDE FILES
#include <s32mem.h>
#include <collate.h>

#include "CPsData.h"
#include "CPcsDefs.h"

// ============================== MEMBER FUNCTIONS ============================


// ----------------------------------------------------------------------------
// CPsData::NewL
// Two Phase constructor
// ----------------------------------------------------------------------------
EXPORT_C CPsData* CPsData::NewL()
{
	CPsData* self = new (ELeave) CPsData();	
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
	
}

// ----------------------------------------------------------------------------
// CPsData::CPsData
// Default constructor
// ----------------------------------------------------------------------------
CPsData::CPsData()
{
}

// ----------------------------------------------------------------------------
// CPsData::ConstructL
// Two phase construction
// ----------------------------------------------------------------------------
void CPsData::ConstructL()
{
    iData = new (ELeave) RPointerArray<HBufC>(1);
    iGc = new (ELeave) RPointerArray<HBufC>(1);
    iDataExtension = NULL;
}

// ----------------------------------------------------------------------------
// CPsData::~CPsData
// Destructor
// ----------------------------------------------------------------------------
EXPORT_C CPsData::~CPsData()
{
	if ( iData )
	{
		iData->ResetAndDestroy();
		delete iData;
	}
	if(iDataExtension)
    {
		delete iDataExtension;
		iDataExtension = NULL;
    }
    if(iIntDataExt && iIntDataExt->Count())
    {
    	
    	iIntDataExt->Close();
    	delete iIntDataExt;
    }
    if ( iGc )
    {
    	iGc->ResetAndDestroy();
    	delete iGc;
    }
}

// ----------------------------------------------------------------------------
// CPsData::Id
// Returns the unique id
// ----------------------------------------------------------------------------
EXPORT_C  TInt CPsData::Id() const
{
    return iId;
}

// ----------------------------------------------------------------------------
// CPsData::SetId
// Sets the unique id
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::SetId (const TInt aId)
{
	iId = aId;
}

// ----------------------------------------------------------------------------
// CPsData::UriId
// Returns the unique URI id
// ----------------------------------------------------------------------------
EXPORT_C  TUint8 CPsData::UriId() const
{
    return iUriId;
}

// ----------------------------------------------------------------------------
// CPsData::SetUriId
// Sets the unique URI id
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::SetUriId(const TUint8 aUriId)
{
	iUriId = aUriId;
}

// ----------------------------------------------------------------------------
// CPsData::Data1
// Returns the data1
// ----------------------------------------------------------------------------
EXPORT_C HBufC* CPsData::Data(TInt aIndex) const
{
    if ( aIndex >= iData->Count() )    
         return NULL;
    
    return (*iData)[aIndex];
}

// ----------------------------------------------------------------------------
// CPsData::SetData1L
// Sets the data1
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::SetDataL(TInt aIndex, const TDesC& aData)
{   
    // Every call to insert makes the array to grow.
    // This check is required to optimize memory.
    if ( aIndex < iData->Count() )
    {
       //delete (*iData)[aIndex];     // Commented as it is delaying the contact caching as well as search time     
       iGc->Append((*iData)[aIndex]); // Instead append to garbage collector for cleanup later
       (*iData)[aIndex] = aData.AllocL();
    }
    else 
    {  
       iData->InsertL( aData.AllocL(), aIndex);
    }
}

// ----------------------------------------------------------------------------
// CPsData::ExternalizeL
// Writes 'this' to aStream
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::ExternalizeL(RWriteStream& aStream) const
{
    aStream.WriteInt16L(iId); // Write unique ID to the stream
    
    aStream.WriteUint8L(iUriId); // Write URI ID to the stream
 
    aStream.WriteUint8L(iDataMatches); // Write data matches attribute 
    
    aStream.WriteUint8L(iData->Count()); // Number of data elements

	for ( int index = 0; index < iData->Count(); index++ )
	{
	    HBufC* data = (*iData)[index];
	    if ( data ) // Write data to the stream (or a NULL descriptor)
	    {
	    	aStream.WriteInt16L( data->Size() ); // data size
			aStream << *data; // data
	    }
	    else
	    {
	    	aStream.WriteInt16L( 0 );
	    	aStream << KNullDesC;
	    }	    	    	
	}
	
	if ( iDataExtension )
    {
        HBufC8* dataExt = (HBufC8*)iDataExtension;
    	aStream.WriteUint8L( dataExt->Size() );
    	aStream << *dataExt;
    }
    else 
    {
    	aStream.WriteUint8L( 0 );
    	aStream << KNullDesC8;	    	
    }
    
    TInt intDataExtCount = 0;
    if (iIntDataExt)
    {
        intDataExtCount = iIntDataExt->Count();
    }
    if(intDataExtCount)
    {
    	aStream.WriteInt32L(intDataExtCount);
    	for(TInt i =0 ; i < intDataExtCount;  i++ )
	  	    aStream.WriteInt32L((*iIntDataExt)[i]);
    }
    else
    {
    	aStream.WriteInt32L(0);
    	
    }
}

// ----------------------------------------------------------------------------
// CPsData::InternalizeL
// Initializes 'this' with the contents of aStream
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::InternalizeL(RReadStream& aStream)
{
    // Read unique id
    TInt tmp = aStream.ReadInt16L();
    iId = tmp;
    
    // Read the URI Id
    iUriId = aStream.ReadUint8L();    
    
    // Read data matches
    iDataMatches = aStream.ReadUint8L();

    // Read number of data elements
    TInt szNumElements = aStream.ReadUint8L();
    
    for ( int index = 0; index < szNumElements; index++ )
    {
        // Read data size
	    TInt szData = aStream.ReadInt16L();
    	    
    	HBufC* data =  HBufC::NewL(aStream, szData);
	    iData->InsertL(data, index);	 
    }
	
	// Read data extension size
	TUint8 szDataExt = aStream.ReadUint8L();
    if(iDataExtension)
    {
        delete iDataExtension;
        iDataExtension = NULL;
    }
    
    HBufC8* dataExt =  HBufC8::NewL(aStream, szDataExt);
    iDataExtension = dataExt;
    
    TInt intDataExtCount = aStream.ReadInt32L();
    if(intDataExtCount)
    {
        if(!iIntDataExt)
		{
		 iIntDataExt = new (ELeave) RArray<TInt> (1);	
		}
	 
    	for(TInt i =0 ; i < intDataExtCount;  i++ )
    	{
    	    TInt tempDataExt = aStream.ReadInt32L();
    	    iIntDataExt->Append(tempDataExt);
    	}
    }
    else
    {
    	// Do Nothing since there are no elements
    }
}

// ----------------------------------------------------------------------------
// CPsData::CompareByData
// Compare function
// ----------------------------------------------------------------------------
EXPORT_C TInt CPsData::CompareByData( const CPsData& aObject1, 
                                      const CPsData& aObject2 )
{
	// Get the standard method
    TCollationMethod meth = *Mem::CollationMethodByIndex( 0 );
    meth.iFlags |= TCollationMethod::EIgnoreNone;
    meth.iFlags |= TCollationMethod::EFoldCase;

    HBufC* str1;
    HBufC* str2 ;

    TInt compareRes(0);
    for ( int cnt1 = 0, cnt2 = 0;
          (cnt1 < aObject1.DataElementCount()) && (cnt2 < aObject2.DataElementCount());
          cnt1++, cnt2++ )
        {
        if ( aObject1.Data(cnt1) )
            {
            //data1 += aObject1.Data(i)->Des();
            str1 =  aObject1.Data(cnt1)->Des().AllocL();    
            str1->Des().TrimAll();
            }	
        else
            {
            str1 = HBufC::NewL(2);
            str1->Des().Copy(KNullDesC);
            }
        CleanupStack::PushL( str1 );
        if ( aObject2.Data(cnt2) )
            {
            str2 = aObject2.Data(cnt2)->Des().AllocL();
            str2->Des().TrimAll();
            }	     
        else
            {
            str2 = HBufC::NewL(2);
            str2->Des().Copy(KNullDesC);
            }
        CleanupStack::PushL( str2 );
        compareRes = str1->Des().CompareC( str2->Des(), 3, &meth );
        CleanupStack::PopAndDestroy(str2);
        CleanupStack::PopAndDestroy(str1);
        if( !compareRes )
            {
            break;
            }
        }
    return compareRes;
}

// ----------------------------------------------------------------------------
// CPsData::CompareById
// Compare function
// ----------------------------------------------------------------------------
EXPORT_C TBool CPsData::CompareById(const CPsData& aObject1, const CPsData& aObject2)
{
    // Both Id() and UriId() must match if data objects represent the same contact.    
    // Values of Id() are guaranteed to be unique only within one store. 
    if ( aObject1.Id() == aObject2.Id() && aObject1.UriId() == aObject2.UriId() )  
        {      
            return ETrue;       
        }        
    return EFalse;
}


// ----------------------------------------------------------------------------
// CPsData::IsDataMatch
// Return TRUE if data is matched for predictive search
// ----------------------------------------------------------------------------		
EXPORT_C TBool CPsData::IsDataMatch(TInt aIndex)
{
    __ASSERT_DEBUG( aIndex < 8, User::Panic( _L("CPsData"), KErrOverflow ) );
    TUint8 val = 1 << aIndex;
    return (iDataMatches & val);
}

// ----------------------------------------------------------------------------
// CPsData:DataMatch
// Return the data match attribute
// ----------------------------------------------------------------------------		
EXPORT_C TUint8 CPsData::DataMatch()
{
    return iDataMatches;
}

// ----------------------------------------------------------------------------
// CPsData::SetData1Match
// 
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::SetDataMatch(TInt aIndex)
{
    __ASSERT_DEBUG( aIndex < 8, User::Panic( _L("CPsData"), KErrOverflow ) );
    TUint8 val = 1 << aIndex;
    iDataMatches |= val;
}

// ----------------------------------------------------------------------------
// CPsData::ClearDataMatches
// 
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::ClearDataMatches()
{
	iDataMatches = 0x0;
}

// ----------------------------------------------------------------------------
// CPsData::DataElementCount
// 
// ----------------------------------------------------------------------------
EXPORT_C TInt CPsData::DataElementCount() const
{
	return (iData->Count());
}


// ----------------------------------------------------------------------------
// CPsData::DataExtension
// 
// ----------------------------------------------------------------------------
EXPORT_C TAny* CPsData::DataExtension() const
{
	return iDataExtension;
}

// ----------------------------------------------------------------------------
// CPsData::SetDataExtension
// 
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::SetDataExtension(TAny* aDataExt)
{
	iDataExtension = aDataExt;
}

// ----------------------------------------------------------------------------
// CPsData::AddIntDataExtL
// 
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::AddIntDataExtL(TInt aDataExt)
{	if(!iIntDataExt)
	{
		 iIntDataExt = new (ELeave) RArray<TInt> (1);	
	}
	
	iIntDataExt->Append(aDataExt);
}

// ----------------------------------------------------------------------------
// CPsData::RemoveIntDataExt
// 
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::RemoveIntDataExt(TInt aIndex)
{
	if(iIntDataExt && (iIntDataExt->Count() > aIndex))
	{
		iIntDataExt->Remove(aIndex);
	}
}

// ----------------------------------------------------------------------------
// CPsData::IntDataExt
// 
// ----------------------------------------------------------------------------
EXPORT_C void CPsData::IntDataExt(RArray<TInt>& aDataExtArray)
{   
	aDataExtArray.Reset();
	if(iIntDataExt)
	{
		for(TInt i =0 ; i < iIntDataExt->Count(); i++ )
		  	aDataExtArray.Insert((*iIntDataExt)[i],0);
	}
}
