// ET_PHONE.H
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#ifndef __ET_PHONE_H
#define __ET_PHONE_H

#include "ETEL.H"
#include "ET_TSY.H"

//
// The request with this handle should not be completed by TSY
//
#define TSY_HANDLE_INIT_VALUE (0)

//
// CReqEntry class
//
class CTelSession;
class CTelObject;
class CValue;
class CReqEntry : public CBase
	{
friend class CPhoneBase;
public:
	static CReqEntry* NewL(TTsyReqHandle aTsyReqHandle,const RMessage& aMessage,CTelSession* aSession,CValue* aValue,const CTelObject* aTelObject,TInt aFunction,RHeap* aHeap);
	CReqEntry(TTsyReqHandle aTsyReqHandle,const RMessage& aMessage,CTelSession* aSession,CValue* aValue,const CTelObject* aTelObject,TInt aFunction,RHeap* aHeap);
	~CReqEntry();
	void Deque();
	void CompleteAndDeque(TInt aError);
//
	static TAny* operator new(TUint aSize);
	static TAny* operator new(TUint aSize,TLeave aLeave);
	static TAny* operator new(TUint aSize,TUint anExtraSize);
	static TAny* operator new(TUint aSize,RHeap* aHeap);
	static void operator delete(TAny* aPtr);

public:
	TTsyReqHandle iTsyReqHandle;
	RMessage iMessage;
	CTelSession* iSession;
	const CTelObject* iTelObject;
	TBool iClientInterested;
	TBool iCancelFnCalled;
	TInt iFunction;
	CValue* iValue;
	TBool iReadByClient;
	TBool iMessageNulled;
	TBool iHasBeenRegistered;
	TBool iPlacedRequest;
	MTelObjectTSY::TReqMode iReqMode;
private:
	TDblQueLink iLink;
public:
	RHeap* iHeap;
	};

//
// CValue class
//
class HEtelBufC8;
class CValue : public CBase
	{
public:
	enum TWhichSlot
		{
		ESlotRead,
		ESlotWrite
		};

	static CValue* NewL(HEtelBufC8* aBuf,RHeap* aHeap);
	CValue(HEtelBufC8* aBuf,RHeap* aHeap);
	~CValue();
	virtual TBool OverFlow() const;
	virtual TBool BufferFull() const;
	virtual TUint8* CurrentSlotData1(TWhichSlot aWhichSlot) const;
	virtual TUint8* CurrentSlotData2(TWhichSlot aWhichSlot) const;
	virtual void IncRead();
	virtual void IncWrite();
	virtual TInt CompareRWPtrs() const;
//
	static TAny* operator new(TUint aSize);
	static TAny* operator new(TUint aSize,TLeave aLeave);
	static TAny* operator new(TUint aSize,TUint anExtraSize);
	static TAny* operator new(TUint aSize,RHeap* aHeap);
	static void operator delete(TAny* aPtr);

public:
	RHeap* iHeap;
	HEtelBufC8* iBuf;
	};

class CBuffer : public CValue
	{
public:
	static CBuffer* NewL(HEtelBufC8* aBuf,RHeap* aHeap,TInt aSizeOfData1,TInt aSizeOfData2,TInt aNoOfSlots);
	CBuffer(HEtelBufC8* aBuf,RHeap* aHeap,TInt aSizeOfData1,TInt aSizeOfData2,TInt aNoOfSlots);
	~CBuffer();
	virtual TBool OverFlow() const;
	virtual TBool BufferFull() const;
	virtual TUint8* CurrentSlotData1(TWhichSlot aWhichSlot) const;
	virtual TUint8* CurrentSlotData2(TWhichSlot aWhichSlot) const;
	virtual void IncRead();
	virtual void IncWrite();
	virtual TInt CompareRWPtrs() const;
private:
	TInt iRead;
	TInt iWrite;
	TInt iNoOfSlots;
	TInt iSizeOfData1;
	TInt iSizeOfData2;
	TBool iOverFlow;
	TBool iBufferFull;
	};

const TInt KDeltaTimerInterval=100000;
const TInt KPhoneTimerPriority=50;

//
//	CTelObject
//
class CDestroyDummySubSession;
class CTelServer;
class CPhoneBase;
class CPhoneManager;
class CTelObject : public CObject, public MTelObjectTSY
	{
public:
	IMPORT_C CTelObject();
	IMPORT_C virtual ~CTelObject();
	IMPORT_C virtual void ReqCompleted(const TTsyReqHandle aTsyReqHandle,const TInt aError);
	IMPORT_C virtual void FlowControlSuspend();
	IMPORT_C virtual void FlowControlResume();
	IMPORT_C virtual TInt GetExtraOption(const TInt aOptionNumber, TDes8& aDes);
	IMPORT_C virtual TInt SetExtraOption(const TInt aOptionNumber, const TDesC8& aDes);
	IMPORT_C virtual TInt ServerVersion() const;

	CPhoneBase* PhoneOwner() const;
	void SetPhoneOwner(CPhoneBase* aPhoneOwner);
	void FlushReqs(CTelSession* aSession,const TInt aSubSessionHandle);
	void GeneralReq(const RMessage& aMessage,CTelSession* aSession,CReqEntry* aNewReqEntry);
	void TelObjectClose();
	TDes8* Des1(const HEtelBufC8* aBuf) const;
	TDes8* Des2(const HEtelBufC8* aBuf) const;
	TDes8* BufferDes1(const CValue* aValue,CValue::TWhichSlot aWhichSlot) const;
	TDes8* BufferDes2(const CValue* aValue,CValue::TWhichSlot aWhichSlot) const;
	TUint8* Ptr1(const TDes8* aDes1) const;
	void WriteBackAndCompleteBufferedReq(const RMessage& aMessage,CReqEntry* aReqEntry,TInt aError) const;
	void WriteBackAndCompleteReq(CReqEntry* aReqEntry,const TInt aError) const;
	void UpdateAndCompleteIfNecessary(CReqEntry* aReqEntry,TInt aError) const;
	void CancelSubSession(CTelSession* aSession,const TInt aSubSessionHandle);
	void CreateDummySession(CTelSession* aSession,const TInt aSubSessionHandle, TBool aCreateDummy=EFalse);
	void CheckAndDestroyDummySubSession();
	void RemoveDummySubSessionDestroyer();
//
// Pure Virtual
//
	virtual void OpenPostProcessing(CTelSession* aSession,const TInt aSubSessionHandle)=0;
	virtual void CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle)=0;
	virtual TInt Service(const RMessage& aMessage,CReqEntry* aReqEntry)=0;
protected:
	TBool IsPriorityClientReq(TInt aReq) const;
private:
	void CompleteAndDestroyReq(CReqEntry* aReqEntry,const TInt aStatus) const;
	void DestroyReq(CReqEntry* aReqEntry) const;
	CReqEntry* ReqAnalyserL(const RMessage& aMessage,CTelSession* aSession,TReqMode& aReqMode);
	CReqEntry* CheckForSimilarRequestAndCreateL(const RMessage& aMessage,CTelSession* aSession) const;
	void CompleteOrBufferRead(const RMessage& aMessage,CReqEntry* aReqEntry);
	TBool IsActiveReq(CTelSession* aSession,const TInt aSubSessionHandle);
	void CancelActiveReq(CTelSession* aSession,const TInt aSubSessionHandle);
	void ResetBooleans(TDes8* aBuf,const TInt aIpc) const;
	void CheckAndResize(TInt& aSizeOfData,const RMessage& aMessage) const;
	CBuffer* CreateRegisteredEntryL(HEtelBufC8* aBuf,const RMessage& aMessage,RTelSubSessionBase::TRegisterInfo& aInfo);
private:// data
	CPhoneBase* iPhoneOwner;
	CPhoneManager* iPhoneManager;
	TInt iActiveReqCount;
	CTelServer* iTelServer;
	CDestroyDummySubSession* iDestroyDummySubSession;
	TBool iCreateDummy;
	};

//
// CSubSessionExtBase
//
class CSubSessionExtBase : public CTelObject, public MSubSessionExtBaseTSY
	{
public:
	IMPORT_C CSubSessionExtBase();
	IMPORT_C virtual ~CSubSessionExtBase();
	TInt ServiceExtFunc(const RMessage& aMessage,CReqEntry* aReqEntry);
protected:
	IMPORT_C virtual TInt Service(const RMessage& aMessage,CReqEntry* aReqEntry);
	IMPORT_C virtual void OpenPostProcessing(CTelSession*,const TInt);
	IMPORT_C virtual void CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle);
	IMPORT_C virtual const CArrayFixFlat<TInt>* ArrayOfMemberDataSizes(const TInt aIpc) const;
private:
	inline void Inc();
	};

//
// CFaxBase Object
//
class CFaxBase : public CTelObject, public MFaxBaseTSY
	{
public:;
	IMPORT_C CFaxBase();
	IMPORT_C virtual ~CFaxBase();
	IMPORT_C virtual TReqMode ReqModeL(const TInt aIpc);
	IMPORT_C virtual TInt CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle);
//
// Pure Virtual
//
private:
	IMPORT_C virtual CTelObject* OpenNewObjectByNameL(const TDesC& aName);
	IMPORT_C virtual CTelObject* OpenNewObjectL(TDes& aName);
	IMPORT_C virtual TInt Service(const RMessage& aMessage,CReqEntry* aReqEntry);
	IMPORT_C virtual void OpenPostProcessing(CTelSession*,const TInt);
	IMPORT_C virtual void CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle);
	IMPORT_C virtual void Init();
	IMPORT_C virtual const CArrayFixFlat<TInt>* ArrayOfMemberDataSizes(const TInt aIpc) const;
	};

//
// CCallBase
//
class CCallBase : public CSubSessionExtBase, public MCallBaseTSY
	{
public:
	IMPORT_C CCallBase();
	IMPORT_C virtual ~CCallBase();


	IMPORT_C TCallOwnership CheckOwnership(const TTsyReqHandle aTsyReqHandle) const;
	IMPORT_C TInt SetUnowned();
	IMPORT_C TInt SetOwnership(const TTsyReqHandle aTsyReqHandle);
	IMPORT_C TBool CheckPriorityClient(const TTsyReqHandle aTsyReqHandle) const;
	IMPORT_C CCallBase* ResolveSubSessionHandle(const TTsyReqHandle aTsyReqHandle,const TInt aSubSessionHandle);
	IMPORT_C void RelinquishOwnershipCompleted(const TInt aError);
	IMPORT_C void RecoverDataPortAndRelinquishOwnershipCompleted(const TInt aError);
	IMPORT_C RFax::TProgress* CreateFaxProgressChunk();
	IMPORT_C void DeleteFaxProgressChunk();
	IMPORT_C virtual TReqMode ReqModeL(const TInt aIpc);
	IMPORT_C virtual TInt CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle);
private:
	IMPORT_C RCall::TOwnershipStatus CheckOwnershipBySession(CTelSession* aSession,const TInt aSubSession) const;
	IMPORT_C virtual TInt Service(const RMessage& aMessage,CReqEntry* aReqEntry);
	IMPORT_C virtual void Init();
	IMPORT_C virtual void OpenPostProcessing(CTelSession*,const TInt);
	IMPORT_C virtual void CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle);
	TCallOwnership iOwnershipStatus;
	CTelSession* iOwnerSession;
	TInt iOwnerSubSessionHandle;
	TBool iLoanDataPort;
	RChunk iChunk;
	};

//
// CLineBase object
//
class CCallBase;
class CLineBase : public CSubSessionExtBase, public MLineBaseTSY
	{
public:;
	IMPORT_C CLineBase();
	IMPORT_C virtual ~CLineBase();
	IMPORT_C virtual TReqMode ReqModeL(const TInt aIpc);
	IMPORT_C virtual TInt CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle);
private:
	IMPORT_C virtual TInt Service(const RMessage& aMessage,CReqEntry* aReqEntry);
	IMPORT_C virtual void Init();
	IMPORT_C virtual void OpenPostProcessing(CTelSession*,const TInt);
	IMPORT_C virtual void CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle);
	
	};

//
// CPhoneBase object
//
class CPhoneBase : public CSubSessionExtBase, public MPhoneBaseTSY
	{
public:
	IMPORT_C CPhoneBase();
	IMPORT_C virtual ~CPhoneBase();
	IMPORT_C virtual TReqMode ReqModeL(const TInt aIpc);
	IMPORT_C virtual TInt CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle);
	
	void FlowControlInc();
	void FlowControlDec();
	TInt FlowControl() const;
	CReqEntry* ActivateNextWaitingReq();
	CReqEntry* FindByTsyHandle(const TTsyReqHandle aTsyReqHandle);
	CReqEntry* FindByTsyHandleAndPlacedRequest(const TTsyReqHandle aTsyReqHandle);
	void UpdateBuffer(CReqEntry* aUpdatedReqEntry,CReqEntry* aReqEntry);
	CReqEntry* FindClientInWaiting(CTelSession* aSession,const TInt aSubSessionHandle,const TInt aIpc);
	CReqEntry* FindClientInActive(CTelSession* aSession,const TInt aSubSessionHandle,const TInt aIpc);
	CReqEntry* FindByIpc(const TInt aIpc);
	CReqEntry* FindByIpcAndTelObject(const TInt aIpc, const CTelObject* aTelObject);
	TInt CountTsyHandleHits(const TTsyReqHandle aTsyReqHandle);
	void AddReqToActive(CReqEntry* aReqEntry);
	void AddReqToWaiting(CReqEntry* aReqEntry);
	CReqEntry* NewReqL(const RMessage& aMessage,CTelSession* aSession,CValue* aValue,const CTelObject* aTelObject,TInt aFunction);
	CReqEntry* FindSameClientEntry(CTelSession* aSession,const TInt aSubSessionHandle,const TInt aIpc);
	CReqEntry* FindClientReqInWaitList(CTelSession* aSession,const TInt aSubSessionHandle);
	CReqEntry* FindThisReqByAnotherClient(CTelSession* aSession,const TInt aSubSessionHandle,const TInt aIpc,const CTelObject* aThisTelObject);
	CReqEntry* FindThisHandleByAnotherClient(CTelSession* aSession,const TInt aSubSessionHandle,const TTsyReqHandle aTsyReqHandle);
	CReqEntry* FindNonCancelledClientReq(CTelSession* aSession,const TInt aSubSessionHandle,const TInt aIpc);
	void CheckAndCompleteAllActive(CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aIpc,const TInt aError);
	TDblQue<CReqEntry>& ReqActiveList();
private:
 	IMPORT_C virtual TInt Service(const RMessage& aMessage,CReqEntry* aReqEntry);
	IMPORT_C virtual void OpenPostProcessing(CTelSession* aSession,const TInt aSubSessionHandle);
	IMPORT_C virtual void CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle);
	
	TTsyReqHandle TsyReqHandle();
	TInt iTsyReqHandleCnt;
	TInt iFlowControlCnt;
	TDblQue<CReqEntry> iReqWaitList;
	TDblQue<CReqEntry> iReqActiveList;
	};

//
// CLibUnloader class
//
class CPhoneFactoryBase;
class CLibUnloader : public CAsyncOneShot
	{
friend CPhoneFactoryBase;
public:
	static CLibUnloader* NewL(RLibrary &aLib);
	~CLibUnloader();
protected:
	CLibUnloader();
	virtual void RunL();
private:
	RLibrary iLib;
	};

//
// CPhoneBase factory object
//
class CPhoneFactoryBase : public CObject, public MPhoneFactoryBaseTSY
	{
public:
	IMPORT_C CPhoneFactoryBase();
	IMPORT_C virtual ~CPhoneFactoryBase();

	IMPORT_C virtual TBool QueryVersionSupported(TVersion const& aVersion) const;
	void ConstructL(RLibrary& aLib);
	inline void Inc();
protected:
	TVersion iVersion;
private:
	CLibUnloader* iLibUnloader;
	};

//
// HEtelBufC8 class - this is our version of HBufC8 which will allocate to the 
// priority client heap if aHeap is not NULL (i.e. this is a priority client 
// request)
//

class HEtelBufC8
	{
public:
	static HEtelBufC8* NewMaxLC(TInt aMaxLength,RHeap* aHeap);
	TPtr8 Des();
	const TUint8* Ptr() const;
	//
	static void operator delete(TAny* aPtr);
private:
	RHeap* iHeap;
	TInt iLength;
	};

#include "ET_PHONE.INL"

#endif
