/*
* Copyright (c) 2007 - 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:  Shows number keypad and generates keypress event when 
*                 buttons are pressed.
*
*/


// INCLUDE FILES
#include <e32event.h>
#include <gulicon.h>
#include <eikapp.h>
#include <aknbutton.h>
#include <AknControl.h>
#include <AknsUtils.h>
#include <AknsSkinInstance.h>
#include <AknsDrawUtils.h>
#include <AknsConstants.h>
#include <AknLayout2Def.h>
#include <aknlayoutscalable_apps.cdl.h>
#include <layoutmetadata.cdl.h>
#include <data_caging_path_literals.hrh> // for KDC_APP_RESOURCE_DIR
#include <touchfeedback.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <AknsFrameBackgroundControlContext.h>

#include "cdialerkeypadcontainer.h"
#include "dialercommon.h"
#include "dialertrace.h"

#include "cdialerkeypadbutton.h"

// Number of buttons in this container
const TInt KNumberOfButtons = 12; 

struct TDialerButton
    {
    TMifDialer iBitmap;
    TMifDialer iBitmapMask;
    TInt iScanCode;
    TInt iKeyCode;
    };  

const TDialerButton KKeyPadButtons[ KNumberOfButtons ] =

    {
        { EMbmDialerQgn_indi_dialer_voicemail,
          EMbmDialerQgn_indi_dialer_voicemail_mask, 
          '1',
          '1'
        },
        { KDialerNoIcon, KDialerNoIcon, 
          '2', '2' },
        { KDialerNoIcon, KDialerNoIcon,  
          '3', '3' },
        { KDialerNoIcon, KDialerNoIcon,  
          '4', '4' },
        { KDialerNoIcon, KDialerNoIcon,  
          '5', '5' },
        { KDialerNoIcon, KDialerNoIcon,  
          '6', '6' },
        { KDialerNoIcon, KDialerNoIcon, 
          '7', '7' },
        { KDialerNoIcon, KDialerNoIcon,  
          '8', '8' },
        { KDialerNoIcon, KDialerNoIcon,  
          '9', '9' },
        { KDialerNoIcon, KDialerNoIcon,  
          EStdKeyNkpAsterisk, '*'  },
        { EMbmDialerQgn_indi_dialer_internet, 
          EMbmDialerQgn_indi_dialer_internet_mask,  
          '0', '0' },
        { KDialerNoIcon, KDialerNoIcon,      
          EStdKeyHash, '#' }
    };



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

// ---------------------------------------------------------------------------
// Symbian OS two phased constructor
// ---------------------------------------------------------------------------
//
CDialerKeyPadContainer* CDialerKeyPadContainer::NewL( 
    const CCoeControl& aContainer,
    TDialerOperationMode aOperatingMode
     )
    {
    CDialerKeyPadContainer* self = 
        new( ELeave )CDialerKeyPadContainer ( aContainer, aOperatingMode );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }


// ---------------------------------------------------------------------------
// Symbian OS two phased constructor
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::ConstructL()
    {    
    DIALER_PRINT("KeyPadContainer::ConstructL<");
    BaseConstructL();
    iKeyLabelManager = CDialerKeyPadLabelManager::NewL( *iCoeEnv, *this );
    CreateButtonsL();
    iCoeEnv->AddForegroundObserverL( *this );
    DIALER_PRINT("KeyPadContainer::ConstructL>");
    }

// Constructor
CDialerKeyPadContainer::CDialerKeyPadContainer( 
    const CCoeControl& aContainer, 
    TDialerOperationMode aOperatingMode )
    : CDialerContainerBase ( 
        const_cast<CCoeControl&>(aContainer) ),
      iOperatingMode( aOperatingMode )
    {
    }
    
// Destructor
CDialerKeyPadContainer::~CDialerKeyPadContainer()
    {
    iButtons.ResetAndDestroy();
    iCoeEnv->RemoveForegroundObserver( *this );
    delete iKeyLabelManager;
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::CountComponentControls
//
// ---------------------------------------------------------------------------
//
TInt CDialerKeyPadContainer::CountComponentControls() const
    {
    return KNumberOfButtons;
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::ComponentControl
//
// ---------------------------------------------------------------------------
//
CCoeControl* CDialerKeyPadContainer::ComponentControl( TInt aIndex ) const
    {
    __ASSERT_DEBUG( aIndex < KNumberOfButtons, 
    _L("CDialerKeyPadContainer::ComponentControl, index out of range."));
    
    return iButtons[aIndex];
    }
    
// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::HandlePointerEventL
//
// ---------------------------------------------------------------------------
//  
void CDialerKeyPadContainer::HandlePointerEventL(
    const TPointerEvent& aPointerEvent )
    {
    DIALER_PRINT("KeyPadContainer::HandlePointerEventL<");    
    
    CCoeControl::HandlePointerEventL( aPointerEvent );    

    if ( aPointerEvent.iType == TPointerEvent::EButton1Down ) 
        {
        iPointerEvent = aPointerEvent; 
        iKeyUpSimulatedDueToDragging = EFalse;
        }
    DIALER_PRINT("KeyPadContainer::HandlePointerEventL>");     
    }
    
// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::SetVariety
//
// Set variety according to current state.
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::SetVariety()
    {
    if ( Layout_Meta_Data::IsLandscapeOrientation() )
        {
        iVariety = EVideoVarietyLandscape;
        }
    else
        {
        iVariety = EVideoVarietyPortrait;
        }
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::SetLayout
//
// Set layout for video dtmf or phone dialer 
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::SetLayout()
    {
    if ( iOperatingMode == EModeDialer ||
         iOperatingMode == EModeEasyDialing )
        {
        // Same renewed layout is used regardless of the status
        // of Easy Dialing
        SetEasyDialingLayout();
        }
    else
        {
        SetVideoLayout();
        }
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::SetPhoneLayout
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::SetPhoneLayout()
    {
    // Set Number entry layout.
    /*

    // LAF Table : grid_dialer2_keypad_pane
    inline TAknLayoutScalableParameterLimits cell_dialer2_keypad_pane_ParamLimits()
    inline TAknWindowComponentLayout cell_dialer2_keypad_pane()

    // LAF Table : cell_dialer2_keypad_pane
    inline TAknLayoutScalableParameterLimits bg_button_pane_pane_cp04_ParamLimits()
    inline TAknWindowComponentLayout bg_button_pane_pane_cp04()
    inline TAknLayoutScalableParameterLimits cell_dialer2_keypad_pane_g1_ParamLimits()
    */
    
    TRect parentRect( Rect() );

    // Layout buttons
    TAknLayoutScalableParameterLimits limits = 
        AknLayoutScalable_Apps::cell_dialer2_keypad_pane_ParamLimits( iVariety );
    
    TInt i = 0;
    for ( TInt row = limits.FirstRow(); row <= limits.LastRow(); row++ )
        {
        for ( TInt col = limits.FirstColumn(); 
              col <= limits.LastColumn(); col++ )
            {
            iButtons[i]->SetVariety( iVariety );
            iButtons[i]->SetOperationMode( iOperatingMode );
    
            AknLayoutUtils::LayoutControl( iButtons[i], parentRect, TAknWindowComponentLayout::Compose( 
                    AknLayoutScalable_Apps::cell_dialer2_keypad_pane( iVariety, col, row ), 
                    AknLayoutScalable_Apps::bg_button_pane_pane_cp04( iVariety ) ) );
            i++;
            }
        }
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::SetEasyDialingLayout
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::SetEasyDialingLayout()
    {
    TRect parentRect( Rect() );
    
    // Layout buttons
    TAknLayoutScalableParameterLimits limits = 
        AknLayoutScalable_Apps::cell_dialer2_keypad_pane_ParamLimits( iVariety );
    
    // Rectangle of the first button
    TAknLayoutRect buttonLayoutRect;
    buttonLayoutRect.LayoutRect( parentRect, 
            AknLayoutScalable_Apps::cell_dia3_key_num_pane( iVariety ) );
    TRect firstButtonRect = buttonLayoutRect.Rect();
    // Move the first button rect to top-left-corner of the keypad area, 
    // the default place is wrong in mirrored layout.
    firstButtonRect.SetRect( parentRect.iTl, firstButtonRect.Size() );
    
    TInt colCount = limits.LastColumn() - limits.FirstColumn() + 1;

    for ( TInt row = limits.FirstRow() ; row <= limits.LastRow() ; row++ )
        {
        for ( TInt col = limits.FirstColumn() ; col <= limits.LastColumn() ; col++ )
            {
            // Calculate corresponding index in iButtons array
            TInt idx = col + row * colCount;
            
            // Set mode and variety so that correct button internal layout will be used.
            // Always use ED mode, so that text labels are visible even when ED is off.
            iButtons[idx]->SetVariety( iVariety );
            iButtons[idx]->SetOperationMode( EModeEasyDialing );
            
            // Layout button
            TRect buttonRect = firstButtonRect;
            buttonRect.Move( col * buttonRect.Width(), row * buttonRect.Height() );
            buttonRect.Shrink( 1, 1 ); // to create small gap between buttons
            iButtons[idx]->SetRect( buttonRect );
            }
        }
    
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::SetVideoLayout
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::SetVideoLayout()
    {
    TRect parentRect( Rect() );
    
    TAknLayoutScalableParameterLimits limits = 
        AknLayoutScalable_Apps::cell_video_dialer_keypad_pane_ParamLimits( iVariety ) ;
    
    TInt i = 0;
    for ( TInt row = limits.FirstRow(); row <= limits.LastRow(); row++ )
        {
        for ( TInt col = limits.FirstColumn(); 
              col <= limits.LastColumn(); 
              col++ )
            {
            iButtons[i]->SetVariety( iVariety );
            iButtons[i]->SetOperationMode( iOperatingMode );
        
            // Layout button
            AknLayoutUtils::LayoutControl(
                iButtons[i], parentRect, 
                TAknWindowComponentLayout::Compose( 
                    AknLayoutScalable_Apps::cell_video_dialer_keypad_pane( 
                        iVariety, col, row ),             
                    AknLayoutScalable_Apps::bg_button_pane_cp08( iVariety ) ) );
            i++;
            }
        }
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::CreateButtonsL
//
// Create buttons for this container.
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::CreateButtonsL()
    {
    DIALER_PRINT("KeyPadContainer::CreateButtonsL<");
    
    TInt flags ( KAknButtonReportOnKeyDown  |
                 KAknButtonRequestExitOnButtonUpEvent );
    
    for ( TInt i = 0; i < KNumberOfButtons; i++ )
        {
        const TPtrC numLabel = iKeyLabelManager->ButtonNumLabel( i );

        const TPtrC alphaLabel = iKeyLabelManager->ButtonFirstAlphaLabel( i );

        const TPtrC secondAlphaLabel = iKeyLabelManager->ButtonSecondAlphaLabel( i );
        
        CDialerKeyPadButton* button = CDialerKeyPadButton::NewLC( 
            numLabel,
            alphaLabel,
            secondAlphaLabel,
            KKeyPadButtons[i].iScanCode,
            KKeyPadButtons[i].iKeyCode,
            KKeyPadButtons[i].iBitmap,
            KKeyPadButtons[i].iBitmapMask,
            flags );
        iButtons.AppendL( button );
        CleanupStack::Pop( button );
        
        button->SetMopParent( this );
        button->SetParent( this );
        button->SetContainerWindowL( *this );
        button->SetObserver( this );
        button->ActivateL();
        }     
    DIALER_PRINT("KeyPadContainer::CreateButtonsL>");
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::HandleControlEventL
//
// Handles an event from an observed button item.
// Finds the pressed button and generates key press event, which
// is handled by parent control.
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::HandleControlEventL( CCoeControl* aControl,
                                                TCoeEvent aEventType )
    {
    DIALER_PRINTF("KeyPadContainer::HandleControlEventL.EventType=",
                 (TInt)aEventType);
    
    if ( aEventType == EEventStateChanged || 
         aEventType == EEventRequestCancel ||
         aEventType == EEventRequestExit ||
         aEventType == CDialerKeyPadButton::EEventDraggingOutsideButton )
        
        {
        // Find tapped control 

        CDialerKeyPadButton* tappedButton = NULL;
        for ( TInt i=0; i < iButtons.Count(); i++ )
            {
            if ( iButtons[i] == aControl )
                {
                tappedButton = iButtons[i];
                break;
                }    
            }
        
        if ( !tappedButton )
            {
            __ASSERT_DEBUG( EFalse, DialerPanic( EDialerPanicEventFromUnknownControl ) );
            return;
            }
        
        // Send key event to phone.
        TKeyEvent keyEvent;
        keyEvent.iCode = 0; // iCode should be 0 for all but EEventKey type of events
        keyEvent.iScanCode = tappedButton->ScanCode();
        keyEvent.iModifiers = ( EModifierNumLock | EModifierKeypad ); // Mark that this event is dialer simulated
        keyEvent.iRepeats = 0;
        
        switch ( aEventType )
            {
            case EEventRequestExit:
            case EEventRequestCancel:
                {
                DIALER_PRINT("HandleControlEventL.EEventRequestExit");
                iButtonPressedDown = EFalse;
                if ( !iKeyUpSimulatedDueToDragging )
                    {
                    ControlEnv()->SimulateKeyEventL( keyEvent, EEventKeyUp );
                    }
                iKeyUpSimulatedDueToDragging = EFalse;
                }
                break;
                
            case EEventStateChanged:
                {    
                DIALER_PRINT("HandleControlEventL.EEventStateChanged");
                iButtonPressedDown = ETrue;
                iParentControl.PrepareForFocusGainL();

                ControlEnv()->SimulateKeyEventL( keyEvent, EEventKeyDown );

                if ( iButtonPressedDown )
                    {
                    // Send event key if key havent be lifted up already
                    keyEvent.iCode = tappedButton->KeyCode();
                    ControlEnv()->SimulateKeyEventL( keyEvent, EEventKey );
                    }
                }
                break;
            
            case CDialerKeyPadButton::EEventDraggingOutsideButton:
                {
                DIALER_PRINT("HandleControlEventL.EEventDraggingOutsideButton");
                // User hasn't released touch yet but in order to cancel
                // long press action handled and initiated by parent control, 
                // we must send key up event now.
                if ( !iKeyUpSimulatedDueToDragging )
                    {
                    ControlEnv()->SimulateKeyEventL( keyEvent, EEventKeyUp );
                    iKeyUpSimulatedDueToDragging = ETrue;
                    }
                }
                break;
                
            default:
            break;
            }
        }
    DIALER_PRINT("KeyPadContainer::HandleControlEventL>");
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::HandleResourceChange
//
// Forwards skin change event to buttons
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::HandleResourceChange( TInt aType )
    {
    if ( aType == KAknsMessageSkinChange )
        {    
        for ( TInt i=0; i < iButtons.Count(); i++ )
            {
            iButtons[i]->HandleResourceChange( aType );
            }
        }
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::MakeVisible
//
// Called when dialer control becomes visible or invisible
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::MakeVisible( TBool aVisible )
    {
    // This is needed when dialer control disappeares during keypress. 
    // Last pressed pointer event must be forwarted to framework 
    // as pointer up event. Thus button is set to unpressed state etc. 
    // This code calls HandlePointerEventL of the parent class instead of this.
    // If we call this classes HandlePointerEventL, this classes 
    // grab status is not cleared, and later coming EButton1Up events may end
    // up erroneously to this class, although intended elsewhere.
    // 
    if ( !aVisible && iButtonPressedDown && Parent() )
        {    
        iPointerEvent.iType = TPointerEvent::EButton1Up;
        TRAP_IGNORE( Parent()->HandlePointerEventL( iPointerEvent ) );
        }    
    CCoeControl::MakeVisible( aVisible );        
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::SetOperationMode
//
// Set new operation mode for the keypad
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::SetOperationMode( TDialerOperationMode aOperatingMode )
    {
    iOperatingMode = aOperatingMode;
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::HandleGainingForeground
//
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::HandleGainingForeground()
    {
    
    }
    
// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::HandleLosingForeground
//
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::HandleLosingForeground()
    {
    // This is needed when dialer control disappeares during keypress. 
    // Last pressed pointer event must be forwarted to framework 
    // as pointer up event. Thus button is set to unpressed state etc. 
    // This code calls HandlePointerEventL of the parent class instead of this.
    // If we call this classes HandlePointerEventL, this classes 
    // grab status is not cleared, and later coming EButton1Up events may end
    // up erroneously to this class, although intended elsewhere.
    // 
    if ( iButtonPressedDown && Parent() )
        {    
        iPointerEvent.iType = TPointerEvent::EButton1Up;
        TRAP_IGNORE( Parent()->HandlePointerEventL( iPointerEvent ) );
        }    
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::KeyLabelsChanged
//
// Reset button labels and update the layout
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::KeyLabelsChanged()
    {
    for ( TInt i = 0 ; i < iButtons.Count() ; i++ )
        {
        const TPtrC numLabel = iKeyLabelManager->ButtonNumLabel( i );
        const TPtrC alphaLabel = iKeyLabelManager->ButtonFirstAlphaLabel( i );
        const TPtrC secondAlphaLabel = iKeyLabelManager->ButtonSecondAlphaLabel( i );
        
        iButtons[i]->SetNumLabel( numLabel );
        iButtons[i]->SetPrimaryAlphaLabel( alphaLabel );
        iButtons[i]->SetSecondaryAlphaLabel( secondAlphaLabel );
        
        // reset layout
        iButtons[i]->SetSize( iButtons[i]->Size() );
        }
    DrawDeferred();
    }

// ---------------------------------------------------------------------------
// CDialerKeyPadContainer::EnableTactileFeedback
//
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadContainer::EnableTactileFeedback( const TBool aEnable )
    {
    for ( TInt i=0; i < iButtons.Count(); i++ )
        {
        iButtons[i]->EnableAudioFeedback( aEnable );
        }

    }
// End of File
