// Copyright (c) 2001-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 "CSimPhone.h"
#include "CSimVoiceCall.h"
#include "Simlog.h"
#include "et_struct.h"

_LIT(KCommonCallName,"VoiceCall%d");	// < Voice call name template.
const TInt KVoiceCallGranularity=2;		// < Granularity of voice call list array.

/**
* @file
*
* This file contains the implementation of the Similator TSY Voice line functionality.  
* The line classes process the line-based requests made by ETel clients 
* and passed down to the TSY by the ETel Server.
*/

CSimVoiceLine* CSimVoiceLine::NewL(CSimPhone* aPhone,const TDesC& aName)
/**
* Standard two phase constructor.
*
* @param aPhone pointer to the phone object.
* @param aName name of the line to be constructed
* @return CSimVoiceLine  pointer to the voice line object created
* @leave Leaves if no memory or object is not created for any reason
*/
	{
	CSimVoiceLine* voiceLine=new(ELeave) CSimVoiceLine(aPhone);
	TCleanupItem newLineVoiceClose(CloseLine,voiceLine);
	CleanupStack::PushL(newLineVoiceClose);
	voiceLine->ConstructL(aName);
	CleanupStack::Pop();
	return voiceLine;
	}

CSimVoiceLine::CSimVoiceLine(CSimPhone* aPhone)
	:CSimLine(aPhone)
/**
*	Trivial constructor. Calls CSimLine to initialise its members
*/
	{
	iICProperty.iCategory = KUidPSSimTsyCategory;
	iICProperty.iKey = KPSSimTsyIncomingVoiceCall;
	iICProperty.iType = KPSSimTsyIncomingVoiceCallKeyType;

	iRHProperty.iCategory = KUidPSSimTsyCategory;
	iRHProperty.iKey = KPSSimTsyRemoteHangup;
	iRHProperty.iType = KPSSimTsyRemoteHangupKeyType;
	}

void CSimVoiceLine::ConstructL(const TName& aName)
/**
* Pre-allocate a pool of voice calls and allocate one to be the default to
* contain information about an incoming call.
*
* @param aName name of the voice line to be constructed
*/
	{
	iCaps=Caps();
	CSimLine::ConstructL(aName);
	iCalls=new(ELeave) CArrayFixFlat<CSimCall*>(KVoiceCallGranularity);
	TName callName;
	iSpareCall=CreateNewCallL(callName,ECallTypeSpareCall);
	iAnswerNextIncomingCall=iSpareCall;
	}

CSimVoiceLine::~CSimVoiceLine()
/**
* Destroy the spare call - all the others will be closed by the client (or server).
*/
	{
	if ((iAnswerNextIncomingCall!=iSpareCall) && (iAnswerNextIncomingCall))
		{
		iAnswerNextIncomingCall->Close();
		}
	if(iSpareCall)
		{
		iSpareCall->Close();
		}
	if(iCalls)
		{
		iCalls->Delete(0,iCalls->Count());
		delete iCalls;
		}
	}

CTelObject* CSimVoiceLine::OpenNewObjectByNameL(const TDesC& aName)
/**
* Opens a voice call by name. 
* This will be called if the user opens a pre-alloc'ed call by name.
*
* @param aName name of call to be opened
* @return CTelObject pointer to the object opened by name
* @leave Leaves if name given does not match the required name
*/
	{
	LOGVOICE1(">>CSimVoiceLine::OpenNewObjectByNameL");
	TInt i;
	TInt count=iCalls->Count();

	for(i=0;i<count;i++)
		{
		LOGVOICE2(">>CSimVoiceLine::OpenNewObjectByNameL %s",&(iCalls->At(i)->iName));
		if(iCalls->At(i)->iName.MatchF(aName)==0)
			{
			iCalls->At(i)->Open();			
			return iCalls->At(i);
			}
		}

	LOGVOICE1("<<CSimVoiceLine::OpenNewObjectByNameL");
	User::Leave(KErrNotFound);
	return NULL;
	}

CTelObject* CSimVoiceLine::OpenNewObjectL(TDes& aNewName)
/**
* Open a voice call and return a name. 
* This function creates a new call object and returns its pointer.
*
* @param aNewName name of call to be opened
* @return CTelObject pointer to the object allocated
* @leave Leaves if no memory available
*/
	{
	return CreateNewCallL(aNewName,ECallTypeNormalCall);
	}

CSimCall* CSimVoiceLine::CreateNewCallL(TDes& aNewName,TCallType aCallType)
	{
	aNewName.Format(KCommonCallName,iCallCnt++);
	CSimVoiceCall* newCall=CSimVoiceCall::NewL(this,aNewName,iPhone);	
	CleanupStack::PushL(newCall);
	iCalls->AppendL(newCall);
	if(aCallType!=ECallTypeSpareCall)
		{
		HandleNewCallAddedNotification(aNewName);
		}
	LOGVOICE2(">>CSimVoiceLine::CreateNewCallL 0x%08x",newCall);
	CleanupStack::Pop(newCall);
	return newCall;
	}

TInt CSimVoiceLine::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc,const TDataPackage& aPackage)
/**
* ExtFunc is called by the server when it has a "extended", i.e. non-core ETel request 
* for the TSY to process
* A request handle, request type and request data are passed to the TSY
*
* @param aTsyReqHandle
* @param aIpc IPc number representing the request
* @param aPackage data for the request
* @return KErrNone
*/
	{

	TAny* dataPtr=aPackage.Ptr1();

	// The request data has to extracted from TDataPackage and the TAny* pointers have to
	// be "cast" to the expected request data type

	switch (aIpc)
		{
//
// No Flow Control OR Multiple Completion
//
	case EMobileLineGetMobileLineStatus:
		return GetMobileLineStatus(aTsyReqHandle,
			REINTERPRET_CAST(RMobileCall::TMobileCallStatus*,dataPtr));

//
// Multiple Completion Services with Immediate Server Repost
// (Usually Notifications)
//
	case EMobileLineNotifyMobileLineStatusChange:
		return NotifyMobileLineStatusChange(aTsyReqHandle,
			REINTERPRET_CAST(RMobileCall::TMobileCallStatus*, dataPtr));

	default:
		return KErrNotSupported;
		}
	}

TInt CSimVoiceLine::CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle)
/**
 * Cancel an outstanding request.
 * @param aIpc The IPC number of the request that must be cancelled.  Note: this is not the
 *             IPC number of the cancel request itself.
 * @param aTsyReqHandle The TSY Request Handle of the request to be cancelled.
 */
	{
	switch(aIpc)
		{
	case EEtelLineNotifyStatusChange:
		// Always returns KErrNone
		(void)NotifyStatusChangeCancel(aTsyReqHandle);
		return KErrNone;

	case EEtelLineNotifyIncomingCall:
		// Always returns KErrNone
		(void)NotifyIncomingCallCancel(aTsyReqHandle);
		return KErrNone;

	case EEtelLineNotifyHookChange:
		// Always returns KErrNone
		(void)NotifyHookChangeCancel(aTsyReqHandle);
		return KErrNone;

	case EEtelLineNotifyCallAdded:
		// Always returns KErrNone
		(void)NotifyCallAddedCancel(aTsyReqHandle);
		return KErrNone;

	case EMobileLineNotifyMobileLineStatusChange:
		// Always returns KErrNone
		(void)NotifyMobileLineStatusChangeCancel(aTsyReqHandle);
		return KErrNone;

	default:
		break;
		}

	return CLineBase::CancelService(aIpc,aTsyReqHandle);
	}

TInt CSimVoiceLine::EnumerateCall(const TTsyReqHandle aTsyReqHandle,TInt* aParams)
/**
* Count and return the number of voice calls used.
*
* @param aTsyReqHandle
* @return KErrNone
* @param aParams pointer to the number of calls used
*/
	{
	*aParams=iCalls->Count();
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimVoiceLine::GetCallInfo(const TTsyReqHandle aTsyReqHandle,TCallInfoIndex* aCallInfoIndex)
/**
* Retrieve the Call Information relevant to the numbered call.
* Returns the name, the current call status and the call capabilities
* TCallInfoIndex specifies which call info is requested.
*
* @param aTsyReqHandle
* @param aCallInfoIndex pointer to the call info
* @return KErrNone
*/
	{
	TInt& i=aCallInfoIndex->iIndex;
	aCallInfoIndex->iInfo.iCallName.Copy(iCalls->At(i)->iName);
	aCallInfoIndex->iInfo.iStatus=(RCall::TStatus)iCalls->At(i)->iState;
	aCallInfoIndex->iInfo.iCallCapsFlags=iCalls->At(i)->Caps();
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimVoiceLine::FindActiveVoiceCall(CSimVoiceCall*& aCall)
/**
 * Find an active voice call.  Return KErrNotFound if no voice calls active.
 * @param aCall		Pointer to active voice call.
 * @return TInt		Standard return error.
 */
	{
	TInt i;
	for(i=0;i<iCalls->Count();i++)
		{
		if(iCalls->At(i)->iState==RMobileCall::EStatusConnected)
			{
			aCall=(CSimVoiceCall*)iCalls->At(i);
			return KErrNone;
			}
		}
	return KErrNotFound;
	}

TInt CSimVoiceLine::FindActiveCall(CSimCall*& aCall)
/**
 * Find an active voice call.  Return KErrNotFound if no voice calls active.
 * @param aCall		Pointer to active voice call.
 * @return TInt		Standard return error.
 */
	{
	TInt i;
	for(i=0;i<iCalls->Count();i++)
		{
		if(iCalls->At(i)->iState==RMobileCall::EStatusConnected)
			{
			aCall=(CSimVoiceCall*)iCalls->At(i);
			return KErrNone;
			}
		}
	return KErrNotFound;
	}

TUint CSimVoiceLine::Caps()
/**
 * Return the current capabilities of this line.
 * @return TUint	Current line capabilities.
 */
	{
	TUint caps=RLine::KCapsVoice;
	if(iState==RMobileCall::EStatusIdle)
		caps|=RLine::KCapsEventIncomingCall;
	return caps;
	}
