// 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:
//

#include <testexecutelog.h>
#include "t_SmsReplyToStep.h"
#include <smuthdr.h>
#include <txtrich.h>
#include <msvuids.h>
#include <smsuaddr.h>
#include <csmsaccount.h>
#include "gsmuIEOperations.h"
#include <CommsDatTypesV1_1.h>

using namespace CommsDat;
LOCAL_D RTest test(_L("TestTextE_1_1"));
_LIT(KTestMessageDir,"");

const TTimeIntervalMicroSeconds32 KWaitForWatchersToStart = 20000000;
const TTimeIntervalMicroSeconds32 KWaitForWatchersToStartDisplayInterval = 5000000;

_LIT(KMessageData, "This is a simple text message");
_LIT(KRecipientOk,		"+44111111111");  // has to be valid number and switched on

		
void EntryObserver::HandleEntryEventL(TMsvEntryEvent aEvent, TAny* /*aArg1*/, TAny* /*aArg2*/, TAny* /*aArg3*/)
	{
	switch (aEvent)
		{
			case EMsvEntryChanged:
				{
				break;
				}
			case EMsvNewChildren:
				{	
				CActiveScheduler::Stop();
				break;
				}
						
		default:
				{
				break;
				}
		}
	}
		
CSmsReplyToStep::CSmsReplyToStep()
:CTestStep()
	{	
	}
		
CSmsReplyToStep::~CSmsReplyToStep()
	{
	delete iTestUtils;
	delete iEntry;
	delete iScheduler;
	delete iEntryObserver;
	delete iSessionObserver;
	delete iSession;
	delete iWatchers;
	delete iOperation;
	delete iTestActive;
	test.End();
	test.Close();
	__UHEAP_MARKEND;
	}

void CSmsReplyToStep::InitialiseReplyToStepL()
{
	SetTestStepName(KSmsReplyToStep1);
	iScheduler = new (ELeave) CActiveScheduler;
	CleanupStack::PushL(iScheduler); 
	CActiveScheduler::Install(iScheduler);	
}
	
void CSmsReplyToStep::InitialiseTestL()
	{
	INFO_PRINTF1(_L("Initialising the test..."));
	iTestUtils = CSmsTestUtils::NewL(test);	
	// Notify the system agent that the phone is on.
	iTestUtils->NotifySaPhoneOnL();
	
	// Restore the service settings.
	iTestUtils->SetEntryL(iTestUtils->iSmsServiceId);
	CSmsAccount* account = CSmsAccount::NewLC();
	account->LoadSettingsL(*iTestUtils->iServiceSettings);
	
	// Remove the default service centres from the service settings
	TInt count = iTestUtils->iServiceSettings->ServiceCenterCount();
	while( count-- )
		{
		iTestUtils->iServiceSettings->RemoveServiceCenter(count);
		}
		
	// Add the Vodafone service centre - store the settings.
	iTestUtils->iServiceSettings->AddServiceCenterL(_L("Vodafone"), _L("+447785016005"));

	// Set delivery options - do matching and make reports visible.	
	iTestUtils->iServiceSettings->SetDeliveryReport(ETrue);
	iTestUtils->iServiceSettings->SetStatusReportHandling(CSmsSettings::EMoveReportToInboxVisibleAndMatch);

	account->SaveSettingsL(*iTestUtils->iServiceSettings);
	CleanupStack::PopAndDestroy(account);

	// set up an opserver to observe the inbox
	iEntryObserver = new (ELeave) EntryObserver();
	iSessionObserver = new (ELeave) SessionObserver();
	iSession = CMsvSession::OpenSyncL(*iSessionObserver);
	TMsvSelectionOrdering ordering;	
	iEntry = CMsvEntry::NewL(*iSession, KMsvGlobalInBoxIndexEntryIdValue,ordering);
	iEntry->AddObserverL(*iEntryObserver);
	
	//used for acynchronous calls
	iTestActive=new(ELeave) CTestActive;
	
	INFO_PRINTF1(_L("Successfully initialised test"));
	
}
	
void CSmsReplyToStep::InitialiseSimTsyL()
	{
	
	INFO_PRINTF1(_L("Initialising the SimTsy..."));
	
	_LIT(KDefaultTsyName, "SIM"); 
	HBufC* tsyName =KDefaultTsyName().AllocLC();

	//Initialize TSY using the System Agent
	TInt testState;
	TInt testNumber=1;
	if(KErrNone != RProperty::Get(KUidPSSimTsyCategory, KPSSimTsyTestNumber, testState))
		{
		User::LeaveIfError(RProperty::Define(KUidPSSimTsyCategory, KPSSimTsyTestNumber, RProperty::EInt));
		}
	User::LeaveIfError(RProperty::Set(KUidPSSimTsyCategory, KPSSimTsyTestNumber, testNumber));
	if(KErrNone != RProperty::Get(KUidSystemCategory, KMsvTestUidPhonePwrValue, testState))
		{
		User::LeaveIfError(RProperty::Define(KUidSystemCategory, KMsvTestUidPhonePwrValue, RProperty::EInt));
		}
	User::LeaveIfError(RProperty::Set(KUidSystemCategory, KMsvTestUidPhonePwrValue, EMsvTestPhoneOn));

	User::LeaveIfError(RProperty::Get(KUidPSSimTsyCategory, KPSSimTsyTestNumber, testNumber));

	RTelServer etelServer;
	User::LeaveIfError(etelServer.Connect());
	CleanupClosePushL(etelServer);
	User::LeaveIfError(etelServer.LoadPhoneModule(tsyName->Des()));

	// Find the phone corresponding to this TSY and open a number of handles on it
	TInt numPhones;
	User::LeaveIfError(etelServer.EnumeratePhones(numPhones));	
	TBool found=EFalse;
	
	RMobilePhone iPhone;
	while (!found && numPhones--)
		{
		TName phoneTsy;
		User::LeaveIfError(etelServer.GetTsyName(numPhones,phoneTsy));
		if (phoneTsy.CompareF(tsyName->Des())==KErrNone)
			{
			found = ETrue;
			RTelServer::TPhoneInfo info;
			User::LeaveIfError(etelServer.GetPhoneInfo(numPhones,info));
			CleanupClosePushL(iPhone);
			User::LeaveIfError(iPhone.Open(etelServer,info.iName));
			User::LeaveIfError(iPhone.Initialise());
			//Required Pause to Allow SMSStack to Complete its Async Init call to the TSY and finish its StartUp.
			TTimeIntervalMicroSeconds32 InitPause=9000000;  
			User::After(InitPause);							
			
			CleanupStack::PopAndDestroy(&iPhone);
			}
		}
	
	CleanupStack::PopAndDestroy(&etelServer);	

	CMDBSession* dbSession = CMDBSession::NewL(CMDBSession::LatestVersion());
	CleanupStack::PushL(dbSession);
	CMDBRecordSet<CCDGlobalSettingsRecord> globalSettingsRecord(KCDTIdGlobalSettingsRecord);
	TRAPD(err, globalSettingsRecord.LoadL(*dbSession));
	if(err != KErrNone)
		{
		User::Leave(KErrNotFound);				
		}
	
	CCDModemBearerRecord *modemRecord = static_cast<CCDModemBearerRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdModemBearerRecord));		
	CleanupStack::PushL(modemRecord);
	modemRecord->SetRecordId(((CCDGlobalSettingsRecord*)globalSettingsRecord.iRecords[0])->iModemForPhoneServicesAndSMS);
	modemRecord->LoadL(*dbSession);
	modemRecord->iTsyName.SetMaxLengthL(tsyName->Des().Length());
	modemRecord->iTsyName = tsyName->Des();	
	modemRecord->ModifyL(*dbSession);
	CleanupStack::PopAndDestroy(3);  //tsyName, dbSession, modemRecord 	
	
	INFO_PRINTF1(_L("Successfully initialised the Sim Tsy"));
	}
	
void CSmsReplyToStep::StartWatcherL()
	{
	INFO_PRINTF1(_L("Start the Watcher"));

	if( WatchersAlreadyRunningL() )
		{
		INFO_PRINTF1(_L("Watchers are already running\n"));
		return;
		}

	iWatchers = CTestUtilsWatcherStarter::NewL();

	TTimeIntervalMicroSeconds32 wait = KWaitForWatchersToStart;
	TBool started = EFalse;
	while( !started && wait.Int() > 0 )
		{
		INFO_PRINTF2(_L("Waiting %d secs for watchers to start..."), wait.Int() / 1000000);
		wait = wait.Int() - KWaitForWatchersToStartDisplayInterval.Int();
		User::After(KWaitForWatchersToStartDisplayInterval);
		started = WatchersAlreadyRunningL();
		}

	if( !WatchersAlreadyRunningL() )
		{
		INFO_PRINTF1(_L("WARNING: NBS Watcher has not started yet\n"));
		}
	}
	
TBool CSmsReplyToStep::WatchersAlreadyRunningL()
	{
	RSocketServ server;
	RSocket socket;

	User::LeaveIfError(server.Connect());
	CleanupClosePushL(server);

		// test if it's there... 
	TProtocolDesc protoInfo;
	TProtocolName protocolname;
	protocolname.Copy(KSmsDatagram);
	User::LeaveIfError(server.FindProtocol(protocolname,protoInfo));

	User::LeaveIfError(socket.Open(server,
										protoInfo.iAddrFamily,
										protoInfo.iSockType, 
										protoInfo.iProtocol));
	CleanupClosePushL(socket);
	

	TSmsAddr addr;
	addr.SetSmsAddrFamily(ESmsAddrRecvAny);
	TInt err = socket.Bind(addr);

	CleanupStack::Pop(2, &server);
	socket.CancelAll();
	socket.Close();
	server.Close();
	return (err == KErrAlreadyExists);
	}

void CSmsReplyToStep::SetRecipientsL(CSmsHeader& aHeader)
	{
	iTestUtils->Printf(_L("--Setting single recipient\n"));
	
	CSmsNumber* rcpt = CSmsNumber::NewL();
	CleanupStack::PushL(rcpt);
	rcpt->SetAddressL(KRecipientOk);
	aHeader.Recipients().AppendL(rcpt);
	CleanupStack::Pop(rcpt);
	}
	
void CSmsReplyToStep::CreateMessageL()
	{
	INFO_PRINTF1(_L("Creating message..."));
	
	TMsvEntry entry;
	entry.SetVisible(ETrue); 
	entry.SetInPreparation(ETrue); 
	entry.iServiceId = iTestUtils->iSmsServiceId; 
	entry.iType = KUidMsvMessageEntry; 
	entry.iMtm = KUidMsgTypeSMS; 
	entry.iDate.HomeTime(); 
	entry.iSize = 0; 
	entry.iDescription.Set(KNullDesC); 
	entry.iDetails.Set(KNullDesC); 
	entry.SetSendingState(KMsvSendStateScheduled);

	// Create the SMS header object...
	CSmsHeader* header = CSmsHeader::NewL(CSmsPDU::ESmsSubmit, *iTestUtils->iRichText);
	CleanupStack::PushL(header);
	
	// Set the body text...
	iTestUtils->iRichText->Reset();
	iTestUtils->iRichText->InsertL(0, KMessageData);
	
	// Copy the message settings...
	header->SetSmsSettingsL(*iTestUtils->iServiceSettings); 
	
	// Set the service centre
	TInt defaultIndex = iTestUtils->iServiceSettings->DefaultServiceCenter();
	header->SetServiceCenterAddressL(iTestUtils->iServiceSettings->GetServiceCenter(defaultIndex).Address());

	// Set recipient - ask derived class
	SetRecipientsL(*header);
	
	// Update entry description and details...
	CArrayPtrFlat<CSmsNumber>& recipient = header->Recipients();
	entry.iDetails.Set(recipient[0]->Address());
	entry.iDescription.Set(iTestUtils->iRichText->Read(0, iTestUtils->iServiceSettings->DescriptionLength()));
	entry.SetInPreparation(EFalse);
	
	// Create the entry - set context to the global outbox.
	iTestUtils->iMsvEntry->SetEntryL(KMsvGlobalOutBoxIndexEntryId);
	iTestUtils->iMsvEntry->CreateL(entry);

	// Create new store and save header information 
	iTestUtils->iMsvEntry->SetEntryL(entry.Id()); 
	CMsvStore* store = iTestUtils->iMsvEntry->EditStoreL(); 
	CleanupStack::PushL(store); 
	header->StoreL(*store);
	store->StoreBodyTextL(*iTestUtils->iRichText);
	store->CommitL(); 
	CleanupStack::PopAndDestroy(2, header); 
	
	iMessageId = entry.Id();

	}
	
void CSmsReplyToStep::SendMessageL()
	{
	INFO_PRINTF1(_L("Sending message..."));

	delete iOperation;
	iOperation = NULL;

	CMsvEntrySelection* sel = new (ELeave) CMsvEntrySelection();
	CleanupStack::PushL(sel);
	sel->AppendL(iMessageId);
	iTestUtils->DisplayMessageL(iMessageId);
	iTestUtils->iMsvEntry->SetEntryL(KMsvGlobalOutBoxIndexEntryId);
	iOperation = iTestUtils->iMsvEntry->CopyL(*sel, iTestUtils->iSmsServiceId,iTestActive->iStatus);
	iTestActive->StartL();
	CActiveScheduler::Start();	
	CleanupStack::PopAndDestroy(sel);
	}

TBool CSmsReplyToStep::CheckMessageL()
	{

	INFO_PRINTF1(_L("Received new message in Inbox - should be status report..."));
		
	TMsvSelectionOrdering ordering;	
	ordering.ShowInvisibleEntries();
	CMsvEntry* entry = CMsvEntry::NewL(*iSession, KMsvGlobalInBoxIndexEntryId,ordering);
	CleanupStack::PushL(entry);
	
	CMsvEntrySelection* msvEntrySelection;
	msvEntrySelection=entry->ChildrenL();
	CleanupStack::PushL(msvEntrySelection);
	
	// Check how many mesasges there are - should be just 1
	TInt count = msvEntrySelection->Count();
	INFO_PRINTF3(_L("Number of new messages: %d, should be: %d"), count, 1);

	// Restore the message
	CSmsHeader* header = CSmsHeader::NewL(CSmsPDU::ESmsDeliver, *iTestUtils->iRichText);
	CleanupStack::PushL(header);
	entry->SetEntryL((*msvEntrySelection)[0]);

	CMsvStore* store = entry->ReadStoreL();
	CleanupStack::PushL(store);	
	header->RestoreL(*store);
	
	if(store->HasBodyTextL())
		{
		store->RestoreBodyTextL(*iTestUtils->iRichText);	
		}
		
	TBuf<KSmsDescriptionLength> desc;
	User::LeaveIfError(TSmsUtilities::GetDescription(header->Message(), desc));
	
	//Check for a reply address field
	CSmsReplyAddressOperations& operations = STATIC_CAST(CSmsReplyAddressOperations&,header->Message().GetOperationsForIEL(CSmsInformationElement::ESmsReplyAddressFormat));
	TBool result=operations.ContainsReplyAddressIEL();

	CleanupStack::PopAndDestroy(4,entry);	
	return result;	
	}

TVerdict CSmsReplyToStep::doTestStepPreambleL()
	{	
	__UHEAP_MARK;
	SetTestStepResult(EPass);
	test.Start(_L("sdf"));
	InitialiseTestL();
	InitialiseSimTsyL();
	StartWatcherL();
	iTestUtils->DeleteSmsMessagesL(KMsvGlobalOutBoxIndexEntryId);
	iTestUtils->DeleteSmsMessagesL(KMsvGlobalInBoxIndexEntryId);
	iTestUtils->DeleteSmsMessagesL(KMsvSentEntryId);
	CreateMessageL();
	SendMessageL();
	//wait for message to be received...
	CActiveScheduler::Start();	

	return TestStepResult();
	}
		

TVerdict CSmsReplyToStep::doTestStepL()
	{		
	if(CheckMessageL())
		{
		SetTestStepResult(EPass);	
		}
	else
		{
		SetTestStepResult(EFail);			
		}
	
	return TestStepResult();
	}	

TVerdict CSmsReplyToStep::doTestStepPostambleL()
/**
 * @return - TVerdict code
 * Override of base class virtual
 */
	{
	return TestStepResult();
	}
	
	


