/*
* Copyright (c) 2008 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:  Avkon keypad 
*
*/


#include <aknlayoutscalable_apps.cdl.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <layoutmetadata.cdl.h>
#include <aknbutton.h>
#include <AknsDrawUtils.h>
#include <AknBidiTextUtils.h>
#include <AknsFrameBackgroundControlContext.h>
#include <aknappui.h>
#include "aknkeypad.h"

#include <AknTasHook.h> // for testability hooks
#include <e32property.h>
#include <PtiDefs.h>                //keys
#include <featmgr.h>                //FeatureManager
#include <AvkonInternalCRKeys.h>


CAknKeypad* CAknKeypad::NewL( CCoeControl& aParent, TInt aQueryType )
    {
    CAknKeypad* self = new ( ELeave ) CAknKeypad;
    CleanupStack::PushL( self );
    self->ConstructL( aParent, aQueryType );
    CleanupStack::Pop(); // self
    AKNTASHOOK_ADDL( self, "CAknKeypad" );
    return self;
    }

CAknKeypad::~CAknKeypad()
    {
    AKNTASHOOK_REMOVE();
    }

void CAknKeypad::SizeChanged()
    {
    TBool landscape = Layout_Meta_Data::IsLandscapeOrientation();
         
    TAknLayoutScalableParameterLimits limits = AknLayoutScalable_Apps::cell_vitu2_itu_pane_ParamLimits( 0 );

    for ( TInt row = 0; row <= limits.LastRow(); ++row )
        {
        for ( TInt column = 0; column <= limits.LastColumn(); ++column )
            {
            TAknLayoutRect layoutRect;
            layoutRect.LayoutRect( Rect(), AknLayoutScalable_Apps::cell_vitu2_itu_pane( landscape ? 1 : 0, column, row ).LayoutLine() );
  
      		TAknLayoutRect layoutRect2;
            layoutRect2.LayoutRect( layoutRect.Rect(), AknLayoutScalable_Apps::bg_button_pane_cp010( landscape ? 3 : 0 ).LayoutLine() );
        
            Components().At( row * ( limits.LastColumn() + 1 ) + column ).iControl->SetRect( layoutRect2.Rect() );
            }
        }
    }

CAknKeypad::CAknKeypad()
    {
    }

void CAknKeypad::ConstructL( CCoeControl& aParent, TInt aQueryType )
    {
    SetContainerWindowL( aParent );
    InitComponentArrayL();
    
    iQueryType = aQueryType;
    
    // create as many buttons as there are rows & columns
    TAknLayoutScalableParameterLimits limits = AknLayoutScalable_Apps::cell_vitu2_itu_pane_ParamLimits( 0 );
    
    TInt count = ( limits.LastRow() + 1 ) * ( limits.LastColumn() + 1 );
    
    const TChar KCharArray[] = 
    	{
    	'1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'
    	};
    
    const TInt KScanCodeArray[] =
    	{
    	49, 50, 51, 52, 53, 54, 55, 56, 57, EStdKeyNkpAsterisk, 48, EStdKeyHash
    	};
    
    for ( TInt i = 0; i < count; ++i )
        {
        TBuf<1> keyChar;
        keyChar.Append( KCharArray[i] );
      
        TInt scanCode = KScanCodeArray[ i ];
        CAknKeypadButton* button = CAknKeypadButton::NewL( keyChar, scanCode, this );
        CleanupStack::PushL( button );

        button->SetFocusing( EFalse );
        
        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
        
        TRgb color; 
        AknsUtils::GetCachedColor( skin, color, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG68 );
   
  		button->OverrideColorL( EColorButtonText, color );
        button->OverrideColorL( EColorButtonTextPressed, color );
        button->OverrideColorL( EColorButtonTextDimmed, color );
        
        button->SetBackgroundIds( KAknsIIDQsnFrKeypadButtonNormal,
        	KAknsIIDQsnFrKeypadButtonPressed, KAknsIIDQsnFrKeypadButtonInactive,
        	KAknsIIDQsnFrKeypadButtonPressed, KAknsIIDQsnFrKeypadButtonInactive );
     
     	// Hack
        
        if ( i == 0 ) //Display '.,?' in button 
            {
            button->SetUpperAndLowerTextL(_L(".,?"), _L(".,?"));
            }
        else if ( i == 1 )
        	{
        	button->SetUpperAndLowerTextL(_L("ABC"), _L("abc"));
       		}
        else if ( i == 2)
        	{
        	button->SetUpperAndLowerTextL(_L("DEF"), _L("def"));
        	}
        else if ( i == 3)
        	{
        	button->SetUpperAndLowerTextL(_L("GHI"), _L("ghi"));
        	}
        else if ( i == 4)
        	{
        	button->SetUpperAndLowerTextL(_L("JKL"), _L("jkl"));
        	}
        else if ( i == 5)
        	{
        	button->SetUpperAndLowerTextL(_L("MNO"), _L("mno"));
        	}	
        else if ( i == 6)
        	{
        	button->SetUpperAndLowerTextL(_L("PQRS"), _L("pqrs"));
        	}
        else if ( i == 7)
        	{
        	button->SetUpperAndLowerTextL(_L("TUV"), _L("tuv"));
        	}
        else if ( i == 8)
        	{
        	button->SetUpperAndLowerTextL(_L("WXYZ"), _L("wxyz"));
        	}
        else if ( i == 9)
        	{
        	button->SetUpperAndLowerTextL(_L("+"), _L("+"));
        	}
        else if ( i == 10)
        	{
        	TBuf<16> txt;
        	txt.Append( TChar(0xf812) );
        	button->SetUpperAndLowerTextL(txt, txt);
        	}
        else if ( i == 11)
        	{
        	TBuf<16> txt;
        	txt.Append( TChar(0x2191) );
        	button->SetUpperAndLowerTextL(txt, txt);
        	}
        	
        // End of Hack	
         
        
        if( scanCode == EStdKeyNkpAsterisk && aQueryType != ECodeLayout && aQueryType != EDataLayout)
        	{
            button->SetDimmed( ETrue );  
            }
        else if( scanCode == EStdKeyHash && aQueryType != EPinLayout && aQueryType != ECodeLayout && aQueryType != EDataLayout)
        	{
        	button->SetDimmed( ETrue );
        	}
        
        
        	
        CleanupStack::Pop(); // button
        
        Components().AppendLC( button, i );
        CleanupStack::Pop(); // button
        }
    }
    
    
void CAknKeypad::SetState(TAknEditingState aState)
	{
	iState = aState;
	Window().Invalidate( Rect() );
	}
	
TAknEditingState CAknKeypad::State()
	{
	return iState;
	}
	
TInt CAknKeypad::QueryType()
	{
	return iQueryType;	
	}
    
    
// CAknKeypadButton
        
CAknKeypadButton* CAknKeypadButton::NewL( const TDesC& aText, const TInt aScanCode, CAknKeypad* aKeypad )
	{
 	CAknKeypadButton* self = new (ELeave) CAknKeypadButton( KAknButtonKeyRepeat, aScanCode, aKeypad );
    CleanupStack::PushL( self );
    self->ConstructL( aText );
    CleanupStack::Pop( self );
    AKNTASHOOK_ADDL( self, "CAknKeypadButton" );
    return self;
	}

CAknKeypadButton::~CAknKeypadButton()
    {
    AKNTASHOOK_REMOVE();
    delete iUpperText;
    delete iLowerText;
    }
    
CAknKeypadButton::CAknKeypadButton( const TInt aFlags, const TInt aScanCode, CAknKeypad* aKeypad ):
	CAknButton( aFlags ), iScanCode(aScanCode), iKeypad(aKeypad)
    {
    }
    
void CAknKeypadButton::ConstructL( const TDesC& aText )
    {
    CAknButton::ConstructL( NULL, NULL, NULL, NULL, aText, KNullDesC, 0 );
    }
    
    
    
void CAknKeypadButton::SetUpperAndLowerTextL( const TDesC& aUpperText, const TDesC& aLowerText )
    {
    delete iUpperText;
    delete iLowerText;
    
    iUpperText = NULL;
    iLowerText = NULL;

    iUpperText = aUpperText.AllocL();
    iLowerText = aLowerText.AllocL();
    }    

void CAknKeypadButton::HandlePointerEventL( const TPointerEvent& aPointerEvent )
	{
	CAknButton::HandlePointerEventL( aPointerEvent);
	
	if ( AknLayoutUtils::PenEnabled() )
		{
		TInt activeKeypad =0;
        RProperty::Get(KCRUidAvkon, KAknKeyBoardLayout,activeKeypad);
        
        
        switch ( aPointerEvent.iType )
            {
            case TPointerEvent::EButton1Down:
                {
                TRawEvent event;
               	event.Set( TRawEvent::EKeyDown, iScanCode);
               	event.SetTip( ETrue );
               	
               	if (iEikonEnv->AppUi())
					{
					static_cast<CAknAppUi*>(iEikonEnv->EikAppUi())->DisableNextKeySound( iScanCode );
					}
               	
                if(activeKeypad != EPtiKeyboard12Key)
				    {				
              	    // Security lock code add, begin:
				    TKeyEvent keyEvent;
				    // Fep manager need check the event, the modifiers and the event type must the same
				    // And other parts must not use the same modifiers!!!
             	    keyEvent.iModifiers = EModifierNumLock | EModifierKeypad | EModifierSpecial;
							ControlEnv()->SimulateKeyEventL( keyEvent, EEventKeyDown );
				    // Security lock code add, end. 
				    }

            	CCoeEnv::Static()->WsSession().SimulateRawEvent( event );
            	
            	if ( iKeypad->QueryType() != ECodeLayout && iKeypad->QueryType() != EDataLayout)
                	{
            		TRawEvent event;
               		event.Set( TRawEvent::EKeyUp, iScanCode);
               		event.SetTip( ETrue );
            		CCoeEnv::Static()->WsSession().SimulateRawEvent( event );
                	}
                break;	
                }

            case TPointerEvent::EButton1Up:
                {
                if ( iKeypad->QueryType() == ECodeLayout || iKeypad->QueryType() == EDataLayout)
                	{
                	TRawEvent event;
               		event.Set( TRawEvent::EKeyUp, iScanCode);
               		event.SetTip( ETrue );
            		CCoeEnv::Static()->WsSession().SimulateRawEvent( event );
                	}
     
                break;
                }

            default:
                break;
            }
       }	
	}
	
	
void CAknKeypadButton::Draw( const TRect& /*aRect*/ ) const
    {
    TRect rect = Rect();

    TAknLayoutRect centerLayout;
    centerLayout.LayoutRect( rect,
        AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() );
    TRect innerRect = centerLayout.Rect();

    CWindowGc& gc = SystemGc();
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();

 	TAknsItemID frameId = KAknsIIDQsnFrKeypadButtonNormal;

    if ( iButtonPressed )
    	{
        frameId = KAknsIIDQsnFrKeypadButtonPressed;
    	}
    else if ( IsDimmed())
        {
    	frameId = KAknsIIDQsnFrKeypadButtonInactive;
        }
        
    iBgContext->SetFrame( frameId );
    iBgContext->SetCenter( frameId );
    iBgContext->SetFrameRects( rect, innerRect );

    if ( !AknsDrawUtils::Background( skin, iBgContext, NULL, gc, rect, KAknsDrawParamNoClearUnderImage ) )
        {
        gc.SetBrushColor( KRgbRed );
        gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
        gc.DrawRect( rect );
        }
    gc.SetBrushStyle( CGraphicsContext::ENullBrush );


	CAknButtonState* state = State();
	TBool landscape = Layout_Meta_Data::IsLandscapeOrientation();
    
    // Draw left text
    TAknEditingState editingState = iKeypad->State();
    
    TAknTextComponentLayout leftLayout;
    leftLayout = AknLayoutScalable_Apps::cell_vitu2_itu_pane_t1( landscape ? 3 : 0  );
        
 	DrawText(gc, state->Text(), leftLayout, 1);	
 	
 	// Draw right text
 	
 	TAknTextComponentLayout rightLayout = AknLayoutScalable_Apps::cell_vitu2_itu_pane_t2( landscape ? 2 : 0 );
 	
 	if (editingState == EMultitapLower && iLowerText)
 		{
 		DrawText(gc, *iLowerText, rightLayout, 0);
 		}
 	else if ( (editingState == EMultitapUpper || 
 	           editingState == EMultitapShifted || editingState == EQwertyShift) 
 	           && iUpperText)
 		{
 		DrawText(gc, *iUpperText, rightLayout, 0);
 		}
    }




void CAknKeypadButton::DrawText( CWindowGc& aGc, const TDesC& aText, TAknTextComponentLayout& aLayout, TInt aMargin ) const
    {
    TAknLayoutText layoutText;
    layoutText.LayoutText(Rect(), aLayout.LayoutLine() );
    
    const CFont* font = layoutText.Font();
    TRect textRect = layoutText.TextRect();
    
    aGc.UseFont( font );
    
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
	TRgb color( layoutText.Color() );
	
    if ( IsDimmed() )
        {
        color = iEikonEnv->ControlColor( EColorButtonText, *this );
        color.SetAlpha( 77 );
        }
    else if ( iButtonPressed )
        {
        color = iEikonEnv->ControlColor( EColorButtonTextPressed, *this );
        }
    else
        {
        color = iEikonEnv->ControlColor( EColorButtonText, *this );
        }
    aGc.SetPenColor( color);
    
    // NOTE: Layout data not correct, add some space for text
    textRect.iBr.iX += aMargin;
    textRect.iTl.iX -= aMargin;
    	
    
    // buffer for visually ordered text
    TBuf<255 + KAknBidiExtraSpacePerLine> visualText; 
    TInt clipWidth = textRect.Width();

    // bidi processing - using AknBidiTextUtils.
    AknBidiTextUtils::ConvertToVisualAndClip(
        aText,
        visualText,
        *font,
        clipWidth,
        clipWidth );

    TInt baselineOffset = 0;
    switch ( iVerticalAlignment )
        {
        case ETop:
            baselineOffset = font->AscentInPixels();
            break;

        case EBottom:
            baselineOffset = textRect.Height();
            break;

        default:  // centered
            baselineOffset = font->AscentInPixels() +
                           ( textRect.Height() - font->AscentInPixels() ) / 2;
        }
        
    aGc.DrawText( visualText, textRect, baselineOffset, layoutText.Align() );    
    }
