/*
* Copyright (c) 2005-2010 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:  Implementation for CBTSAController class. This class is advertised
*				 to E-com framework (@see proxy.cpp) so that it loads this class when 
*				 this plugin gets loaded. That is why this class implements the interface
*				 of the module (currently BT Accessory Server) which loads this plugin.Being
*				 main class, this class constructs other classes and also recieves callbacks,
*				 hence implementing their interfaces.  
*
*/


// INCLUDE FILES
#include "btsaController.h"
#include "btsacactive.h"
#include "btsacStateIdle.h"
#include "btsacStateListening.h"
#include "btsacStreamerController.h"
#include "btsacSEPManager.h"
#include "btsacGavdp.h"
#include "debug.h"
#include <e32property.h>
#include "btaudioremconpskeys.h"

_LIT_SECURITY_POLICY_C1( KPSKeyReadPolicy, 
                         ECapabilityLocalServices);
_LIT_SECURITY_POLICY_C1( KPSKeyWritePolicy, 
                         ECapabilityLocalServices);

// CONSTANTS

// MODULE DATA STRUCTURES

// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// CBTSAController::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CBTSAController* CBTSAController::NewL(TPluginParams& aParams)
    {
    CBTSAController* self = new (ELeave) CBTSAController(aParams);
    CleanupStack::PushL(self);
    self->ConstructL(  );
    CleanupStack::Pop(self);
    return self;
    }

    
// -----------------------------------------------------------------------------
// Destructor.
// -----------------------------------------------------------------------------
//
CBTSAController::~CBTSAController()
    {
    TRACE_FUNC
    if(iStreamingSockets.Count())
		{
		TRACE_INFO((_L("[SOCKET] closed.")))
		iStreamingSockets[0].Close();
		}
	iStreamingSockets.Close();
	delete iStreamer;
    delete iGavdp;
    delete iState;
    delete iGavdpErrorActive;
    delete iLocalSEPs;
	delete iRemoteSEPs;
    iAccDb.ResetAndDestroy();
	iAccDb.Close();    
    RProperty::Delete( KBTAudioRemCon, KBTAudioPlayerControl );
    TRACE_INFO((_L("CBTSAController::~CBTSAController() completed")))
    }

// -----------------------------------------------------------------------------
// CBTSAController::CBTSAController
// C++ default constructor.
// -----------------------------------------------------------------------------
//
CBTSAController::CBTSAController(TPluginParams& aParams)
    : CBTAccPlugin(aParams)
    {
  	TRACE_FUNC
    }
    
    
// -----------------------------------------------------------------------------
// CBTSAController::ConstructL
// Symbian 2nd phase constructor.
// -----------------------------------------------------------------------------
//
void CBTSAController::ConstructL()
    {
    TRACE_FUNC_ENTRY
    CBtsacState* state = CBtsacIdle::NewL(*this);
    CleanupStack::PushL(state);
	iStreamer = CBTSACStreamerController::NewL(*this);
    // Initially idle state is registered as observer of GAVDP
    iGavdp = CBTSACGavdp::NewL(state); 
 	iLocalSEPs = CBTSACSEPManager::NewL(TBTDevAddr());
 	iGavdpErrorActive = CBtsacActive::NewL(*this, CActive::EPriorityStandard, KRequestIdGavdpError); 	
 	CleanupStack::Pop(state);
 	ChangeStateL(state);
    ResetRemoteCache();
    
    TInt err = RProperty::Define( KBTAudioRemCon, 
                       KBTAudioPlayerControl, RProperty::EInt, 
                       KPSKeyReadPolicy, 
                       KPSKeyWritePolicy );
    TRACE_INFO((_L("PS define err %d"), err))
	TRACE_FUNC_EXIT
    }

// -----------------------------------------------------------------------------
// CBTSAController::ChangeStateL
// -----------------------------------------------------------------------------
//  

void CBTSAController::ChangeStateL(CBtsacState* aState)
  {
  TRACE_FUNC_ENTRY
  TRACE_ASSERT(aState != NULL, EBTPanicNullPointer);
  if(iState && aState->GetStateIndex() == iState->GetStateIndex())
      {
      // We already are in desired state, delete the state which came in and return
      TRACE_INFO((_L("CBTSAController::ChangeStateL(), already in desired state.")))
      delete aState;
      return;
      }
  delete iState;
  iState = aState;
  TInt err = KErrNone;
  TRAP(err, iState->EnterL());
  if (err)
      {
      ChangeStateL(iState->ErrorOnEntryL(err));
      }
  TRACE_FUNC_EXIT
  }


// -----------------------------------------------------------------------------
// CBTSAController::ResetRemoteCache
// -----------------------------------------------------------------------------
//
void CBTSAController::ResetRemoteCache()
    {
	TRACE_FUNC
    }

// -----------------------------------------------------------------------------
// CBTSAController::InitializeSEPManager
// -----------------------------------------------------------------------------
//
void CBTSAController::InitializeSEPManager()
	{
    TRACE_FUNC
    iSBCSEPIndex = 0;   // SBC SEP Index in iRemoteSEPs array
    if( iRemoteSEPs )
    	{
    	delete iRemoteSEPs;
    	iRemoteSEPs = NULL;
    	}
	TRAPD(ret, iRemoteSEPs = CBTSACSEPManager::NewL(iRemoteAddr));
	if (ret)
		{
		TRACE_INFO((_L("CBTSAController::InitializeSEPManager(), ERROR")))
		}
	}

// -----------------------------------------------------------------------------
// CBTSAController::CleanSockets
// -----------------------------------------------------------------------------
//
void CBTSAController::CleanSockets()
	{
	TRACE_FUNC
	if(iStreamingSockets.Count())
		{
		// Close possible streaming socket(s)
		TRACE_INFO((_L("[SOCKET] closed.")))
		iStreamingSockets[0].Close();
		iStreamingSockets.Remove(0);
		iStreamingSockets.Reset();        
		}
	}

// -----------------------------------------------------------------------------
// CBTSAController::PluginType
// -----------------------------------------------------------------------------
//
TProfiles CBTSAController::PluginType()
	{
	TRACE_FUNC
	return EStereo;
	}

// -----------------------------------------------------------------------------
// CBTSAController::ConnectToAccessory
// -----------------------------------------------------------------------------
//
void CBTSAController::ConnectToAccessory(const TBTDevAddr& aAddr, TRequestStatus& aStatus)
	{
    TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); 
         Trace(_L("[REQUEST] Connect request, BT Addr %S"), &buf);})
    iConnectStatus = &aStatus;
	aStatus = KRequestPending;
    TRAPD(err, iState->ConnectL(aAddr));
    if (err)
        {
        CompletePendingRequests(KConnectReq, err);
        }
    TRACE_FUNC_EXIT
	}

// -----------------------------------------------------------------------------
// CBTSAController::CancelConnectToAccessory
// -----------------------------------------------------------------------------
//
void CBTSAController::CancelConnectToAccessory(const TBTDevAddr& aAddr)
	{
	TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); Trace(_L("BT Addr %S"), &buf);})
	if (aAddr != iRemoteAddr)
    	{
   	    TRACE_INFO((_L("CBTSAController::CancelConnectToAccessory() Invalid address, error.")))
   		CompletePendingRequests(KConnectReq, KErrArgument);
   		return;
    	}
    TRAP_IGNORE(iState->CancelConnectL());    
    TRACE_FUNC_EXIT
	}
	
// -----------------------------------------------------------------------------
// CBTSAController::DisconnectAccessory
// -----------------------------------------------------------------------------
//
void CBTSAController::DisconnectAccessory(const TBTDevAddr& aAddr, TRequestStatus& aStatus)
	{
    TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); 
         Trace(_L("[REQUEST] Disconnect request, BT Addr %S"), &buf);})
	
	// if we have an open/close audio request pending, complete it
	CompletePendingRequests((KOpenAudioReq | KCloseAudioReq), KErrDisconnected);
	iDisconnectStatus = &aStatus;
	aStatus = KRequestPending;
    if (aAddr != iRemoteAddr )
    	{
   	    TRACE_INFO((_L("CBTSAController::DisconnectAccessory() Invalid address, error.")))
   		CompletePendingRequests(KDisconnectReq, KErrArgument);
   		return;
    	}
    TRAPD(err, iState->DisconnectL());
    if (err)
        {
        CompletePendingRequests(KDisconnectReq, err);
        return;
        }
    SetResetAudioInput(ETrue);
    TRACE_FUNC_EXIT
	}
		
// -----------------------------------------------------------------------------
// CBTSAController::OpenAudioLink
// -----------------------------------------------------------------------------
//
void CBTSAController::OpenAudioLink(const TBTDevAddr& aAddr, TRequestStatus& aStatus)
	{
    TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); 
         Trace(_L("[REQUEST] Open audio request, BT Addr %S"), &buf);})
    iOpenAudioStatus = &aStatus;
	aStatus = KRequestPending;
    TRAPD(err, iState->OpenAudioLinkL(aAddr));
    if (err)
        {
        CompletePendingRequests(KOpenAudioReq, err);
        }
    TRACE_FUNC_EXIT 		
	}

// -----------------------------------------------------------------------------
// CBTSAController::CancelOpenAudioLink
// -----------------------------------------------------------------------------
//
void CBTSAController::CancelOpenAudioLink(const TBTDevAddr& aAddr)
    {
	TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); Trace(_L("BT Addr %S"), &buf);})
	if(aAddr != iRemoteAddr)
    	{
   	    TRACE_INFO((_L("CBTSAController::CancelOpenAudioLink() Invalid address, error.")))
   		CompletePendingRequests(KOpenAudioReq, KErrArgument);
   		return;
    	}
    if(IsOpenAudioReqFromAccFWPending())
	    {    	
	    TRAP_IGNORE(iState->CancelOpenAudioLinkL());
	    }
    TRACE_FUNC_EXIT
    }
	
// -----------------------------------------------------------------------------
// CBTSAController::CloseAudioLink
// -----------------------------------------------------------------------------
//
void CBTSAController::CloseAudioLink(const TBTDevAddr& aAddr, TRequestStatus& aStatus)
	{
    TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); 
         Trace(_L("[REQUEST] Close audio request, BT Addr %S"), &buf);})
	iCloseAudioStatus = &aStatus;
	aStatus = KRequestPending;
    TRAPD(err, iState->CloseAudioLinkL(aAddr));
    if (err)
        {
        CompletePendingRequests(KCloseAudioReq, err);
        }
    TRACE_FUNC_EXIT
	}

// -----------------------------------------------------------------------------
// CBTSAController::CancelCloseAudioLink
// -----------------------------------------------------------------------------
//
void CBTSAController::CancelCloseAudioLink(const TBTDevAddr& aAddr)
	{
    TRACE_FUNC_ENTRY
    TRACE_INFO_SEG(
        {TBuf<KBTDevAddrReadable> buf; aAddr.GetReadable(buf); Trace(_L("BT Addr %S"), &buf);})
	if(aAddr != iRemoteAddr)
    	{
   	    TRACE_INFO((_L("CBTSAController::CancelCloseAudioLink() Invalid address, error.")))
   		CompletePendingRequests(KCloseAudioReq, KErrArgument);
   		return;
    	}
    if(iCloseAudioStatus)
	    {    	
	    iState->CancelCloseAudioLink(aAddr);
	    }
    TRACE_FUNC_EXIT
	}

// -----------------------------------------------------------------------------
// CBTSAController::AccInUse
// -----------------------------------------------------------------------------
//
void CBTSAController::AccInUse()
	{
 	TRACE_FUNC
	}
	
// -----------------------------------------------------------------------------
// CBTSAController::StartRecording
// -----------------------------------------------------------------------------
//
void CBTSAController::StartRecording()
	{
 	TRACE_FUNC
	iState->StartRecording(); 
	}
	
// -----------------------------------------------------------------------------
// CBTSAController::StoreAccInfo
// -----------------------------------------------------------------------------
//
void CBTSAController::StoreAccInfo()
	{
    TRACE_FUNC
	iAccDb.Append(iRemoteSEPs);
	}

// -----------------------------------------------------------------------------
// CBTSAController::DeleteAccInfo
// -----------------------------------------------------------------------------
//
void CBTSAController::DeleteAccInfo()
	{
    TRACE_FUNC
    for(TInt i = 0 ; i < iAccDb.Count() ; i++)
    	{
    	iAccDb.Remove(i);
    	}
	iAccDb.Reset();
	}
	
// -----------------------------------------------------------------------------
// CBTSAController::IsAccInfoAvailable
// -----------------------------------------------------------------------------
//
TBool CBTSAController::IsAccInfoAvailable()
	{
	TRACE_INFO((_L("CBTSAController::IsAccInfoAvailable() Count: %d"), iAccDb.Count()))
	for (TInt i=0; i<iAccDb.Count(); i++)	
		{
		CBTSACSEPManager* SM = iAccDb[i];
		if ( SM->GetDeviceAddr() == iRemoteAddr )	
			{
			iRemoteSEPs = iAccDb[i];	// retrieve SEP Manager
			return ETrue; 
			}
		}
	return EFalse;
	}

// -----------------------------------------------------------------------------
// CBTSAController::AbortStream
// -----------------------------------------------------------------------------
//
TInt CBTSAController::AbortStream()
	{
	TRACE_FUNC
	TAvdtpSEPInfo SEPInfo;
	if (iRemoteSEPs->GetInfo(iSBCSEPIndex, SEPInfo))
		{
		TRACE_INFO((_L("CBTSAController::AbortStream() Couldn't retrieve SEP Info !")))
		return KErrGeneral;
      	}
	TSEID remoteSEPid = SEPInfo.SEID(); 	
	iGavdp->AbortStreaming(remoteSEPid);
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CBTSAController::NewAccessory
// -----------------------------------------------------------------------------
//
void CBTSAController::NewAccessory(const TBTDevAddr& aAddr)
	{
 	TRACE_FUNC
	TRACE_INFO((_L("\tiNotifiedObserverOfNewAccessory = %d"), iNotifiedObserverOfNewAccessory))
	if ( !iNotifiedObserverOfNewAccessory )
		{
	 	TInt connectedProfiles = Observer().ConnectionStatus( aAddr );
	 	if( !(connectedProfiles & EStereo) )
	 	    {
	 	    Observer().NewAccessory( aAddr, EStereo );
	 	    iNotifiedObserverOfNewAccessory = ETrue;
	 	    } 
		}
	}

// -----------------------------------------------------------------------------
// CBTSAController::DisconnectedFromRemote
// -----------------------------------------------------------------------------
//
void CBTSAController::DisconnectedFromRemote(const TBTDevAddr& aAddr, TInt /*aError*/)
	{
	TRACE_FUNC
	TRACE_INFO((_L("\tiNotifiedObserverOfNewAccessory = %d"), iNotifiedObserverOfNewAccessory))
	if ( iNotifiedObserverOfNewAccessory )
		{
		Observer().AccessoryDisconnected(aAddr, EStereo );
		iNotifiedObserverOfNewAccessory = EFalse;
		}
	}

// -----------------------------------------------------------------------------
// CBTSAController::AccessoryOpenedAudio
// -----------------------------------------------------------------------------
//
void CBTSAController::AccessoryOpenedAudio(const TBTDevAddr& aBDAddr)
	{
	TRACE_FUNC
	Observer().RemoteAudioOpened(aBDAddr, EStereo );
	}	


// -----------------------------------------------------------------------------
// CBTSAController::AccessoryClosedAudio
// -----------------------------------------------------------------------------
//		
void CBTSAController::AccessoryClosedAudio(const TBTDevAddr& aBDAddr)
	{
	TRACE_FUNC
	Observer().RemoteAudioClosed(aBDAddr, EStereo );
	}

// -----------------------------------------------------------------------------
// CBTSAController::AccessorySuspendedAudio
// -----------------------------------------------------------------------------
//		
void CBTSAController::AccessorySuspendedAudio(const TBTDevAddr& aBDAddr)
	{
	TRACE_FUNC
	RProperty::Set(KBTAudioRemCon, KBTAudioPlayerControl, EBTAudioPausePlayer);	
	Observer().RemoteAudioClosed(aBDAddr, EStereo );
	}

// -----------------------------------------------------------------------------
// CBTSAController::CompletePendingRequests
// -----------------------------------------------------------------------------
//
void CBTSAController::CompletePendingRequests(TUint aCompleteReq, TInt aError)
	{
	TRACE_INFO((_L("CBTSAController::CompletePendingRequests() Request %d"), aCompleteReq))
	
	if((aCompleteReq & KConnectReq) && iConnectStatus)
		{		
		TRACE_INFO((_L("[REQUEST] Connect request completed with %d"), aError))
		User::RequestComplete(iConnectStatus, aError);
		}
	if((aCompleteReq & KDisconnectReq) && iDisconnectStatus)
		{		
		TRACE_INFO((_L("[REQUEST] Disconnect request completed with %d"), aError))
		User::RequestComplete(iDisconnectStatus, aError);
		}
	if((aCompleteReq & KOpenAudioReq) && iOpenAudioStatus)
		{		
		TRACE_INFO((_L("[REQUEST] Open audio request completed with %d"), aError))
		User::RequestComplete(iOpenAudioStatus, aError);
		}
	if((aCompleteReq & KCloseAudioReq) && iCloseAudioStatus)
		{		
		TRACE_INFO((_L("[REQUEST] Close audio request completed with %d"), aError))
		User::RequestComplete(iCloseAudioStatus, KErrNone); // audio sw cant handle error codes.
		}
	}

// -----------------------------------------------------------------------------
// CBTSAController::SetRemoteAddr
// -----------------------------------------------------------------------------
//
void CBTSAController::SetRemoteAddr(const TBTDevAddr& aRemoteAddr)
	{
#ifdef PRJ_ENABLE_TRACE
	TBuf<12> buf;
	aRemoteAddr.GetReadable(buf);
	TRACE_INFO((_L("CBTSAController::SetRemoteAddr aRemoteAddr = %S"), &buf))
#endif
	iRemoteAddr = aRemoteAddr;
	}
	
// -----------------------------------------------------------------------------
// CBTSAController::GetRemoteAddr
// -----------------------------------------------------------------------------
//
TBTDevAddr CBTSAController::GetRemoteAddr() const
	{
#ifdef PRJ_ENABLE_TRACE
	TBuf<12> buf;
	iRemoteAddr.GetReadable(buf);
	TRACE_INFO((_L("CBTSAController::GetRemoteAddr iRemoteAddr = %S"), &buf))
#endif
	return iRemoteAddr;
	}

// -----------------------------------------------------------------------------
// CBTSAController::IsOpenAudioReqFromAccFWPending
// -----------------------------------------------------------------------------
//
TBool CBTSAController::IsOpenAudioReqFromAccFWPending() const
	{
	if(iOpenAudioStatus)
		return ETrue;
	else
		return EFalse;
	}

// -----------------------------------------------------------------------------
// CBTSAController::SetSEPIndex
// -----------------------------------------------------------------------------
//
void CBTSAController::SetSEPIndex(TInt aIndex)
	{
	iSBCSEPIndex = aIndex;
	}

// -----------------------------------------------------------------------------
// CBTSAController::GetSEPIndex
// -----------------------------------------------------------------------------
//
TInt CBTSAController::GetSEPIndex() const
	{
	return iSBCSEPIndex;
	}

// -----------------------------------------------------------------------------
// CBTSAController::SetResetAudioInput
// -----------------------------------------------------------------------------
//
void CBTSAController::SetResetAudioInput(TBool aReset)
	{
	iResetAudioInput = aReset;
	}

// -----------------------------------------------------------------------------
// CBTSAController::GetResetAudioInput
// -----------------------------------------------------------------------------
//
TBool CBTSAController::GetResetAudioInput() const
	{
	return iResetAudioInput;
	}

// -----------------------------------------------------------------------------
// CBTSAController::GetGavdpErrorActive
// -----------------------------------------------------------------------------
//
CBtsacActive* CBTSAController::GetGavdpErrorActive() const
	{
	return iGavdpErrorActive;
	}

// -----------------------------------------------------------------------------
// CBTSAController::NotifyError
// -----------------------------------------------------------------------------
//
void CBTSAController::NotifyError(TInt /*aError*/)
	{
	TRACE_FUNC
	if(iState->GetStateIndex() == EStateStreaming)
		{
		TRAP_IGNORE(iState->CloseAudioLinkL(GetRemoteAddr()));
		}
	else
		{
		TRAPD(err, ChangeStateL(CBtsacListening::NewL(*this, EResetGavdp, KErrNone)));
		if (err)
			{
			TRACE_INFO((_L("CBTSAController::NotifyError() Couldn't change state.")))
			}
		}
	CompletePendingRequests(KCompleteAllReqs, KErrCancel);
	}

// -----------------------------------------------------------------------------
// CBTSAController::GAVDP_Error
// -----------------------------------------------------------------------------
//
void CBTSAController::GAVDP_Error(TInt aError) 
	{
	TRACE_INFO((_L("CBTSAController::GAVDP_Error(%d)"), aError))
	if(iGavdpErrorActive)
		{
		if (!iGavdpErrorActive->IsActive())
		    {		    
		    TRequestStatus* sta = &(iGavdpErrorActive->iStatus);
		    iGavdpErrorActive->iStatus = KRequestPending;		    
		    User::RequestComplete(sta, aError);
		    iGavdpErrorActive->GoActive();
		    }
		}
	else
		{
		TRACE_INFO((_L("CBTSAController::CBTSAController() AO doesn't exist.")))
		}	
	}
	
// -----------------------------------------------------------------------------
// CBTSAController::RequestCompletedL
// -----------------------------------------------------------------------------
//	
void CBTSAController::RequestCompletedL(CBtsacActive& aActive)
	{
	TRACE_FUNC
	switch(aActive.RequestId())
		{
		case KRequestIdGavdpError:
			{
			iState->HandleGavdpErrorL(aActive.iStatus.Int());
			break;
			}
		default:
			{
			TRACE_INFO((_L("CBTSAController::RequestCompletedL() Unknown request")))
			break;
			}				
		}
	}

// -----------------------------------------------------------------------------
// CBTSAController::CancelRequest
// -----------------------------------------------------------------------------
//	
void CBTSAController::CancelRequest(CBtsacActive& /*aActive*/)
	{
	TRACE_FUNC
	}

//  End of File      
