/*
* Copyright (c) 2002 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 of CPhoneUIController class.
*
*/


// INCLUDE FILES
#include <featmgr.h>        // for FeatureManager
#include <settingsinternalcrkeys.h>
#include <phoneappcommands.hrh>

#include "cphoneuicontroller.h"
#include "pevirtualengine.h"
#include "cphonestatehandle.h"
#include "cphoneenginehandler.h"
#include "cphonesystemeventhandler.h"
#include "cphoneremotecontrolhandler.h"
#include "phonestatedefinitions.h"
#include "phonelogger.h"
#include "phoneconstants.h"
#include "phoneui.pan"
#include "cphonekeyeventforwarder.h"
#include "cphonecenrepproxy.h"
#include "cphonemediatorfactory.h"
#include "tphonecmdparamnumberentryobserver.h"
#include "cphonesecuritymodeobserver.h"
#include "cphoneviewcontroller.h"

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

// -----------------------------------------------------------
// CPhoneUIController::CPhoneUIController
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------
//
CPhoneUIController::CPhoneUIController()
    {
    }

// -----------------------------------------------------------
// CPhoneUIController::ConstructL()
// (other items were commented in a header).
// -----------------------------------------------------------
//
void CPhoneUIController::ConstructL( CPhoneViewController& aViewController )
    {
    __LOGMETHODSTARTEND(EPhoneControl, "CPhoneUIController::ConstructL()");
    // Creates correct protocol DLL
    CreateProtocolDllL( aViewController );

    // Reference the phone state machine
    iStateMachine = CPhoneStateHandle::Instance()->StateMachine();

    // Create the phone engine handler
    iEngineHandler = CPhoneEngineHandler::NewL( iStateMachine );
    // Create the system event handler
    iSystemEventHandler = CPhoneSystemEventHandler::NewL( iStateMachine );

    // Create the key event forwarder
    iKeyEventForwarder = CPhoneKeyEventForwarder::NewL( 
        CEikonEnv::Static()->EikAppUi()->ClientRect(), iStateMachine, &aViewController ); // codescanner::eikonenvstatic

    TInt leaveCode( 0 );
    TInt retry( 0 );
    RTimer timer;
    TRequestStatus timerReady;
    timer.CreateLocal();
    // Phone Engine is tried to start for KPeRetryCount times
    do
        {
        // Handle the message and trap leaves from message handling functions
        TRAP( leaveCode, iPhoneEngine = iStateMachine->CreatePhoneEngineL( 
            *this ) );
            
        if ( leaveCode )
            {
            // This thread is suspended for KPeRetryDelay
            timer.After( timerReady, KPeRetryDelay );
            User::WaitForRequest( timerReady );
            retry++;
            }
        }while ( leaveCode && retry < KPeRetryCount );
    timer.Close();
    
    if ( leaveCode )
        {
        // If Phone Engine didn't start
        User::Leave( leaveCode );
        }
    
    // Get the engine info
    iEngineInfo = iPhoneEngine->EngineInfo();

    // Store the phone engine information in the logger
    CPhoneLogger* phoneLogger = static_cast<CPhoneLogger*>
        ( CCoeEnv::Static( KUidPhoneUILoggerSingleton ) );
    phoneLogger->SetPhoneEngine( iPhoneEngine );

    // Store the phone engine information in the state machine
    iStateMachine->SetPhoneEngine( iPhoneEngine );
	
	// Set up security mode observer.
	iSecurityModeObserver = CPhoneSecurityModeObserver::NewL();
	iSecurityModeObserver->SetPhoneEngineInfo( iPhoneEngine->EngineInfo() );
	iStateMachine->SetSecurityModeObserver( iSecurityModeObserver );
	iStateMachine->SetSecurityMessageHandler( iSecurityModeObserver );
	
    // Set Number Entry observer
    TPhoneCmdParamNumberEntryObserver cmdParamNumberEntryObserver;
    cmdParamNumberEntryObserver.SetObserver( TCallBack( HandlePhoneNumberEditorCallBack, this ) );
    aViewController.ExecuteCommand( EPhoneViewSetNumberEntryObserver, 
                                            &cmdParamNumberEntryObserver);
    
	// Set up controller to observe security mode state changes.
    iStateMachine->SecurityMode()->RegisterStateObserver( aViewController );
	
    // Go to the startup state
    iStateMachine->ChangeState( EPhoneStateStartup );

	  CPhoneMediatorFactory::Instance()->CommandListener( this, iStateMachine,
		    iStateMachine->PhoneEngineInfo() );
    }

// -----------------------------------------------------------------------------
// CPhoneUIController::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CPhoneUIController* CPhoneUIController::NewL( 
    CPhoneViewController& aViewCommandHandle )
    {

    CPhoneUIController* self = new( ELeave ) CPhoneUIController();
    
    CleanupStack::PushL( self );
    self->ConstructL( aViewCommandHandle );
    CleanupStack::Pop( self );

    return self;
    }

// -----------------------------------------------------------
// Destructor
// 
// -----------------------------------------------------------

EXPORT_C CPhoneUIController::~CPhoneUIController()
    {
    __LOGMETHODSTARTEND(EPhoneControl, "CPhoneUIController::~CPhoneUIController()");
	delete iSecurityModeObserver;
	delete iRemoteControlHandler;
	delete iSystemEventHandler;
	delete iEngineHandler;
	delete iKeyEventForwarder;
//    delete iStateHandle; <-- CCoeStatic objects are destroyed outside application
    }

// ---------------------------------------------------------
// CPhoneUIController::HandleMessage( TInt aMessage, TInt aCallId ) 
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandleMessage( 
    const TInt aMessage, 
    const TInt aCallId ) 
    {
    __PHONELOGENGINEMSG( aMessage, aCallId );
    
    // PhoneCmdHandler is using Call information API so 
	// Remote Control Handler can be constructed only after CCCE is constructed.
	if ( aMessage == EPEMessagePEConstructionReady )
		{
		TRAP_IGNORE( ConstructRemoteControlHandlerL() );
		}
        	
    TRAPD( err, iEngineHandler->DoHandleMessageL( aMessage, aCallId ) );

    if ( err != KErrNone )
        {
        __PHONELOG2(
            EOnlyFatal, 
            EPhoneControl,
            "PHONEUI_ERROR: CPhoneUIController::HandleMessage - Message received in unexpected state (aMessage=%d, err=%d)",
            aMessage,
            err);
        }

    __PHONELOGENGINEMSGEND( aMessage );
    }
    
// ---------------------------------------------------------
// CPhoneUIController::HandleError( const TPEErrorInfo& aErrorInfo )
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandleError( 
    const TPEErrorInfo& aErrorInfo ) 
    {
    TInt err( KErrNone );
    
   	TRAP( err, iStateMachine->State()->HandleErrorL( aErrorInfo ) );	    	
    
    if( err != KErrNone )
        {
        __PHONELOG1(
            EOnlyFatal, 
            EPhoneControl,
            "PHONEUI_ERROR: CPhoneUIController::HandleError -  leave (err=%d)",
            err);
       	__ASSERT_DEBUG( EFalse, Panic( EPhoneCtrlUnknownPanic ) );
        }
    }    

// ---------------------------------------------------------
// CPhoneUIController::HandleKeyEventL
// ---------------------------------------------------------
//
EXPORT_C TKeyResponse CPhoneUIController::HandleKeyEventL(
    const TKeyEvent& aKeyEvent,
    TEventCode aEventCode )
    {
    __ASSERT_DEBUG( iKeyEventForwarder, Panic( EPhoneCtrlInvariant ) );
    return iKeyEventForwarder->OfferKeyEventAfterControlStackL( 
                aKeyEvent,
                aEventCode );
    }

// ---------------------------------------------------------
// CPhoneUIController::DynInitMenuPaneL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::DynInitMenuPaneL( 
    TInt aResourceId, 
    CEikMenuPane* aMenuPane )
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->DynInitMenuPaneL( aResourceId, aMenuPane );
    }

// ---------------------------------------------------------
// CPhoneUIController::DynInitMenuBarL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::DynInitMenuBarL( 
    TInt aResourceId, 
    CEikMenuBar* aMenuBar )
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->DynInitMenuBarL( aResourceId, aMenuBar );
    }

// ---------------------------------------------------------
// CPhoneUIController::HandleSystemEventL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandleSystemEventL( const TWsEvent& aEvent )
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandleSystemEventL( aEvent );
    }

// ---------------------------------------------------------
// CPhoneUIController::HandleForegroundEventL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandleForegroundEventL( TBool aForeground )
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandleForegroundEventL( aForeground );
    }

// ---------------------------------------------------------
// CPhoneUIController::HandlePhoneForegroundEventL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandlePhoneForegroundEventL()
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandlePhoneForegroundEventL();
    }

// ---------------------------------------------------------
// CPhoneUIController::HandlePhoneFocusLostEventL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandlePhoneFocusLostEventL()
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandlePhoneFocusLostEventL();
    }

// ---------------------------------------------------------
// CPhoneUIController::HandleIdleForegroundEventL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandleIdleForegroundEventL()
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandleIdleForegroundEventL();
    }

// ---------------------------------------------------------
// CPhoneUIController::HandleEnvironmentChangeL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandleEnvironmentChangeL( 
    const TInt aChanges )
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandleEnvironmentChangeL( aChanges );
    }

// ---------------------------------------------------------
// CPhoneUIController::HandlePhoneStartupL
// ---------------------------------------------------------
//
EXPORT_C void CPhoneUIController::HandlePhoneStartupL()
    {
    __ASSERT_DEBUG( iSystemEventHandler, Panic( EPhoneCtrlInvariant ) );
    iSystemEventHandler->HandlePhoneStartupL();
    }

// ---------------------------------------------------------
// CPhoneUIController::HandleCommandL
// ---------------------------------------------------------
//
EXPORT_C TBool CPhoneUIController::HandleCommandL( TInt aCommand )
    {
    __ASSERT_DEBUG( iStateMachine->State(), Panic( EPhoneCtrlInvariant ) );

	// Send key up message to engine so that we wouldn't accidentally play
	// any DTMF tone.
    
    // DTMF tone is not ended if command is EPhoneDialerValidNumber or
    // EPhoneDialerInvalidNumber. These commands result from
    // user pressing numbers, and they must not interfere with tones.
    if ( ! ( aCommand == EPhoneDialerValidNumber || aCommand == EPhoneDialerInvalidNumber ) )
        {
        iStateMachine->SendPhoneEngineMessage( MPEPhoneModel::EPEMessageEndDTMF );
        }

    return iStateMachine->State()->HandleCommandL( aCommand );
    }

// ---------------------------------------------------------
// CPhoneUIController::ProcessCommandL
// ---------------------------------------------------------
//
EXPORT_C TBool CPhoneUIController::ProcessCommandL( TInt aCommand )
    {
    __ASSERT_DEBUG( iStateMachine->State(), Panic( EPhoneCtrlInvariant ) );
    return iStateMachine->State()->ProcessCommandL( aCommand );
    }

// ---------------------------------------------------------
// CPhoneUIController::CreateProtocolDllL
// ---------------------------------------------------------
//
void CPhoneUIController::CreateProtocolDllL( CPhoneViewController& aViewController )
	{
	TBool voipSupported( EFalse );

    if( FeatureManager::FeatureSupported( KFeatureIdCommonVoip ) )
	    {
	    TInt dynamicVoIP( KDynamicVoIPOff );
		CPhoneCenRepProxy::Instance()->GetInt( 
	        KCRUidTelephonySettings, KDynamicVoIP, dynamicVoIP );
	        
	    if( dynamicVoIP == KDynamicVoIPOn )
		    {
			voipSupported = ETrue;		    	
		    }
	    }

    if( voipSupported )
	    {
	    iStateHandle = CPhoneStateHandle::CreateL(
	        &aViewController,
	        KVoIPExtension,
	        KUidAppVoIPExtensionStates );				    	
	    }
	else
		{
	    iStateHandle = CPhoneStateHandle::CreateL(
	        &aViewController,
	        KGSMProtocol,
	        KUidAppGSMStates );			
		}		
	}

// ---------------------------------------------------------
// CPhoneUIController::HandlePhoneNumberEditorCallBack
// ---------------------------------------------------------
//
TInt CPhoneUIController::HandlePhoneNumberEditorCallBack( TAny* aAny )
    {
    CPhoneUIController* aPhoneUiController =
        static_cast< CPhoneUIController* >( aAny );
        
    aPhoneUiController->DoHandlePhoneNumberEditorCallBack();
    
    return 0;
    }

// ---------------------------------------------------------
// CPhoneUIController::DoHandlePhoneNumberEditorCallBack
// ---------------------------------------------------------
//
void CPhoneUIController::DoHandlePhoneNumberEditorCallBack()
    {
    iStateMachine->State()->HandleNumberEntryEdited();
    }

// ---------------------------------------------------------
// CPhoneUIController::ConstructRemoteControlHandlerL
// ---------------------------------------------------------
//
void CPhoneUIController::ConstructRemoteControlHandlerL()
    { 
	// Create the remote control handler
	iRemoteControlHandler = CPhoneRemoteControlHandler::NewL( iStateMachine );
    }

//  End of File  
