/*
* Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
* Contact: http://www.qt-project.org/legal
* 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: 
*
*/


/**
@SYMPREQ                  PREQ1187
@SYMComponent             app-engines_cntmodel
@SYMAuthor                Simon Mellor, JamesCl
@SYMTestStatus            Implemented
@SYMTestType              CT

@SYMTestCaseDesc          Tests the performance of Reading and Updating a single contact and of
						  Matching Contacts by Phone Number on a corporate profile database of 
						  1000 contacts. 

@SYMTestActions           Measures the time taken to: 
						  -- Attempt to match a phone number using CContactDatabase::MatchPhoneNumberL()
						  -- Create a contact using CContactDatabase::AddNewContactL()
						  -- Read   a contact using CContactDatabase::OpenContactLX()
						  -- Update a contact using CContactDatabase::CommitContactL()
						  -- Delete a contact using CContactDatabase::DeleteContactL()

@SYMTestExpectedResults   Test cases will run without leaving and will output timing information.

*/

#include "t_perfcrudoperations.h"
#include "../t_utils.h"
#include <cntitem.h>

// Constants   
_LIT(KDbPathName,"C:Contacts.cdb");
const TPtrC KDbPath( (KDbPathName) );


CCrudOperations::CCrudOperations()
	{
	} 

CCrudOperations::~CCrudOperations()
	{
	iDb->CloseTables();
	delete iDb;
	} 
	
CCrudOperations* CCrudOperations::NewLC(RTest& aTest)
	{
	CCrudOperations* self = new(ELeave) CCrudOperations();
	CleanupStack::PushL(self);
	self->ConstructL(aTest);
	return(self);
	}  

void CCrudOperations::ConstructL(RTest& aTest)
	{
	iTest = &aTest;
	iDb = CContactDatabase::OpenL(KDbPath);
	CCntTest::ProfileReset(0, 59);
	} 

/**
	Main test routine.
*/
void CCrudOperations::DoTestsL(TInt aNumMsToGet20ItemsFromView)
	{
	iNumMsToGet20ItemsFromView= aNumMsToGet20ItemsFromView;

	// As, at this point, we haven't used the database before, this is the 
	// equivalent of startup. We fetch a contact as a bare minimum operation 
	// on the database to ensure that we fetch and cache the system template.
	// Then, we just get rid of the contact item as we don't actually want it.
	const TInt KContactIdOne(1);
	CContactItem* tmpItem = iDb->ReadContactLC(KContactIdOne);
	CleanupStack::PopAndDestroy(tmpItem);
	tmpItem = NULL;

	MatchContactsByPhoneNumL();
	MatchContactsByEmailAndSipL();
	DoCrudTestsL();
	}

/**
	Try to match the phone number given with existing numbers in the database.
*/
void CCrudOperations::MatchContactsByPhoneNumL()
	{
	_LIT(KPass, "Pass");
	_LIT(KFail, "Fail");
	_LIT(KMatchOutputFormat1, "Number of phone numbers matched: %d -- %s\n");
	_LIT(KMatchOutputFormat2, "Phone number lookup took: %d s %03d\n");
	_LIT(KMatchOutputFormat3, "The contact's first name: %S\n");

	_LIT(KPhoneNumberToFind, "241867306233253164487125"); // this number belongs to the 1000th
														  // contact item in the database, which 
														  // has a photo. 
	
	const TInt KMatchLengthFromRight(7); // match on the number without the dialling code prefix
										 // to avoid differences like +447876... and 07876...
	_LIT(KPhoneNumberTestTitle, "\nBeginning Phone Number Match testing...\n");


	iTest->Printf(KPhoneNumberTestTitle);
	TCntPerfTimer timer;
	timer.StartTimer();
	
	// Search the database...
	CContactIdArray* idArray = iDb->MatchPhoneNumberL(KPhoneNumberToFind, KMatchLengthFromRight);
	CleanupStack::PushL(idArray);
	TInt numMatches = idArray->Count();
	iTest->Printf(KMatchOutputFormat1, numMatches, numMatches ? KPass().Ptr() : KFail().Ptr());

	if (numMatches)
		{
		//fetch first contact item in array
		CContactItem* item = iDb->ReadContactLC((*idArray)[0]);
		timer.StopTimer();
		CContactItemFieldSet& fieldSet = item->CardFields();
		TInt firstNameFieldId = fieldSet.Find(KUidContactFieldGivenName);
		if (firstNameFieldId == KErrNotFound)
			{
			User::Leave(KErrNotFound);
			}
		CContactItemField& firstNameField = fieldSet[firstNameFieldId];
		CContactTextField* firstNameText = firstNameField.TextStorage();
		TPtrC firstName(firstNameText->Text());
		iTest->Printf(KMatchOutputFormat3, &firstName);

		CleanupStack::PopAndDestroy(item);
		}
	else
		{
		timer.StopTimer();
		}

	CleanupStack::PopAndDestroy(idArray);

	TInt result = timer.Result();
	TBuf<64> formattable;
	formattable.Format(KMatchOutputFormat2, result / 1000000, (result / 1000) % 1000);
	iTest->Printf(formattable);
	}

/**
	Try to match the phone number given with existing numbers in the database.
*/
void CCrudOperations::MatchContactsByEmailAndSipL()
	{
	_LIT(KPass, "Pass");
	_LIT(KFail, "Fail");
	_LIT(KEmailMatchOutputFormat1,"Number of email addresses matched: %d -- %s\n");
	_LIT(KEmailMatchOutputFormat2,"Email address lookup took: %d s %03d\n");
	_LIT(KMatchOutputFormat3, "The contact's first name: %S\n");

	// Test Email address matching

	// this address belongs to the 1000th contact item in the database, which has a photo. 
	_LIT(KEmailAddressToFind, "fred.bloggs@symbian.com"); 
	_LIT(KEmailTestTitle, "\nBeginning Email Address Match testing...\n");

	iTest->Printf(KEmailTestTitle);
	TCntPerfTimer timer;
	timer.StartTimer();
	
	// Search the database...
	CContactItemFieldDef* fieldsToSearch = new (ELeave) CContactItemFieldDef();
	CleanupStack::PushL(fieldsToSearch);
	fieldsToSearch->AppendL(KUidContactFieldEMail);
	CContactIdArray* idArray = iDb->FindLC(KEmailAddressToFind, fieldsToSearch);
	TInt numMatches = idArray->Count();
	iTest->Printf(KEmailMatchOutputFormat1, numMatches, numMatches ? KPass().Ptr() : KFail().Ptr());

	if (numMatches)
		{
		//fetch first contact item in array
		CContactItem* item = iDb->ReadContactLC((*idArray)[0]);
		CContactItemFieldSet& fieldSet = item->CardFields();
		TInt firstNameFieldId = fieldSet.Find(KUidContactFieldGivenName);
		if (firstNameFieldId == KErrNotFound)
			{
			User::Leave(KErrNotFound);
			}
		CContactItemField& firstNameField = fieldSet[firstNameFieldId];
		CContactTextField* firstNameText = firstNameField.TextStorage();
		TPtrC firstName(firstNameText->Text());
		iTest->Printf(KMatchOutputFormat3, &firstName);
		CleanupStack::PopAndDestroy(item);
		}
	
	timer.StopTimer();
	CleanupStack::PopAndDestroy(2, fieldsToSearch); // and idArray

	
	TInt result = timer.Result();
	TBuf<64> formattable;
	formattable.Format(KEmailMatchOutputFormat2, result / 1000000, (result / 1000) % 1000);
	iTest->Printf(formattable);

	// reset variables
	fieldsToSearch = NULL;
	idArray = NULL;
	numMatches = 0;
	timer.ResetTimer();
	result = 0;
	formattable.Zero();

	
	// Test SIP address matching

	// this address belongs to the 1000th contact item in the database, which has a photo. 
	_LIT(KSipAddressToFind, "sip:fred.bloggs@symbian.com"); 
	_LIT(KSipTestTitle, "\nBeginning SIP Address Match testing...\n");
	_LIT(KSipMatchOutputFormat1,"Number of SIP addresses matched: %d -- %s\n");
	_LIT(KSipMatchOutputFormat2,"SIP address lookup took: %d s %03d\n");

	iTest->Printf(KSipTestTitle);
	timer.StartTimer();
	
	// Search the database...
	fieldsToSearch = new (ELeave) CContactItemFieldDef();
	CleanupStack::PushL(fieldsToSearch);
	fieldsToSearch->AppendL(KUidContactFieldSIPID);
	idArray = iDb->FindLC(KSipAddressToFind, fieldsToSearch);
	numMatches = idArray->Count();
	iTest->Printf(KSipMatchOutputFormat1, numMatches, numMatches ? KPass().Ptr() : KFail().Ptr());

	if (numMatches)
		{
		//fetch first contact item in array
		CContactItem* item = iDb->ReadContactLC((*idArray)[0]);
		CContactItemFieldSet& fieldSet = item->CardFields();
		TInt firstNameFieldId = fieldSet.Find(KUidContactFieldGivenName);
		if (firstNameFieldId == KErrNotFound)
			{
			User::Leave(KErrNotFound);
			}
		CContactItemField& firstNameField = fieldSet[firstNameFieldId];
		CContactTextField* firstNameText = firstNameField.TextStorage();
		TPtrC firstName(firstNameText->Text());
		iTest->Printf(KMatchOutputFormat3, &firstName);
		CleanupStack::PopAndDestroy(item);
		}
	
	timer.StopTimer();
	CleanupStack::PopAndDestroy(2, fieldsToSearch); // and idArray

	result = timer.Result();
	formattable.Format(KSipMatchOutputFormat2, result / 1000000, (result / 1000) % 1000);
	iTest->Printf(formattable);
	}


/**
	Perform CRUD operations with 1 item in the database.
*/
void CCrudOperations::DoCrudTestsL()
	{
	// chosen because they have a photo field
	const TContactItemId K901stContactItemId(901);
	const TContactItemId K973rdContactItemId(973); 
	const TContactItemId K926thContactItemId(926);

	_LIT(KCRUDTestTitle, "\nBeginning CRUD Operations on 1 Contact (with photo) testing ...\n");
	_LIT(KCRUDTestNote, "[Figures for each write operation include time to fetch first 20 items in view.]\n");
	iTest->Printf(KCRUDTestTitle);
	iTest->Printf(KCRUDTestNote);
	
	TCntPerfTimer timer;

	// fetch a contact item to seed a new one
	CContactItem* temp = iDb->OpenContactL(K901stContactItemId);
	CleanupStack::PushL(temp);
	CContactItem* item = CContactCard::NewL(temp);
	CleanupStack::PopAndDestroy(temp);
	CleanupStack::PushL(item);

	// Create (add) a contact with a photo
	timer.StartTimer();
	iDb->AddNewContactL(*item);
	timer.StopTimer();
	TInt createResult = timer.Result() + iNumMsToGet20ItemsFromView; // add the time to fetch 20 items from view.
	timer.ResetTimer();
	CleanupStack::PopAndDestroy(item);
	item = NULL;

	// Read a contact with a photo
	timer.StartTimer();
	item = iDb->OpenContactLX(K973rdContactItemId); // lock object put on the CleanupStack
	CleanupStack::PushL(item);
	timer.StopTimer();
	TInt readResult = timer.Result();
	timer.ResetTimer();
	
	// Update the contact in the database
	timer.StartTimer();
	iDb->CommitContactL(*item);
	timer.StopTimer();
	TInt updateResult = timer.Result() + iNumMsToGet20ItemsFromView; // add the time to fetch 20 items from view.
	timer.ResetTimer();
	CleanupStack::PopAndDestroy(item);
	item = NULL;
	CleanupStack::PopAndDestroy(); // lock object

	// Delete a contact with a photo
	timer.StartTimer();
	iDb->DeleteContactL(K926thContactItemId);
	timer.StopTimer();
	TInt deleteResult = timer.Result() + iNumMsToGet20ItemsFromView; // add the time to fetch 20 items from view.
	timer.ResetTimer();
	
	// output timing result
	_LIT(KCreateOutputFormat,"Creating (adding) 1 contact took: %d s %03d\n");
	iTest->Printf(KCreateOutputFormat, createResult / 1000000, (createResult / 1000) % 1000);

	_LIT(KReadOutputFormat,"Reading 1 contact took: %d s %03d\n");
	iTest->Printf(KReadOutputFormat, readResult / 1000000, (readResult / 1000) % 1000);

	_LIT(KUpdateOutputFormat,"Updating 1 contact took: %d s %03d\n");
	iTest->Printf(KUpdateOutputFormat, updateResult / 1000000, (updateResult / 1000) % 1000);

	_LIT(KDeleteOutputFormat,"Deleting 1 contact took: %d s %03d\n");
	iTest->Printf(KDeleteOutputFormat, deleteResult / 1000000, (deleteResult / 1000) % 1000);
	}
