/**
Change the sorting order/text definition. It should be always called when 
there is not an iteration started in persistence layer.

@param aTextDef the new text definition to be used in the view session.
*/
void CCntPplViewSession::ChangeSortOrderL(const CContactTextDef& aTextDef)
	{
	//Cleanup the cached Prepare statement as the sort order will be changed
	Cancel();
    CleanupCachedPrepareStatement();
	
	//Copy the text definition
	CContactTextDef* textDef = CContactTextDef::NewLC();
	const TInt KTextDefCount = aTextDef.Count();
	for (TInt index = 0; index < KTextDefCount; ++index)
		{
		textDef->AppendL(TContactTextDefItem(aTextDef.At(index).iFieldType));
		}
	
	// Create select statement on contact table
	TCntSqlStatementType statementType(ESelect, KSqlContactTableName());
	CCntSqlStatement* sqlSmt = TSqlProvider::GetSqlStatementL(statementType);
	CleanupStack::PushL(sqlSmt);
	
	// Always select id, type flags.	
	sqlSmt->SetParamL(KContactId(), KSpace());
	sqlSmt->SetParamL(KContactTypeFlags(), KSpace());
	
	//Go through text definition to construct select statement.
	TBool isFastAccessOnly = ETrue;
	for(TInt ii = 0; ii < KTextDefCount; ++ii)
		{
		const TDesC& KColunmName = TCntPersistenceUtility::GetFastAccessColumnNameById(aTextDef.At(ii).iFieldType.iUid);
		if(KColunmName.Length() > 0) 
			{
			sqlSmt->SetParamL(KColunmName, KSpace());
			}
		else
			{
			isFastAccessOnly = EFalse;		
			}
		}
	
	if(!isFastAccessOnly)
		{
		//Fields in text blob are needed, add text fields header and
        //text blob columns in the select statement.		
		sqlSmt->SetParamL(KContactTextFieldHeader(), KSpace());
		sqlSmt->SetParamL(KContactTextFields(), KSpace());
		}

	CleanupStack::Pop(2, textDef); // sqlSmt, textDef.
	
	delete iCntSqlStatement;
	iCntSqlStatement = sqlSmt;
	
	delete iTextDef;
	iTextDef = textDef;
	
	iIsFastAccessFieldsOnly = isFastAccessOnly;
	}
/**
Initialise requested view contact object based on given parameters:
 1. search the contact in contact table.
 2. fill in contact type and hint to the view contact object.

@param aSqlStmt      reference to a RSqlStatement to be read in data 
@return initialized CViewContact object or NULL if reached end of rows.
*/
CViewContact* CCntPplViewSession::InitialiseViewItemL(RSqlStatement& aSqlStmt, const CCntSqlStatement& aCntSqlStmt, const TContactViewPreferences& aViewPrefs)
	{
	CViewContact* viewContact = NULL;
	
    while(viewContact == NULL)
	    {
    	TInt err = aSqlStmt.Next();
    	 
    	if(err == KSqlAtEnd)
    	    {
    	    return NULL;
    	    }
    	    
       	User::LeaveIfError(err);
       	
    	TInt typeFlags = aSqlStmt.ColumnInt(aCntSqlStmt.ParameterIndex(KContactTypeFlags()));
    	TUid contactTypeUid = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
    	
        if(!ContactCorrectType(contactTypeUid, aViewPrefs))
            {
            //The contact type doesn't match the view prefreference
            continue;
            }
    	
    	viewContact = CViewContact::NewLC(KNullContactId);
    	
    	/* Got a row and add common fields for both Groups and Contact view items. */
    	viewContact->SetId(aSqlStmt.ColumnInt(aCntSqlStmt.ParameterIndex(KContactId())));
    	viewContact->SetContactHint(TCntPersistenceUtility::TypeFlagsToHint(typeFlags));
    	viewContact->SetContactTypeUid(contactTypeUid);
    	
    	
    	if(contactTypeUid == KUidContactGroup)
    		{
    		// Groups don't require all the field types to be set.
    		viewContact->SetContactType(CViewContact::EGroup);
    		}
    	else
    		{
    		// All other contact types do require field types to be set.
    		viewContact->SetContactType(CViewContact::EContactItem);
    		}

    	CleanupStack::Pop(viewContact);		
	    }
   	
	return viewContact;    
	}	
/**
Utility method used to read binary blob fields from contacts database. Provides a mechanism to
fill a contact item with informations stored in binary blobs within contact database.
A reference to the contact item to be fill has to be provided. A template has to be provided
if the contact item is based on a template. Template can be NULL. Also a view definition can
be provided to filter which fields are read from blob fields.

@param		aItem Contact item to be filled with information from binary blob field.
@param		aView View definition specifying what item fields should be read from binary blob field
@param		aTemplate Contact item representing a template based on which aItem should be read. Can be NULL
@param		aDatabase RSqlDatabase reference.
@leave		KErrNotFound if the specified contact item does not exist any more in contact database
*/	
void TCntPersistenceUtility::ReadBinaryBlobL(CContactItem& aItem, const CContactItemViewDef& aView, const CContactItem* aTemplate, RSqlDatabase& aDatabase)
	{
	HBufC* selectString = HBufC::NewLC(KSelectTwoFields().Length() + KContactBinaryFieldHeader().Length() + KContactBinaryFields().Length() + KSqlContactTableName().Length() + KContactId().Length());
	TPtr ptrSelectString = selectString->Des();
	ptrSelectString.Format(KSelectTwoFields, &KContactBinaryFieldHeader, &KContactBinaryFields, &KSqlContactTableName, &KContactId, aItem.Id());
	
	RSqlStatement selectStmt;
	CleanupClosePushL(selectStmt);
	User::LeaveIfError(selectStmt.Prepare(aDatabase, ptrSelectString));

	TInt err = selectStmt.Next();
	if(err != KSqlAtRow)
		{
		if(err == KSqlAtEnd)
			{
			User::Leave(KErrNotFound);	
			}
		else
			{
			User::Leave(err);	
			}	
		}
	
	TPtrC8 binaryHeader;
	selectStmt.ColumnBinary(User::LeaveIfError(selectStmt.ColumnIndex(KContactBinaryFieldHeader)), binaryHeader);
	RDesReadStream binaryHeaderStream(binaryHeader);
	CleanupClosePushL(binaryHeaderStream);
	CEmbeddedStore* binaryHeaderStore = CEmbeddedStore::FromLC(binaryHeaderStream);
	
	TPtrC8 binaryFields;
	selectStmt.ColumnBinary(User::LeaveIfError(selectStmt.ColumnIndex(KContactBinaryFields)), binaryFields);
	RDesReadStream binaryFieldsStream(binaryFields);
	CleanupClosePushL(binaryFieldsStream);
	CEmbeddedStore* binaryBlobStore = CEmbeddedStore::FromLC(binaryFieldsStream);

	ReadBinaryBlobL(*binaryHeaderStore, *binaryBlobStore, aItem, aView, aTemplate);	

	CleanupStack::PopAndDestroy(6, selectString); //binaryHeaderStore, binaryHeaderStrean, binaryBlobStore, binaryBlobStream, selectStmt, selectString
	}
void CPredictiveSearchSynchronizer::CreatePredSearchTablesL(TBool aAllTables)
	{
	PRINT1(_L("CPredictiveSearchSynchronizer::CreatePredSearchTablesL all=%d"), aAllTables);

	if (aAllTables)
		{
		i12keyTable.CreateTableL();
		iSettingsTable.CreateTableL();
		iSettingsTable.StoreCurrentLanguageL();
		}
	iQwertyTable.CreateTableL();

	_LIT(KSelectAllContactsFormat, "SELECT %S,%S,%S FROM %S;");
	TInt bufSize = KSelectAllContactsFormat().Length() +
				   KContactId().Length() +
				   KContactFirstName().Length() +
				   KContactLastName().Length() +
				   KSqlContactTableName().Length();
	HBufC* sqlStatement = HBufC::NewLC(bufSize);
	sqlStatement->Des().AppendFormat(KSelectAllContactsFormat,
		&KContactId,
		&KContactFirstName,
		&KContactLastName,
		&KSqlContactTableName);

	RSqlStatement stmnt;
	CleanupClosePushL(stmnt);
	PRINT1(_L("CreatePredSearchTablesL prepare SQL statement:%S"), sqlStatement);
    stmnt.PrepareL(iDatabase, *sqlStatement);

	const TInt KContactIdIndex = 0;
	const TInt KFirstNameIndex = 1;
	const TInt KLastNameIndex = 2;
	TInt err(KErrNone);
    while ((err = stmnt.Next()) == KSqlAtRow)
        {
		PRINT(_L("CreatePredSearchTablesL create CContactItem"));

		TInt id = KUidContactCardValue;
		TUid uid;
		uid.iUid = id;
		CContactItem* contact = CContactItem::NewLC(uid);
		contact->SetId(stmnt.ColumnInt(KContactIdIndex));

		// If first name exists, write it to contact item
		TPtrC firstName;
		if (stmnt.ColumnText(KFirstNameIndex, firstName) == KErrNone)
			{
			CContactItemField* field =
				CContactItemField::NewLC(KStorageTypeText, KUidContactFieldGivenName);
			CContactTextField* textfield = field->TextStorage();
			textfield->SetTextL(firstName);
			contact->AddFieldL(*field); // Takes ownership
			CleanupStack::Pop(field);
			}

		TPtrC lastName;
		if (stmnt.ColumnText(KLastNameIndex, lastName) == KErrNone)
			{
			CContactItemField* field =
				CContactItemField::NewLC(KStorageTypeText, KUidContactFieldFamilyName);
			CContactTextField* textfield = field->TextStorage();
			textfield->SetTextL(lastName);
			contact->AddFieldL(*field); // Takes ownership
			CleanupStack::Pop(field);
			}
		PRINT(_L("CreatePredSearchTablesL create entry to tables"));
		if (aAllTables)
			{
			i12keyTable.CreateInDbL(*contact);
			}
		if (ReadMailAddressesL(*contact))
			{
			iQwertyTable.CreateInDbL(*contact);
			}

		CleanupStack::PopAndDestroy(contact);
        }

    // Leave if we didn't complete going through the results properly
    if (err != KSqlAtEnd)
        {
		PRINT1(_L("CreatePredSearchTablesL SQL err=%d"), err);
        User::Leave(err);
        }
    CleanupStack::PopAndDestroy(&stmnt);
	CleanupStack::PopAndDestroy(sqlStatement);

	PRINT(_L("CPredictiveSearchSynchronizer::CreatePredSearchTablesL ends"));
	}