// T_SERV.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <f32file.h>
#include <fbs.h>
#include <apaid.h>
#include <apffndr.h>
#include <apgaplst.h>
#include <apaflrec.h>
#include <apgcli.h>
#include <apacmdln.h>
#include <apsserv.h>
#include <apfrec.h>
#include <datastor.h>
#include <apgicnfl.h>
#include "tstapp.h"
//
#include "..\apserv\apsclsv.h" // so I can start the server
//
#include <e32test.h>

LOCAL_D RTest test(_L("T_Serv"));
LOCAL_D CTrapCleanup* TheTrapCleanup;
LOCAL_D CActiveScheduler* TheScheduler;
LOCAL_D CApaProcess* TheProcess;
LOCAL_D CIdle* TheIdler;
LOCAL_D RFs TheFs;
LOCAL_D TInt DoTestL();

const TInt KTestCleanupStack=0x40;

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 CMyScheduler : public CActiveScheduler
	{
public:
	void Error(TInt) { return; }
	};


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;
    }

GLDEF_C TInt E32Main()
	{
	setupCleanup();

	FbsStartup();
	TInt ret=RFbsSession::Connect();
		test(!ret);
	//
	test.Title();
	test.Start(_L("Testing App list server...ER 1 style interface"));
	//
	// set up the directory structure
	ret = TheFs.Connect();
		test(ret==KErrNone);
	//
	// set up an fbs
	ret = FbsStartup();
		test(ret==KErrNone);
	//
	// set up an app list server
	ret = StartServerInThread();
		test(ret==KErrNone);
	//
	// run the testcode (inside an alloc heaven harness)

//	__UHEAP_MARK;
	// RDebug::Print(_L("About to test server"));
	TRAP(ret,DoTestL());
		test(ret==KErrNone);
		// connection to the server changes state by 15 allocs
//	__UHEAP_CHECK(17);
//	__UHEAP_MARKENDC(17); // we have recognized a file - accordingly one recognizer has new state.

	test.End();
	test.Close();
	
	delete TheTrapCleanup;
	return KErrNone;
	}

#include "tservcom.cpp"