/*
* Copyright (c) 2007 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:  Model class for Control Bar component.
*
*/



#include "emailtrace.h"
#include <AknUtils.h>

#include "fscontrolbarmodel.h"
#include "fscontrolbutton.h"
#include "fsgenericpanic.h"
#include "fscontrolbuttonvisualiser.h"
#include "fslayoutmanager.h"

const TUint KDefaultSelectorSpeed = 1000;


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

// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CFsControlBarModel::CFsControlBarModel() :
    iSelectorTransitionTime( KDefaultSelectorSpeed ),
    iWidthUseDefault( ETrue ),
    iHeightUseDefault( ETrue )
    {
    FUNC_LOG;
    }


// ---------------------------------------------------------------------------
// Second phase constructor.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::ConstructL()
    {
    FUNC_LOG;
    }


// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CFsControlBarModel* CFsControlBarModel::NewL()
    {
    FUNC_LOG;
    CFsControlBarModel* self = CFsControlBarModel::NewLC();
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CFsControlBarModel* CFsControlBarModel::NewLC()
    {
    FUNC_LOG;
    CFsControlBarModel* self = new (ELeave) CFsControlBarModel;
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }


// ---------------------------------------------------------------------------
// Destructor.
// ---------------------------------------------------------------------------
//
CFsControlBarModel::~CFsControlBarModel()
    {
    FUNC_LOG;
    // <cmail> Touch
    // Buttons are now alf controls and owned by alf environment, not deleted here
    /*for( TInt i = 0; i < Count(); i++ )
        {
        delete iButtons[i];
        }*/
    // </cmail>

    iButtons.Reset();
    }


// ---------------------------------------------------------------------------
// Adds button object to collection.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::AddButtonL( CFsControlButton& aButton )
    {
    FUNC_LOG;
    iButtons.AppendL( &aButton );
    }


// ---------------------------------------------------------------------------
// Retrieves button from collection with specified index.
// ---------------------------------------------------------------------------
//
CFsControlButton* CFsControlBarModel::ButtonByIndex( TInt aIndex )
    {
    FUNC_LOG;
    CFsControlButton* result( NULL );

    if ( aIndex >= 0 && aIndex < Count() )
        {
        result = iButtons[ aIndex ];
        }

    return result;
    }


// ---------------------------------------------------------------------------
// Retrieves button from collection with specified id.
// Panics if id is incorrect.
// ---------------------------------------------------------------------------
//
CFsControlButton* CFsControlBarModel::ButtonById( TInt aId )
    {
    FUNC_LOG;
    CFsControlButton* button( NULL );
    CFsControlButton* result( NULL );
    TInt i( 0 );

    if ( ECBFirstFocusableButton == aId )
        {
        while ( Count() > i && !result )
            {
            button = ButtonByIndex( i );
            if ( button->IsVisible() && !button->IsDimmed() )
                {
                result = button;
                }
            ++i;
            }
        }
    else
        {
        while ( Count() > i && !result )
            {
            button = ButtonByIndex( i );
            if( button->Id() == aId )
                {
                result = button;
                }
            ++i;
            }

        // panic only when specified id passed by component user is searched
        if ( !result )
            {
            FsGenericPanic( EFsControlButtonIncorrectButtonId );
            }
        }

    return result;
    }


// ---------------------------------------------------------------------------
// Retrieves number of buttons in collection.
// ---------------------------------------------------------------------------
//
TInt CFsControlBarModel::Count() const
    {
    FUNC_LOG;
    return iButtons.Count();
    }


// ---------------------------------------------------------------------------
// Removes button from collection using index.
// Used function ButtonByIndex panics - see ButtonByIndex.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::RemoveButtonByIndex( TInt aIndex )
    {
    FUNC_LOG;
    delete ButtonByIndex( aIndex );
    iButtons.Remove( aIndex );
    }


// ---------------------------------------------------------------------------
// Removes button from collection using id.
// ---------------------------------------------------------------------------
//
TInt CFsControlBarModel::RemoveButtonById( TInt aId )
    {
    FUNC_LOG;
    TInt retVal( KErrNotFound );
    for ( TInt i( 0 ); Count() > i; i++ )
        {
        if( ButtonByIndex( i )->Id() == aId )
            {
            RemoveButtonByIndex( i );
            retVal = KErrNone;
            break;
            }
        }

    if ( retVal )
        {
        FsGenericPanic( EFsControlButtonIncorrectButtonId );
        }

    return retVal;
    }


// ---------------------------------------------------------------------------
// Checks if button with specified id exists in collection.
// ---------------------------------------------------------------------------
//
TBool CFsControlBarModel::ExistsButtonWithId( TInt aId )
    {
    FUNC_LOG;
    TBool result( EFalse );

    for( TInt i( 0 ); iButtons.Count() > i; i++ )
        {
        if( iButtons[i]->Id() == aId )
            {
            result = ETrue;
            break;
            }
        }

    return result;
    }


// ---------------------------------------------------------------------------
// Retrieves index of button with specified id.
// ---------------------------------------------------------------------------
//
TInt CFsControlBarModel::IndexById( TInt aButtonId )
    {
    FUNC_LOG;
    TInt result( -1 );
    TInt i( 0 );

    while ( -1 == result && Count() > i )
        {
        if( ButtonByIndex( i )->Id() == aButtonId )
            {
            result = i;
            }
        i++;
        }

    return result;
    }


// ---------------------------------------------------------------------------
// Retrieves next focusable button.
// ---------------------------------------------------------------------------
//
CFsControlButton* CFsControlBarModel::NextButton( TInt aButtonId )
    {
    FUNC_LOG;
    TInt index( -1 );
    CFsControlButton* currentBtn( ButtonById( aButtonId ) );

    // Find current button's id.
    TInt buttonId( 0 );
    while ( iButtons.Count() > buttonId )
        {
        if ( iButtons[buttonId] == currentBtn )
            {
            break;
            }
        buttonId++;
        }

    // Find the next button on right.
    TInt curPos( currentBtn->Visualiser()->Pos().Target().iX );
    TBool candidate( EFalse );
    TInt next( 0 );
    for ( TInt i( 0 ); iButtons.Count() > i; i++ )
        {
        if ( i == buttonId
            || !iButtons[i]->IsVisible()
            || iButtons[i]->IsDimmed() )
            {
            continue;
            }
        TInt btnPos( iButtons[i]->Visualiser()->Pos().Target().iX );
        if ( btnPos >= curPos )
            {
            if ( btnPos == curPos )
                {
                if ( i < buttonId )
                    {
                    continue;
                    }
                }
            if ( !candidate )
                {
                // This is the first proper candidate.
                index = i;
                next = btnPos;
                candidate = ETrue;
                }
            else if ( btnPos <= next )
                {
                // This button is closer than previously found button.
                index = i;
                next = btnPos;
                if ( btnPos == curPos )
                    {
                    break;
                    }
                }
            }
        }
    return ButtonByIndex( index );
    }


// ---------------------------------------------------------------------------
// Retrieves previous focusable button.
// ---------------------------------------------------------------------------
//
CFsControlButton* CFsControlBarModel::PrevButton( TInt aButtonId )
    {
    FUNC_LOG;
    TInt index( -1 );
    CFsControlButton* currentBtn( ButtonById( aButtonId ) );

    // Find current button's id.
    TInt buttonId( 0 );
    while ( iButtons.Count() > buttonId )
        {
        if ( iButtons[buttonId] == currentBtn )
            {
            break;
            }
        buttonId++;
        }

    // Find the next button on left.
    TInt curPos( currentBtn->Visualiser()->Pos().Target().iX );
    TBool candidate( EFalse );
    TInt next( 0 );
    for ( TInt i( iButtons.Count() - 1 ); 0 <= i; i-- )
        {
        if ( i == buttonId
            || !iButtons[i]->IsVisible()
            || iButtons[i]->IsDimmed() )
            {
            continue;
            }
        TInt btnPos( iButtons[i]->Visualiser()->Pos().Target().iX );
        if ( btnPos <= curPos )
            {
            if ( btnPos == curPos )
                {
                if ( i > buttonId )
                    {
                    continue;
                    }
                }
            if ( !candidate )
                {
                // This is the first proper candidate.
                index = i;
                next = btnPos;
                candidate = ETrue;
                }
            else if ( btnPos >= next )
                {
                // This button is closer than previously found button.
                index = i;
                next = btnPos;
                if ( btnPos == curPos )
                    {
                    break;
                    }
                }
            }
        }

    return ButtonByIndex( index );
    }


// ---------------------------------------------------------------------------
// Sets focus for control bar.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::SetFocus( TBool aState )
    {
    FUNC_LOG;
    iFocused = aState;
    }


// ---------------------------------------------------------------------------
// Retrieves focus state of control bar.
// ---------------------------------------------------------------------------
//
TBool CFsControlBarModel::IsFocused() const
    {
    FUNC_LOG;
    return iFocused;
    }


// ---------------------------------------------------------------------------
// Generates free id value for new button.
// ---------------------------------------------------------------------------
//
TInt CFsControlBarModel::GenerateButtonId()
    {
    FUNC_LOG;
    TInt result( 0 );

    for ( TInt i( 0 ); Count() > i; i++ )
        {
        if ( result == ButtonByIndex( i )->Id() )
            {
            ++result;
            }
        }

    return result;
    }


// ---------------------------------------------------------------------------
// Retrieves default bar background color.
// ---------------------------------------------------------------------------
//
const TRgb& CFsControlBarModel::BarBgColor() const
    {
    FUNC_LOG;
    return iBgColor;
    }


// ---------------------------------------------------------------------------
// Gets transition time for moving selector.
// ---------------------------------------------------------------------------
//
TInt CFsControlBarModel::SelectorTransitionTime() const
    {
    FUNC_LOG;
    return iSelectorTransitionTime;
    }


// ---------------------------------------------------------------------------
// Sets transition time for moving selector.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::SetSelectorTransitionTime( TInt aTransitionTime )
    {
    FUNC_LOG;
    iSelectorTransitionTime = aTransitionTime;
    }


// ---------------------------------------------------------------------------
// Refresh the buttons' positions.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::UpdateButtonsPositions()
    {
    FUNC_LOG;
    TSize parentSize( Size() );

    for ( TInt i( 0 ); iButtons.Count() > i; i++ )
        {
        iButtons[i]->RefreshButtonPosition( parentSize );
        }
    }

// ---------------------------------------------------------------------------
// Set new position and size
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::SetRect( const TRect& aRect )
    {
    iSize = aRect.Size();
    iWidthUseDefault = EFalse;
    iHeightUseDefault = EFalse;
    iTl = aRect.iTl;
    }

// ---------------------------------------------------------------------------
// Get top-left position of the bar
// ---------------------------------------------------------------------------
//
TPoint CFsControlBarModel::Pos() const
    {
    return iTl;
    }

// ---------------------------------------------------------------------------
// Sets width in pixels of controlbar and refreshes control.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::SetWidth( TInt aWidth )
    {
    FUNC_LOG;
    iSize.iWidth = aWidth;
    iWidthUseDefault = EFalse;
    }


// ---------------------------------------------------------------------------
// Sets height in pixels of controlbar and refreshes control.
// ---------------------------------------------------------------------------
//
void CFsControlBarModel::SetHeight( TInt aHeight )
    {
    FUNC_LOG;
    iSize.iHeight = aHeight;
    iHeightUseDefault = EFalse;
    }


// ---------------------------------------------------------------------------
// Retrieves controlbar's size in pixels.
// ---------------------------------------------------------------------------
//
TSize CFsControlBarModel::Size() const
    {
    FUNC_LOG;
    TRect layoutRect;

    if ( iWidthUseDefault || iHeightUseDefault )
        {
        TRect parentRect;
        AknLayoutUtils::LayoutMetricsRect(
            AknLayoutUtils::EScreen, parentRect );

        CFsLayoutManager::LayoutMetricsRect( parentRect,
            CFsLayoutManager::EFsLmMainSpFsCtrlbarPane, layoutRect );
        }

    return TSize(
        iWidthUseDefault ? layoutRect.Width() : iSize.iWidth,
        iHeightUseDefault ? layoutRect.Height() : iSize.iHeight );
    }

