// PROFILE.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <f32file.h>
#include <fbs.h>
#include <s32std.h> 
#include <s32stor.h> 
#include <s32file.h> 

#include <apaid.h>
#include "..\apparc\apadll.h"
#include <apffndr.h>
#include <apgaplst.h>
#include <apgicnfl.h>
#include <apgdoor.h>
#include <apffndr.h>
#include <apfrec.h>
#include <apfctlf.h>
#include <apgctl.h>
#include <apgaplst.h>
#include <apaflrec.h>
#include <apgcli.h>
#include <apacmdln.h>
#include <apsserv.h>
#include "..\apserv\apsclsv.h" // so I can start the server
#include "tstapp.h"
//
#if !defined(__E32TEST_H__)
#include <e32test.h>
#endif


const TInt KTestCleanupStack=0x40;

LOCAL_D TUid testUid={1};
LOCAL_D TFileName dllname=_L("tstapp.app");
LOCAL_D TApaAppCaption KAppCaption=_L("Test App");
LOCAL_D TFullName searchPath=_L("\\system\\apps\\");
LOCAL_D TFullName filePath=_L("c:\\docs\\tstapp.doc");
LOCAL_D TFullName tempPath=_L("c:\\system\\temp\\");
LOCAL_D TFullName appPath=_L("z:\\system\\apps\\tstapp\\tstapp.app");
LOCAL_D TFullName icnPath=_L("z:\\system\\apps\\tstapp\\tstapp.aif");
LOCAL_D TFullName iniPath=_L("c:\\system\\apps\\tstapp\\tstapp.ini");

LOCAL_D RTest test(_L("Profile"));
LOCAL_D CTrapCleanup* TheTrapCleanup;
LOCAL_D CApaProcess* TheProcess;
LOCAL_D RFs TheFs;


LOCAL_C void setupCleanup()
//
// Initialise the cleanup stack.
//
    {
	TheTrapCleanup=CTrapCleanup::New();
	TRAPD(r,\
		{\
		for (TInt i=KTestCleanupStack;i>0;i--)\
			CleanupStack::PushL((TAny*)1);\
		test(r==KErrNone);\
		CleanupStack::Pop(KTestCleanupStack);\
		});
	}


class CDummyShell : public CBase, public MApaAppStarter
	{
public:
	static TInt ThreadStart(TAny* aArg);
	TThreadId StartAppL(const CApaCommandLine&) { return *(TThreadId*)this; }
private:
	void ConstructL();
public:
	CApaAppList* iAppList;
	CApaFileRecognizer* iFileRecognizer;
	CApaAppListServer* iServer;
	RFs iFs;
	RFbsSession iFbs;
	};


GLDEF_C TInt CDummyShell::ThreadStart(TAny* anArg)
// Start up a new server
	{
	setupCleanup();
	// convert argument into semaphore reference
	RSemaphore& semaphore=*(RSemaphore*)anArg;
	//
	// start scheduler and server
	CActiveScheduler *pA=new CActiveScheduler;
	CActiveScheduler::Install(pA);
	//
	// construct shell
	CDummyShell* shell=new CDummyShell();
	TRAPD(ret,shell->ConstructL());
	//
	// signal that we've started
	semaphore.Signal();
	//
	// start fielding requests from clients
	CActiveScheduler::Start();
	//
	// finished
	return(ret);
	}


void CDummyShell::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	User::LeaveIfError(iFbs.Connect());
	//
	// create app list & recognizer
	CApaAppFinder* appFinder=CApaScanningAppFinder::NewL(iFs);
	iAppList = CApaAppList::NewL(iFs,appFinder);	// takes ownership of appFinder
	iAppList->UpdateL();
	iFileRecognizer = CApaScanningFileRecognizer::NewL(iFs,this);
	iServer = CApaAppListServer::NewL(iAppList,iFileRecognizer);
	}


LOCAL_C TInt StartServerInThread()
// Starts a server in a new thread
// This function is exported from the DLL and called from the client 
    {
	TInt res=KErrNone;
	// create server - if one of this name does not already exist
	TFindServer findServer(KAppListServerName);
	TFullName name;
	if (findServer.Next(name)!=KErrNone) // we don't exist already
		{
		RThread thread;
		RSemaphore semaphore;
		semaphore.CreateLocal(0); // create a semaphore so we know when thread finished

		RThread myThread;
		res=thread.Create(KAppListServerName,CDummyShell::ThreadStart,KDefaultStackSize,myThread.Heap(),&semaphore);

		if (res==KErrNone) // thread created ok - now start it going
			{
			thread.SetPriority(EPriorityNormal);
			thread.Resume(); // start it going
			semaphore.Wait(); // wait until it's initialized
			thread.Close(); // we're no longer interested in the other thread
			}
		else // thread not created ok
			{
			thread.Close(); // therefore we've no further interest in it
			}
		semaphore.Close();
		// notify the kernel that a server has started.
		#if defined (__WINS__)
		UserSvr::ServerStarted();
		#endif
		}
	else 
		return KErrAlreadyExists;
    return res;
    }


LOCAL_D void setup()
	{
#if defined(__EPOC32__)
	// if we're on the rack create the directories we need
	TParse parser;
	parser.Set(filePath,NULL,NULL);
	TheFs.MkDirAll(parser.DriveAndPath());
	parser.Set(tempPath,NULL,NULL);
	TheFs.MkDirAll(parser.DriveAndPath());
#endif
	}


////////////////////

LOCAL_C void ProfileAppListL()
	{
	test.Next(_L("Profiling CApaAppList"));
	//
	// set up applist
	CApaAppFinder* appFinder=CApaScanningAppFinder::NewL(TheFs);
	CApaAppList* appList = CApaAppList::NewL(TheFs,appFinder);	// takes ownership of appFinder
	//
	// set up profiling
	/*
	16 - AppList::Update
	17 - AppData::UpdateAif
	*/
	RDebug::ProfileReset(16,2); 
	//
	// update list 100 times with no changes
	test.Next(_L("Updating list 100 times"));
	for (TInt i=0 ; i<100 ; i++)
		appList->UpdateL();
	//
	// get the results
	TProfile result; // iTime, iCount
	TBuf<64> resultBuf;
	//
	RDebug::ProfileResult(&result,16,1);
	resultBuf.Format(_L("AppList::Update() - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,17,1);
	resultBuf.Format(_L("AppData::UpdateAif() - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	// tidy up
	delete appList;
	}

	
/*	
LOCAL_C void ProfileDoorsL()
	{
	test.Next(_L("Profiling CApaDoor"));
	//
	// delete the file to be created by the testcode
	TheFs.Delete(filePath);
	// create a process
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	TRAPD(ret,TheProcess = CApaProcess::NewL(TheFs,*finder));
		test(ret==KErrNone);
	//
	// create a new main doc of type tstapp
	CFileStore* store = NULL;
	CApaDocument* doc=NULL;
	TRAP(ret,doc=TheProcess->AddNewDocumentL(dllname));
		test(ret==KErrNone);
	TheProcess->SetMainDocument(doc);
	TRAP(ret, {
		store=doc->CreateFileStoreLC(TheProcess->FsSession(),filePath);
		CleanupStack::Pop(); // store 
		});
		test(ret==KErrNone);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
	TheProcess->SetMainDocFileName(filePath);
	// initialise the document with factory settings
	TRAP(ret, doc->NewDocumentL() );
		test(ret==KErrNone);
	//
	/////////////////////////////////////////////////////////////////////////////////
	// Start the profiling
	/////////////////////////////////////////////////////////////////////////////////
	//
	;
	 
	Profiling points used:
	0  - Process::AddNewDocument()
	1  - Process::OpenNewDocument()
	2  - Process::AddAppDllL()
	3  - Door::ConstructL()
	4  - Door::StoreL()
	5  - Door::Restore()
	6  - Door::SetFormatToIcon()
	7  - Door::SetFormatToGlass()
	8  - Door::SFTI::FindAIF
	9  - Door::Construct::OpenAIF
	10 - Door::GetDefaultIcon
	11 - Door::SFTI::CreateIcon
	12 - Door::ReadStreamDictionary
	13 - Door::Restore::InternalizeStreams
	14 - Door::Restore::InternalizeStore
	15 - Door::SFTI::FindApp
	16 - AppList::Update
	17 - AppData::UpdateAif
	
	RDebug::ProfileReset(0,21); 
	//
	// embed 100 tstapp docs
	test.Next(_L("Embedding 100 documents"));
	for (TInt i=0 ; i<100 ; i++)
		{
		RDebug::ProfileStart(20);
		((CTestAppDoc*)TheProcess->MainDocument())->EmbedNewDocL(dllname);
		RDebug::ProfileEnd(20);
		}
	//
	// get the results
	TProfile result; // iTime, iCount
	TBuf<64> resultBuf;
	//
	RDebug::ProfileResult(&result,20,1);
	resultBuf.Format(_L("Embedding a doc - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,0,1);
	resultBuf.Format(_L("Process::AddNewDocument() - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,3,1);
	resultBuf.Format(_L("Door::Construct() - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,9,1);
	resultBuf.Format(_L("Door::Construct::OpenAIF - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,6,1);
	resultBuf.Format(_L("Door::SetFormatToIcon() - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,8,1);
	resultBuf.Format(_L("Door::SFTI::FindAIF - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,11,1);
	resultBuf.Format(_L("Door::SFTI::CreateIcon - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	test.Next(_L("Press a key to continue..."));
	test.Getch();
	//
	// create a doc with an embedded object and load it 100 times
	TheProcess->ResetL();
	TheFs.Delete(filePath);
	doc = NULL;
	TRAP(ret,doc=TheProcess->AddNewDocumentL(dllname));
		test(ret==KErrNone);
	TheProcess->SetMainDocument(doc);
	// create the store and initialise it
	TRAP(ret, {
		store=doc->CreateFileStoreLC(TheProcess->FsSession(),filePath);
		CleanupStack::Pop(); // store 
		});
		test(ret==KErrNone);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
	TheProcess->SetMainDocFileName(filePath);
	// initialise the document with factory settings
	TRAP(ret, doc->NewDocumentL() );
		test(ret==KErrNone);
	// embed a doc and save
	TRAP(ret,((CTestAppDoc*)TheProcess->MainDocument())->EmbedNewDocL(dllname));
		test(ret==KErrNone);
	TRAP(ret,TheProcess->MainDocument()->SaveL());
		test(ret==KErrNone);
	//
	// do the profiling...
	RDebug::ProfileReset(0,21); 
	//
	// load doc cold 100 times
	TRAP(ret,TheProcess->ResetL());
		test(ret==KErrNone);
	test.Next(_L("Loading doc 100 times"));
	for (i=0 ; i<100 ; i++)
		{
		CStreamDictionary* streamDic=NULL;
		TRAP(ret,
			RDebug::ProfileStart(19);
			doc=TheProcess->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite);
			RDebug::ProfileEnd(19);
			);
			test(ret==KErrNone);
		delete streamDic;
		TheProcess->DestroyDocument(doc);
		TRAP(ret,TheProcess->ResetL());
			test(ret==KErrNone);
		delete store;
		}
	//
	RDebug::ProfileResult(&result,19,1);
	resultBuf.Format(_L("Loading doc - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,5,1);
	resultBuf.Format(_L("Door::Restore - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,12,1);
	resultBuf.Format(_L("Door::ReadStreamDictionary - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,13,1);
	resultBuf.Format(_L("Door::Restore::InternalizeStreams - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,14,1);
	resultBuf.Format(_L("Door::Restore::InternalizeStore - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,6,1);
	resultBuf.Format(_L("Door::SetFormatToIcon() - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,15,1);
	resultBuf.Format(_L("Door::SFTI::FindApp - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,8,1);
	resultBuf.Format(_L("Door::SFTI::FindAIF - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,9,1);
	resultBuf.Format(_L("Door::SFTI::GetCapAndIcon - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,11,1);
	resultBuf.Format(_L("Door::SFTI::CreateIcon - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	RDebug::ProfileResult(&result,10,1);
	resultBuf.Format(_L("Door::SFTI::GetDefaultIcon - Time: %D, Count: %D"),result.iTime,result.iCount);
	test.Next(resultBuf);
	//
	// tidy up and delete the file created by the testcode
	TheProcess->ResetL();
	delete TheProcess;
	TheFs.Delete(filePath);
	}
*/

GLDEF_C TInt E32Main()
	{
	setupCleanup();
	//
	test.Title();
	test.Start(_L("Profiling Apparch..."));
	//
	// set up an fbs
	FbsStartup();
	TInt ret=RFbsSession::Connect();
		test(!ret);
	//
	// set up the directory structure
	TheFs.Connect();
	setup();
	//
	// set up the server
	ret=StartServerInThread();
		test(ret==KErrNone);
	//
	// run the testcode (inside an alloc heaven harness)

	__UHEAP_MARK;
//	TRAPD(r,ProfileDoorsL());
//		test(r==KErrNone);
	__UHEAP_MARKEND;

	__UHEAP_MARK;
	TRAPD(r,ProfileAppListL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	test.End();
	test.Close();
	
	delete TheTrapCleanup;
	return KErrNone;
	}

