// APGCLI.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include "..\apserv\apsclsv.h"
#include "apgcli.h"
#include "apacmdln.h"
#include "apgstd.h"
#include "apgicnfl.h"
#include <apsserv.h>
#include <apmrec.h>
#include <s32mem.h>

const TUint KDefaultMessageSlots=4;


////////////////////////////////////
//RApaLsSession
////////////////////////////////////

EXPORT_C RApaLsSession::RApaLsSession()
	{}


EXPORT_C TInt RApaLsSession::Connect()
// Connect to the server - default number of message slots = 4
	{
//	TInt r=StartThread();
	TInt r=CreateSession(KAppListServerName,Version(),KDefaultMessageSlots);
	return(r); 
	}

	
EXPORT_C TVersion RApaLsSession::Version(void) const
// Return the client side version number.
	{
	return(TVersion(KAppListServMajorVersionNumber,KAppListServMinorVersionNumber,KAppListServBuildVersionNumber));
	}


EXPORT_C TInt RApaLsSession::AppCount(TInt& aCount)
// returns the total number of apps in the server side list
	{
	return DoAppCount(aCount,EAppListServAppCount);
	}


EXPORT_C TInt RApaLsSession::EmbeddableAppCount(TInt& aCount)
// returns the number of embeddable apps in the server side list
	{
	return DoAppCount(aCount,EAppListServEmbedCount);
	}


TInt RApaLsSession::DoAppCount(TInt& aCount,TInt aCommand)
// returns the number of embeddable apps in the server side list
	{
	__ASSERT_DEBUG(aCommand==EAppListServEmbedCount || aCommand==EAppListServAppCount,Panic(EDPanicWrongCommand));
	//
	TAny *p[KMaxMessageArguments];
	TPckgBuf<TInt> pckg;
	p[0] = &pckg;
	TInt ret=SendReceiveWithReconnect(aCommand,&p[0]);
	if (ret==KErrNone)
		aCount = pckg();
	return ret;
	}


EXPORT_C TInt RApaLsSession::GetAllApps()
// call to initialize before calling GetNextApp(), returns err
	{
	return DoGetApps(EAppListServInitFullList);
	}


EXPORT_C TInt RApaLsSession::GetEmbeddableApps()
// call to initialize before calling GetNextApp(), returns err
	{
	return DoGetApps(EAppListServInitEmbedList);
	}


TInt RApaLsSession::DoGetApps(TInt aCommand)
// call to initialize before calling GetNextApp(), returns err
	{
	__ASSERT_DEBUG(aCommand==EAppListServInitFullList || aCommand==EAppListServInitEmbedList,Panic(EDPanicWrongCommand));
	//
	TAny *p[KMaxMessageArguments];
	return SendReceiveWithReconnect(aCommand,&p[0]);
	}


EXPORT_C TInt RApaLsSession::GetNextApp(TApaAppInfo& aInfo)
// Call repeatedly to get each embeddable app in the server side list, one at a time
// returns an error value which may be KErr* or ENoMoreAppsInList, EAppListInvalid
	{
	TPckgBuf<TApaAppInfo> infoPk;
	TAny* p[KMaxMessageArguments];
	p[0] = &infoPk;
	TInt ret=SendReceiveWithReconnect(EAppListServGetNextApp,&p[0]);
	if (ret==KErrNone)
		aInfo = infoPk();
	else if (ret==KErrNotFound)
		ret = ENoMoreAppsInList;
	else if (ret==KErrCorrupt)
		ret = EAppListInvalid;
	return ret;
	}


EXPORT_C TInt RApaLsSession::GetAppInfo(TApaAppInfo& aInfo,TUid aAppUid)
	{
	TPckgBuf<TApaAppInfo> pckg;
	TAny* p[KMaxMessageArguments];
	p[0] = &pckg;
	p[1] = (TAny*)aAppUid.iUid;
	TInt ret=SendReceiveWithReconnect(EAppListServGetAppInfo,&p[0]);
	if (ret==KErrNone)
		aInfo = pckg();
	return ret;
	}


EXPORT_C TInt RApaLsSession::GetAppCapability(TDes8& aCapabilityBuf,TUid aAppUid)
	{
	TAny* p[KMaxMessageArguments];
	p[0] = &aCapabilityBuf;
	p[1] = (TAny*)aAppUid.iUid;
	return SendReceiveWithReconnect(EAppListServGetAppCapability,&p[0]);
	}

EXPORT_C TInt RApaLsSession::StartApp(const CApaCommandLine& aCommandLine)
	{
	TAny* p[KMaxMessageArguments];
	TPtrC cmdLine=aCommandLine.FullCommandLine();
	p[0] = &cmdLine;
	return SendReceiveWithReconnect(EAppListServStartApp,&p[0]);
	}

EXPORT_C TInt RApaLsSession::RecognizeData(const TDesC& aName, const TDesC8& aBuffer, TDataRecognitionResult& aDataType)
	{
	const TAny* p[KMaxMessageArguments];
	p[0]=&aName;
	p[1]=&aBuffer;
	TPckgBuf<TDataRecognitionResult> dataPk;
	p[2]=&dataPk;
	TInt err=SendReceiveWithReconnect(EAppListServRecognizeData,&p[0]);
	if (err==KErrNone)
		aDataType=dataPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::RecognizeSpecificData(const TDesC& aName, const TDesC8& aBuffer, const TDataType& aDataType, TBool& aResult)
	{
	const TAny* p[KMaxMessageArguments];
	p[0]=&aName;
	p[1]=&aBuffer;
	TPtrC8 dataDes=aDataType.Des8();
	p[2]=&dataDes;
	TPckgBuf<TBool> boolPk;
	p[3]=&boolPk;
	TInt err=SendReceiveWithReconnect(EAppListServRecognizeSpecificData,&p[0]);
	if (err==KErrNone)
		aResult=boolPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::AppForDataType(const TDataType& aDataType, TUid& aAppUid)
	{
	const TAny* p[KMaxMessageArguments];
	TPtrC8 dataDes=aDataType.Des8();
	p[0]=&dataDes;
	TPckgBuf<TUid> uidPk;
	p[1]=&uidPk;
	TInt err=SendReceiveWithReconnect(EAppListServAppForDataType,&p[0]);
	if (err==KErrNone)
		aAppUid=uidPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::StartDocument(const TDesC& aFileName, TThreadId& aId, TLaunchType /*aLaunchType*/)
	{
	// !! TODO launch type
	const TAny* p[KMaxMessageArguments];
	p[0]=&aFileName;
	TPckgBuf<TThreadId> idPk;
	p[1]=&idPk;
	TInt err=SendReceiveWithReconnect(EAppListServStartDocument,&p[0]);
	if (err==KErrNone)
		aId=idPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::StartDocument(const TDesC& aFileName, const TDataType& aDataType, TThreadId& aId, TLaunchType /*aLaunchType*/)
	{
	// !! TODO launch type
	const TAny* p[KMaxMessageArguments];
	p[0]=&aFileName;
	TPtrC8 dataDes=aDataType.Des8();
	p[1]=&dataDes;
	TPckgBuf<TThreadId> idPk;
	p[2]=&idPk;
	TInt err=SendReceiveWithReconnect(EAppListServStartDocumentByDataType,&p[0]);
	if (err==KErrNone)
		aId=idPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::StartDocument(const TDesC& aFileName, TUid aAppUid, TThreadId& aId, TLaunchType aLaunchType)
	{
	return StartAndCreate(EAppListServStartDocumentByUid,aFileName,aAppUid,aId,aLaunchType);
	}

EXPORT_C TInt RApaLsSession::CreateDocument(const TDesC& aFileName, TUid aAppUid, TThreadId& aId, TLaunchType aLaunchType)
	{
	return StartAndCreate(EAppListServCreateDocumentByUid,aFileName,aAppUid,aId,aLaunchType);
	}

TInt RApaLsSession::StartAndCreate(TInt aRqst,const TDesC& aFileName, TUid aAppUid, TThreadId& aId, TLaunchType /*aLaunchType*/)
	{
	// !! TODO Launch type
	const TAny* p[KMaxMessageArguments];
	p[0]=&aFileName;
	p[1]=REINTERPRET_CAST(TAny*,aAppUid.iUid);
	TPckgBuf<TThreadId> idPk;
	p[2]=&idPk;
	TInt err=SendReceiveWithReconnect(aRqst,&p[0]);
	if (err==KErrNone)
		aId=idPk();
	return err;
	}


EXPORT_C TInt RApaLsSession::GetAppIcon(TUid aAppUid, TInt aSize, CApaMaskedBitmap& aAppBitmap)
// gets the bitmap handles from the Server, forms these up into a CApaMaskedBitmap
	{
	__ASSERT_DEBUG(aSize>-1 && aSize<3, Panic(EDPanicBadIconSize));
	const TAny* p[KMaxMessageArguments];
	p[0]=REINTERPRET_CAST(TAny*,aAppUid.iUid);
	p[1]=REINTERPRET_CAST(TAny*,aSize);
	TPckgBuf<TInt> iconPk;
	p[2]=&iconPk;
	TPckgBuf<TInt> maskPk;
	p[3]=&maskPk;
	TInt err=SendReceiveWithReconnect(EAppListServAppIconByUid,&p[0]);
	if (err==KErrNone)
		{
		TInt handle=iconPk();
		aAppBitmap.Duplicate(handle);
		handle=maskPk();
		aAppBitmap.Mask()->Duplicate(handle);
		}
	return err;
	}

EXPORT_C TInt RApaLsSession::AppForDocument(const TDesC& aFileName, TUid& aUid, TDataType& aDataType)
	{
	const TAny* p[KMaxMessageArguments];
	p[0]=&aFileName;
	TPckgBuf<TUid> uidPk;
	p[1]=&uidPk;
	TPckgBuf<TDataType> dataPk;
	p[2]=&dataPk;
	TInt err=SendReceiveWithReconnect(EAppListServAppForDocument,&p[0]);
	if (err==KErrNone)
		{
		aUid=uidPk();
		aDataType=dataPk();
		}
	return err;
	}

EXPORT_C TInt RApaLsSession::IsProgram(const TDesC& aFileName, TBool& aProgram)
	{
	const TAny* p[KMaxMessageArguments];
	p[0]=&aFileName;
	TPckgBuf<TBool> progPk;
	p[1]=&progPk;
	TInt err=SendReceiveWithReconnect(EAppListServIsProgram,&p[0]);
	if (err==KErrNone)
		aProgram=progPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::GetAcceptedConfidence(TInt& aConfidence)
	{
	const TAny* p[KMaxMessageArguments];
	TPckgBuf<TInt> confPk;
	p[0]=&confPk;
	TInt err=SendReceiveWithReconnect(EAppListServGetConfidence,&p[0]);
	if (err==KErrNone)
		aConfidence=confPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::SetAcceptedConfidence(TInt aConfidence)
	{
	const TAny* p[KMaxMessageArguments];
	p[0]=REINTERPRET_CAST(TAny*,aConfidence);
	return SendReceiveWithReconnect(EAppListServSetConfidence,&p[0]);
	}

EXPORT_C TInt RApaLsSession::GetMaxDataBufSize(TInt& aBufSize)
	{
	const TAny* p[KMaxMessageArguments];
	TPckgBuf<TInt> bufPk;
	p[0]=&bufPk;
	TInt err=SendReceiveWithReconnect(EAppListServGetBufSize,&p[0]);
	if (err==KErrNone)
		aBufSize=bufPk();
	return err;
	}

EXPORT_C TInt RApaLsSession::SetMaxDataBufSize(TInt aBufSize)
	{
	const TAny* p[KMaxMessageArguments];
	p[0]=REINTERPRET_CAST(TAny*,aBufSize);
	return SendReceiveWithReconnect(EAppListServSetBufSize,&p[0]);
	}

EXPORT_C TInt RApaLsSession::GetSupportedDataTypesL(CDataTypeArray& aDataTypes)
	{
	const TAny* p[KMaxMessageArguments];
	TPckgBuf<TInt> countPk;
	p[0]=&countPk;
	TInt err=SendReceiveWithReconnect(EAppListServGetDataTypesPhase1,&p[0]);
	if (err==KErrNone)
		{
		TInt count=countPk();
		CBufFlat* buf=CBufFlat::NewL(count);
		CleanupStack::PushL(buf);
		buf->ExpandL(0,count);
		TPtr8 ptr=buf->Ptr(0);
		p[0]=&ptr;
		err=SendReceiveWithReconnect(EAppListServGetDataTypesPhase2,&p[0]);
		if (err==KErrNone)
			{
			RBufReadStream readStream(*buf);
			readStream >> aDataTypes;
			}
		CleanupStack::PopAndDestroy(); // buf
		}
	return err;
	}

TInt RApaLsSession::SendReceiveWithReconnect(TInt aFunction, TAny* aPtr)
	{
	TBool done=EFalse;
	retry:
	TInt ret=ReconnectToServer(SendReceive(aFunction,aPtr),done);
	if ((ret==KErrServerTerminated && !done) || (ret==KErrNone && done))
		goto retry;
	return ret;
	}

TInt RApaLsSession::ReconnectToServer(TInt aErr, TBool& aTriedOnce)
// Sneaky function
// If a call to the server fails because the server has disconnected this
// attempts a reconnection to the server, the call is then sucessful it alters
// the current connection to point to the new connection
	{
	if (aTriedOnce)
		{
		if (aErr==KErrNone)
			aTriedOnce=EFalse;
		return aErr;
		}
	if (aErr!=KErrServerTerminated)
		return aErr;
	RApaLsSession ls;
	TInt err=ls.Connect();
	if (err==KErrNone)
		{
		Close();
		iHandle=ls.iHandle;
		}
	aTriedOnce=ETrue;
	return err;
	}