/*
* Copyright (c) 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:  Accessory Control Interface class for HDMI Cable Status FSM.
*
*/


#include "accessorycontrolif.h"
#include "multifinitestatemachine.h"
#include "pdeconstants.h"
#include "trace.h"
#include "hdmicablestatusfsm.h"
#include <AccessoryServer.h>
#include <AccessoryControl.h>
#include <AsyCmdTypes.h>
#include <AccConfigFileParser.h>
#include <e32cmn.h>

// ======== LOCAL FUNCTIONS ========


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


// ---------------------------------------------------------------------------
// Symbian two-phased constructor
// ---------------------------------------------------------------------------
//
CAccessoryControlIf* CAccessoryControlIf::NewL(
        MFSMForBody& aFSM,
        RAccessoryServer& aAccessoryServer )
    {
    FUNC_LOG;
    CAccessoryControlIf* self = new ( ELeave ) CAccessoryControlIf(  aFSM );
    CleanupStack::PushL( self );
    self->ConstructL( aAccessoryServer );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CAccessoryControlIf::~CAccessoryControlIf()
    {
    FUNC_LOG;
    Cancel();
    if ( iAccessoryConnected )
        {
        TRequestStatus status;                
        iAccessoryControl.DisconnectAccessory( status, iGenericIDPtr->GenericID() );
        User::WaitForRequest( status ); 
        TInt retval = status.Int();
        INFO_1( "iAccessoryControl.DisconnectAccessory() return value %i", retval );
        }
    delete iGenericIDPtr;
    iAccessoryControl.CloseSubSession();        
    }

// ---------------------------------------------------------------------------
// ConnectAccessoryL
// ---------------------------------------------------------------------------
//
void CAccessoryControlIf::ConnectAccessoryL( TBool aCopyProtectionStatus )
    {
    FUNC_LOG;
    if ( !IsActive() )
        {
        CAccConfigFileParser* accConfigFileParser =
            CAccConfigFileParser::NewL( _L("Configuration file") );
        CleanupStack::PushL( accConfigFileParser );
        if ( !iGenericIDPtr )
            {
            delete iGenericIDPtr;
            iGenericIDPtr = NULL;
            }
        iGenericIDPtr = CAccConGenericID::NewL();

        RArray<TAccPolNameValueRecord> nameValueArray;
        CleanupClosePushL( nameValueArray );
        TBuf<KHWModelIDMaxLength> hwModelID( _L("hdmi"));
        TAccPolNameRecord nameRecord;
        TAccPolValueRecord valueRecord;

        TBuf<KHWModelIDMaxLength> HWModelID( _L("hdmi"));

        //Set GenericID header
        TAccPolGIDHeader GIDHeader;
        GIDHeader.iAccessoryDeviceType = KDTAVDevice;
        GIDHeader.iPhysicalConnection = KPCHDMI;
        GIDHeader.iApplicationProtocol = 0x0;    
        GIDHeader.iCapabilitiesSubblocks = KSBAudioSubblock | KSBVideoSubblock;
        GIDHeader.iHWModelID = hwModelID;
        GIDHeader.iHWDeviceID = 0x0;
        GIDHeader.iDeviceAddress = 0x0;
        TAccPolGenericID genericID;
        GIDHeader.iDBID = genericID.UniqueID();

				//Set "Audio Output Type" capability
				TAccPolNameValueRecord nameValueRecordAudioOutputType( KAccAudioOutputType,
					  EAccAudioOutPutTypePublic,
						EAPVInt,
						EAPVPolicy );
				nameValueArray.AppendL( nameValueRecordAudioOutputType );		

        //Set "Video Output Type" capability
        TAccPolNameValueRecord nameValueRecordVideoOut( KAccVideoOut,
            EAccVideoOutEHDMI,
            EAPVInt,
            EAPVAccessory );
        nameValueArray.AppendL( nameValueRecordVideoOut );
        
        // Set "HDMI attributes" capability
        TAccPolNameValueRecord nameValueRecordHdmiAttributes( KAccVideoHdmiAttributes,
            EAPVAccessory );
        nameValueArray.AppendL( nameValueRecordHdmiAttributes );

        // Set "HDCP" capability
        TAccPolNameValueRecord nameValueRecordHdcpSupport( KAccVideoHdcpSupport,
            aCopyProtectionStatus,
            EAPVBool,
            EAPVAccessory );
        nameValueArray.AppendL( nameValueRecordHdcpSupport );
        
        // Set "HDCP status" capability
        TAccPolNameValueRecord nameValueRecordHdcpSupportStatus( KAccVideoHdcpSupportStatus,
        aCopyProtectionStatus,
        EAPVBool,
        EAPVAccessory );
        nameValueArray.AppendL( nameValueRecordHdcpSupportStatus );
    
        // Set "Video active format" capability
        TAccPolNameValueRecord nameValueRecordVideoFormat( KAccVideoFormat,
            EAPVAccessory );
        nameValueArray.AppendL( nameValueRecordVideoFormat );

        accConfigFileParser->ParseGenericIDL( iGenericIDPtr,
            GIDHeader,
            nameValueArray );
        nameValueArray.Close();


        CleanupStack::PopAndDestroy( &nameValueArray );
        CleanupStack::PopAndDestroy( accConfigFileParser );

        iActiveRequestId = EAccessoryControlIfConnectRequested;
        iAccessoryControl.ConnectAccessory( iStatus, iGenericIDPtr, EFalse );
        SetActive();        
        }
    else
        {
        if ( EAccessoryControlIfConnectRequested == iActiveRequestId )
            {            
            INFO("Could not connect, because connect request already pending")
            }
        else if ( EAccessoryControlIfDisconnectRequested == iActiveRequestId )
            {
            INFO("Could not connect, because disconnect is pending")
            }
        User::Leave(KErrCouldNotConnect);
        }
    }

// ---------------------------------------------------------------------------
// DisconnectAccessory
// ---------------------------------------------------------------------------
//
void CAccessoryControlIf::DisconnectAccessory()
    {
    FUNC_LOG;
    if ( IsActive() )
        {
        Cancel();
        }
    iActiveRequestId = EAccessoryControlIfDisconnectRequested;
    iAccessoryControl.DisconnectAccessory( iStatus, iGenericIDPtr->GenericID() );
    SetActive();        
    }

// ---------------------------------------------------------------------------
// GetUniqueID
// ---------------------------------------------------------------------------
//
TInt CAccessoryControlIf::GetUniqueID()
    {
    FUNC_LOG;
    TInt uniqueID( 0 );
    if ( iGenericIDPtr  )
        {
        uniqueID = iGenericIDPtr->GenericID().UniqueID();
        }       
    return uniqueID;
    }

// ---------------------------------------------------------------------------
// GetAccPolGenericID
// ---------------------------------------------------------------------------
//
TInt CAccessoryControlIf::GetAccPolGenericID( TAccPolGenericID& aAccPolGenericID )
    {
    FUNC_LOG;
    TInt retVal( KErrNone );
    if ( iGenericIDPtr )
        {
        aAccPolGenericID = iGenericIDPtr->GenericID();
        }
    else
        {
        retVal = KErrNotFound;
        }
    return retVal;
    }

// ---------------------------------------------------------------------------
// NotifyValueChange
// ---------------------------------------------------------------------------
//
TInt CAccessoryControlIf::NotifyValueChange(
        const TUint32& aName,
        const TAccValueTypeTBool aValue ) const
    {
    FUNC_LOG;
    TInt retVal( KErrNone );
    if ( iGenericIDPtr )
        {
        TAccPolNameRecord aNameRecord;
        aNameRecord.SetName( aName );
        TRAP( retVal, iAccessoryControl.AccessoryValueChangedNotifyL( iGenericIDPtr->GenericID(), aNameRecord, aValue ) );
        if ( KErrNone != retVal )
            {
            INFO_1( "RAccessoryControl::AccessoryValueChangedNotifyL() failed, return code: %d", retVal );
            }
        }
    else
        {
        INFO( "No Generic ID found, cannot notify");
        retVal = KErrNotFound;
        }
    return retVal;
    }

// ---------------------------------------------------------------------------
// NotifyValueChange
// ---------------------------------------------------------------------------
//
TInt CAccessoryControlIf::NotifyValueChange(
        const TUint32& aName,
        const CAccPolObjectCon& aValue ) const
    {
    FUNC_LOG;
    TInt retVal( KErrNone );
    if ( iGenericIDPtr )
        {
        TAccPolNameRecord aNameRecord;
        aNameRecord.SetName( aName );
        TRAP( retVal, iAccessoryControl.AccessoryValueChangedNotifyL( iGenericIDPtr->GenericID(), aNameRecord, aValue ) );
        if ( KErrNone != retVal )
            {
            INFO_1( "RAccessoryControl::AccessoryValueChangedNotifyL() failed, return code: %d", retVal );
            }
        }
    else
        {
        INFO( "No Generic ID found, cannot notify");
        retVal = KErrNotFound;
        }
    return retVal;
    }


// ----------------------------------------------------------------------------
// RunL
//
// ----------------------------------------------------------------------------
//
void CAccessoryControlIf::RunL()
    {

    FUNC_LOG;
    TInt retVal( iStatus.Int() );
    if ( KErrNone == retVal )
        {
        if (  EAccessoryControlIfConnectRequested == iActiveRequestId )
            {
            iAccessoryConnected = ETrue;

            ((CHDMICableStatusFSM*)&iFSM)->GetPDEngine()->Input(
                    EPDEFSMIdHDMICableStatus,
                    EPDEIfAccessoryControl,
                    EPDEIfAccessoryControlEventConnected );
            }
        else if (  EAccessoryControlIfDisconnectRequested == iActiveRequestId )
            {
            iAccessoryConnected = EFalse;
 
            ((CHDMICableStatusFSM*)&iFSM)->GetPDEngine()->Input(
                    EPDEFSMIdHDMICableStatus,
                    EPDEIfAccessoryControl,
                    EPDEIfAccessoryControlEventDisconnected );
            delete iGenericIDPtr;
            iGenericIDPtr = NULL;
            }
        }
    else
        {
        if (  EAccessoryControlIfConnectRequested == iActiveRequestId )
            {
            INFO_1( "RAccessoryControl::ConnectAccessory failed, error code: %d", retVal );

            ((CHDMICableStatusFSM*)&iFSM)->GetPDEngine()->Input(
                    EPDEFSMIdHDMICableStatus,
                    EPDEIfAccessoryControl,
                    EPDEIfAccessoryControlEventConnectFailed );            
            }
        else if (  EAccessoryControlIfDisconnectRequested == iActiveRequestId )
            {
            INFO_1( "RAccessoryControl::DisconnectAccessory failed, error code: %d", retVal );
           
            ((CHDMICableStatusFSM*)&iFSM)->GetPDEngine()->Input(
                    EPDEFSMIdHDMICableStatus,
                    EPDEIfAccessoryControl,
                    EPDEIfAccessoryControlEventDisconnectFailed );            
            delete iGenericIDPtr;
            iGenericIDPtr = NULL;
            }
        }
    iActiveRequestId = EAccessoryControlIfNoRequestActive;
    }

// ----------------------------------------------------------------------------
// DoCancel
//
// ----------------------------------------------------------------------------
//
void CAccessoryControlIf::DoCancel()
    {
    FUNC_LOG;
    if (  EAccessoryControlIfConnectRequested == iActiveRequestId )
        {
        iAccessoryControl.CancelConnectAccessory();
        }
    else if (  EAccessoryControlIfDisconnectRequested == iActiveRequestId )
        {
        iAccessoryControl.CancelDisconnectAccessory();
        }
    iActiveRequestId = EAccessoryControlIfNoRequestActive;
    }

// ---------------------------------------------------------
// C++ constructor
// ---------------------------------------------------------
//
CAccessoryControlIf::CAccessoryControlIf(
        MFSMForBody& aFSM
        ) 
    : CActive( CActive::EPriorityLow ),
    iFSM( aFSM )
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------
// ConstructL
// ---------------------------------------------------------
//
void CAccessoryControlIf::ConstructL( RAccessoryServer& aAccessoryServer )
    {
    FUNC_LOG;
    
    User::LeaveIfError( iAccessoryControl.CreateSubSession( aAccessoryServer ) );
    CActiveScheduler::Add( this );
    }

// ======== GLOBAL FUNCTIONS ========

