/*
* 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:  View Manager
*
*/

// System includes
#include <startupdomainpskeys.h>
#include <AknUtils.h>
#include <AknsWallpaperUtils.h>
#include <AknSkinsInternalCRKeys.h>
#include <StringLoader.h>
#include <xnuiengine.rsg>
#include <aknnotewrappers.h>
#include <AknsConstants.h>
#include <aifwdefs.h>
#include <gfxtranseffect/gfxtranseffect.h>
#include <akntransitionutils.h>
#include <xnuiengine.rsg>

// User includes
#include "xnapplication.h"
#include "xnuiengine.h"
#include "xnproperty.h"
#include "xndomnode.h"
#include "xndomlist.h"
#include "xnnode.h"
#include "xncomposer.h"
#include "xneditor.h"
#include "xnrootdata.h"
#include "xnviewdata.h"
#include "xnappuiadapter.h"
#include "xncontroladapter.h"
#include "xnviewnodeimpl.h"
#include "xnviewadapter.h"
#include "xnodt.h"
#include "xndomdocument.h"
#include "xntype.h"
#include "xntext.h"
#include "xnpanic.h"
#include "xnmenu.h"
#include "xnmenuadapter.h"
#include "xncomponentnodeimpl.h"
#include "xnnodepluginif.h"
#include "xnoomsyshandler.h"
#include "xnbackgroundmanager.h"
#include "xneffectmanager.h"
#include "xnkeyeventdispatcher.h"

// Constants
_LIT8( KEmptyWidgetUid, "0x2001f47f" );
_LIT8( KTemplateViewUID, "0x20026f50" );

const TInt KPSCategoryUid( 0x200286E3 );
const TInt KPSCrashCountKey( 1 );     
const TInt KStabilityInterval( 60000000 ); // 1 minute
const TInt KActivationCompleteInterval( 2000000 ); // 2s
const TInt KCrashRestoreDefaultTreshold( 3 );
const TInt KCrashRestoreAllTreshold( 4 );
const TInt KCrashRestoreRomTreshold( 5 );
const TInt KCrashRestoreViewsTreshold( 6 );

// ============================ LOCAL FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// BuildTriggerL
// Builds a trigger node
// -----------------------------------------------------------------------------
//
static CXnNode* BuildTriggerL( CXnUiEngine& aUiEngine,
    const TDesC8& aStringValue )
    {
    CXnNode* node = CXnNode::NewL();
    CleanupStack::PushL( node );

    CXnType* type = CXnType::NewL( XnPropertyNames::action::KTrigger );
    CleanupStack::PushL( type );

    CXnNodeImpl* impl = CXnNodeImpl::NewL( type );
    CleanupStack::Pop( type );

    node->SetImpl( impl );
    node->SetUiEngine( aUiEngine );

    CXnDomStringPool* sp( aUiEngine.ODT()->DomDocument().StringPool() );

    CXnProperty* name = CXnProperty::NewL(
        XnPropertyNames::action::trigger::KName, aStringValue,
        CXnDomPropertyValue::EString, *sp );

    CleanupStack::PushL( name );
    node->SetPropertyL( name );
    CleanupStack::Pop( name );

    CXnProperty* value = CXnProperty::NewL(
        XnPropertyNames::action::KValue,
        KNullDesC8, CXnDomPropertyValue::EString, *sp );

    CleanupStack::PushL( value );
    node->SetPropertyL( value );
    CleanupStack::Pop( value );

    CleanupStack::Pop( node ); 

    return node;
    }

// -----------------------------------------------------------------------------
// resolveIconId
// -----------------------------------------------------------------------------
//
static TAknsItemID ResolveIconId( TInt aIndex )
    {
    TAknsItemID ret( KAknsIIDNone );
    switch( aIndex )
        {
        case 0:
            {
            ret = KAknsIIDQgnHomePage11;
            }
            break;
        case 1:
            {
            ret = KAknsIIDQgnHomePage21;
            }
            break;
        case 2:
            {
            ret = KAknsIIDQgnHomePage22;
            }
            break;
        case 3:
            {
            ret = KAknsIIDQgnHomePage31;
            }
            break;
        case 4:
            {
            ret = KAknsIIDQgnHomePage32;
            }     
            break;
        case 5:
            {
            ret = KAknsIIDQgnHomePage33;
            }    
            break;
        case 6:
            {
            ret = KAknsIIDQgnHomePage41;
            }
            break;
        case 7:
            {
            ret = KAknsIIDQgnHomePage42;
            }   
            break;
        case 8:
            {
            ret = KAknsIIDQgnHomePage43;
            }   
            break;
        case 9:
            {
            ret = KAknsIIDQgnHomePage44;
            }     
            break;
        case 10:
            {
            ret = KAknsIIDQgnHomePage51;
            }     
            break;
        case 11:
            {
            ret = KAknsIIDQgnHomePage52;
            }     
            break;
        case 12:
            {
            ret = KAknsIIDQgnHomePage53;
            } 
            break;
        case 13:
            {
            ret = KAknsIIDQgnHomePage54;
            }     
            break;
        case 14:
            {
            ret = KAknsIIDQgnHomePage55;
            }
            break;
        case 15:
            {
            ret = KAknsIIDQgnHomePage61;
            }    
            break;
        case 16:
            {
            ret = KAknsIIDQgnHomePage62;
            }   
            break;
        case 17:
            {
            ret = KAknsIIDQgnHomePage63;
            }    
            break;
        case 18:
            {
            ret = KAknsIIDQgnHomePage64;
            }
            break;
        case 19:
            {
            ret = KAknsIIDQgnHomePage65;
            }
            break;            
        case 20:
            {
            ret = KAknsIIDQgnHomePage66;
            }            
            break;            
        default:
            {
            }
            break;
        }
    
    return ret;
    }

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

// -----------------------------------------------------------------------------
// CXnViewManager::NewL()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnViewManager* CXnViewManager::NewL( CXnAppUiAdapter& aAdapter )    
    {
    CXnViewManager* self = CXnViewManager::NewLC( aAdapter );
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnViewManager* CXnViewManager::NewLC( CXnAppUiAdapter& aAdapter )
    {
    CXnViewManager* self = new( ELeave ) CXnViewManager( aAdapter );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::CXnViewManager()
// C++ default constructor
// -----------------------------------------------------------------------------
//
CXnViewManager::CXnViewManager( CXnAppUiAdapter& aAdapter ) 
    : iAppUiAdapter( aAdapter ), 
      iApplicationUid( iAppUiAdapter.Application()->AppDllUid() )
    {
    }

// -----------------------------------------------------------------------------
// CXnViewManager::~CXnViewManager()
// C++ default destructor.
// -----------------------------------------------------------------------------
//
CXnViewManager::~CXnViewManager()
    {
    delete iAsyncCb;
    
    delete iStabilityTimer;
    
    iObservers.Reset();
    
    delete iRootData;
    
    delete iWidgetAmountTrigger;       

    if ( iResources )
        {
        iResources->Reset();
        }
    
    delete iResources;

    iControls.Reset();
    iAppearanceNodes.Reset();
              
    delete iComposer;
    delete iEditor;
    delete iOomSysHandler;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ConstructL()
// 2nd phase constructor
// -----------------------------------------------------------------------------
//
void CXnViewManager::ConstructL()
    {       
    iOomSysHandler = CXnOomSysHandler::NewL();
    
    // Create resource list
    iResources = new ( ELeave ) CArrayPtrSeg< CXnResource > ( 16 );
       
    const TInt KMaxUidLength( 10 );
    _LIT8( KUint, "%u" );

    TBuf8< KMaxUidLength > uid;
    uid.Format( KUint, iApplicationUid.iUid );
    
    iEditor = CXnEditor::NewL( *this, uid );

    iHspsWrapper = &iEditor->HspsWrapper();
    
    iComposer = CXnComposer::NewL( *iHspsWrapper );
           
    iAsyncCb = CPeriodic::NewL( CActive::EPriorityIdle ); 
                       
    DoRobustnessCheckL();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::LoadUiL()
// Loads the application UI and initial view
// -----------------------------------------------------------------------------
//
void CXnViewManager::LoadUiL()
    {
    iUiEngine->DisableRenderUiLC();
    
    // Load application root configuration
    iRootData = CXnRootData::NewL( *this, iApplicationUid );
           
    // Load root configuration and initial view.
    TInt err = iRootData->Load();
    
    if( err == EXnInvalidConfiguration )
        {
        // Configuration loading failed totally
        Panic( EXnInvalidConfiguration );
        }
    
    // Show the error note only once, if there are more views
    // the note should be shown from CXnRootData::RunLoadL()
    if( iRootData->PluginData().Count() == 1 )
        {        
        HandleErrorNotes( err );
        }
               
    CleanupStack::PopAndDestroy(); // DisableRenderUiLC();
    
    // Load initial view publishers    
    ActiveViewData().SetActive( ETrue );    
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ReloadUiL()
// Reloads the application UI and initial ivew
// -----------------------------------------------------------------------------
void CXnViewManager::ReloadUiL()  
    {
#ifdef _XN_PERFORMANCE_TEST_
    RDebug::Print( _L( "CXnViewManager::ReloadUiL() - start" ) );
#endif //_XN_PERFORMANCE_TEST_
    
    NotifyViewDeactivatedL( ActiveViewData() );
    
    if ( iAsyncCb->IsActive() )
        {
        iAsyncCb->Cancel();
        
        ContainerActivated( this );
        }
    
    delete iWidgetAmountTrigger;
    iWidgetAmountTrigger = NULL;
          
    // Destroy all publishers
    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
    
    for ( TInt i = 0; i < views.Count(); i++ )
        {
        CXnViewData* view = static_cast< CXnViewData* >( views[i] );
                
        view->DestroyPublishers( EAiFwSystemShutdown );        
        }
    
    // Destroy active view data
    ActiveViewData().Destroy();
         
    // Schedule application configuration destroyal
    iRootData->Destroy();
    iRootData = NULL;
       
    User::Heap().Compress();
    
    iUiReady = EFalse;
    
    LoadUiL();
    
    // Activate first view from the new configuration
    iAppUiAdapter.ViewAdapter().ActivateContainerL( ActiveViewData() );    
   
#ifdef _XN_PERFORMANCE_TEST_
    RDebug::Print( _L( "CXnViewManager::ReloadUiL() - end" ) );
#endif //_XN_PERFORMANCE_TEST_
    }

// -----------------------------------------------------------------------------
// CXnViewManager::LoadWidgetToPluginL()
//
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::LoadWidgetToPluginL( const CHsContentInfo& aContentInfo,
    CXnPluginData& aPluginData )
    {
    // Plugin must not have widget when about to add
    if ( aPluginData.Occupied() )
        {
        return KErrAlreadyExists;
        }

    CXnViewData& viewData( 
        static_cast< CXnViewData& >( *aPluginData.Parent() ) );

    TBool emptyInUse( viewData.UseEmptyWidget() );
            
    // By default widget is added to active view configuration
    const TDesC8& configurationId( viewData.ConfigurationId() );

    TInt retval( KErrGeneral );
              
    if ( emptyInUse && aPluginData.Empty() )
        {
        retval = iHspsWrapper->ReplacePluginL( 
            aPluginData.PluginId(), aContentInfo.Uid() );   
        
        if( retval == KErrDiskFull )
            {
            TRAP_IGNORE( ShowErrorL( R_QTN_HS_OPERATION_FAILED_NO_DISK ) );            
            }
        }
    else
        {
        TInt index( viewData.PluginData().Find( &aPluginData ) );
        
        CAddPluginResult* result = iHspsWrapper->AddPluginL( 
            configurationId, aContentInfo.Uid(), index );
    
        CleanupStack::PushL( result );
        
        retval = result->Status();        
        if ( retval == KErrNone )
            {
            aPluginData.SetPluginIdL( result->PluginId() );
            }
        else if( retval == KErrDiskFull )
            {
            TRAP_IGNORE( ShowErrorL( R_QTN_HS_OPERATION_FAILED_NO_DISK ) );            
            }        
        
        CleanupStack::PopAndDestroy( result ); 
        }
             
    if ( retval == KErrNone )
        {              
        iUiEngine->DisableRenderUiLC();
                                     
        NotifyConfigureWidgetL( aContentInfo, aPluginData );
    
        retval = aPluginData.Load();
        
        if ( retval == KErrNone )
            {
            UpdateCachesL();
        
            NotifyWidgetAdditionL( aPluginData );

            // Report widget amount in the view
            ReportWidgetAmountL( viewData );           
            }  
        
        // Handle the errors
        HandleErrorNotes( retval );        
        
        CleanupStack::PopAndDestroy(); // DisableRenderUiLC
        }
           
    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::UnloadWidgetFromPluginL()
//
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::UnloadWidgetFromPluginL( CXnPluginData& aPluginData, 
    TBool aForce )    
    {                  
    if ( !aForce )
        {
        if( !aPluginData.Occupied() )
            {
            // Plugin must have widget when about to remove
            return KErrNotFound;                    
            }
        if ( !aPluginData.Removable() )
            {
            // Not allowed to remove locked
            return KErrArgument;
            }
        }
    
    CXnViewData& viewData( 
        static_cast< CXnViewData& >( *aPluginData.Parent() ) );
    
    TBool emptyInUse( viewData.UseEmptyWidget() );
    
    TInt retval( KErrGeneral );
    
    // Save temporary
    TBuf8< 32 > id( aPluginData.PluginId() );
           
    if ( emptyInUse )
        {
        retval = iHspsWrapper->ReplacePluginL( 
            aPluginData.PluginId(), KEmptyWidgetUid );                       
        }
    else 
        {        
        retval = iHspsWrapper->RemovePluginL( aPluginData.PluginId() );
        }
       
    if ( retval == KErrNone )
        {
        TBool active( aPluginData.Active() );
        
        iUiEngine->DisableRenderUiLC();
        
        NotifyWidgetRemovalL( aPluginData );
                 
        aPluginData.Destroy();
        
        if ( emptyInUse )
            {
            // Write id back for for later usage
            aPluginData.SetEmptyL( id );
            }
        else
            {
            // Reorder plugindata array
            RPointerArray< CXnPluginData >& plugins( viewData.PluginData() ); 
                
            TInt index( plugins.Find( &aPluginData ) );

            plugins.Remove( index );
            plugins.Insert( &aPluginData, plugins.Count() - 1 );                                           
            }
                                                           
        UpdateCachesL();

        // Report widget amount in the view 
        ReportWidgetAmountL( viewData );
        
        if ( active )
            {            
            iUiEngine->RenderUIL();            
            }
               
        CleanupStack::PopAndDestroy(); // DisableRenderUiLC               
        }

    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ReplaceWidgetToPluginL
//
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::ReplaceWidgetToPluginL( const CHsContentInfo& aContentInfo,
    CXnPluginData& aPluginData )
    {
    TInt retval( KErrNone );
    
    retval = iHspsWrapper->ReplacePluginL( aPluginData.PluginId(),
                                           aContentInfo.Uid() );

    if ( retval == KErrNone )
        {
        iUiEngine->DisableRenderUiLC();
        
        NotifyWidgetRemovalL( aPluginData );

        TBuf8< 32 > id( aPluginData.PluginId() );
        TBuf8< 32 > uid( aContentInfo.Uid() );
        
        aPluginData.Destroy();
                        
        UpdateCachesL();
        aPluginData.SetPluginIdL( id );
        
        NotifyConfigureWidgetL( aContentInfo, aPluginData );
        
        retval = aPluginData.Load();
        
        if ( retval == KErrNone )
            {
            UpdateCachesL();
            
            // notify addition if not replaced with empty widget
            // NotifyWidgetAdditionL will call RenderUIL()
            if( uid != KEmptyWidgetUid )
                {
                NotifyWidgetAdditionL( aPluginData );
                }
            else
                {
                if( aPluginData.Active() )
                    {
                    iUiEngine->RenderUIL();
                    }
                }            
            }
        
        // Handle the errors
        HandleErrorNotes( retval );
        
        CleanupStack::PopAndDestroy(); // DisableRenderUiLC
        }
    
    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ODT()
// Get the ODT
// -----------------------------------------------------------------------------
//
CXnODT* CXnViewManager::ODT() const
    {
    return iRootData->ODT();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::RootNode()
// Finds the root node 
// -----------------------------------------------------------------------------
//
CXnNode* CXnViewManager::RootNode() const
    {
    return iRootData->RootNode();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ViewNode()
// Finds the view node from active view data
// -----------------------------------------------------------------------------
//
CXnNode* CXnViewManager::ViewNode() const
    {
    return ActiveViewData().ViewNode();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::Parser()
// Gets ODT parser
// -----------------------------------------------------------------------------
//
CXnODTParser& CXnViewManager::Parser() const
    {
    return iRootData->Parser();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::EcomHandler()
// Gets Ecom handler
// -----------------------------------------------------------------------------
//
CXnEcomHandler& CXnViewManager::EcomHandler() const
    {
    return iRootData->EcomHandler();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::Controls()
// Finds the controls from active view data
// -----------------------------------------------------------------------------
//
const RPointerArray< CXnControlAdapter >& CXnViewManager::Controls() const
    {
    return iControls;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::PluginNodes()
// Finds the plugin nodes from active view data
// -----------------------------------------------------------------------------
//
RPointerArray< CXnNode >& CXnViewManager::PluginNodes() const
    {
    // These must be fetched from layout tree to get correct order of plugins
    CXnViewData& activeViewData( ActiveViewData() );

    // Get first plugin data
    CXnPluginData* pluginData( activeViewData.PluginData()[0] );
    CXnNode* parent( pluginData->Owner()->LayoutNode()->Parent() );

    // This assumes that the parent has only "plugin" nodes as its children
    RPointerArray< CXnNode >& children( parent->Children() );

    return children;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::PluginDataL()
// 
// -----------------------------------------------------------------------------
//
void CXnViewManager::PluginDataL( RPointerArray< CXnPluginData >& aList, 
    TBool aGlobal ) const
    {
    if ( aGlobal )
        {
        RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
        
        for ( TInt i = 0; i < views.Count(); i++ )
            {
            RPointerArray< CXnPluginData >& plugins( views[i]->PluginData() );
            
            for ( TInt j = 0; j < plugins.Count(); j++ )
                {
                aList.AppendL( plugins[ j ] );
                }
            }            
        }
    else
        {
        RPointerArray< CXnPluginData >& 
            plugins( ActiveViewData().PluginData() ); 

        for ( TInt j = 0; j < plugins.Count(); j++ )
            {
            aList.AppendL( plugins[ j ] );
            }        
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::PluginDataL()
// Returns list of plugins from all views or from the defined view
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::PluginDataL( const TDesC8& aViewId, 
    RPointerArray< CXnPluginData >& aList ) const
    {
    TInt err( KErrNone );
    TBool found( EFalse );
    
    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
    
    for ( TInt i = 0; i < views.Count(); i++ )
        {
        if ( !aViewId.Length() || views[i]->PluginId().Compare( aViewId ) == 0 )
            {
            found = ETrue;
            RPointerArray< CXnPluginData >& plugins( views[i]->PluginData() );
            
            for ( TInt j = 0; j < plugins.Count(); j++ )
                {
                aList.AppendL( plugins[ j ] );
                }
            }
        }      
    if ( !found )
        {
        // View not found
        err = KErrArgument;
        }
    
    return err;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::Resources()
// Finds the resources from the active view data
// -----------------------------------------------------------------------------
//
CArrayPtrSeg< CXnResource >& CXnViewManager::Resources() const
    {
    return *iResources;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::AppearanceNodes()
//
// -----------------------------------------------------------------------------
//
RPointerArray< CXnNode >& CXnViewManager::AppearanceNodes() const
    {
    return iAppearanceNodes;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ViewData()
// Finds a view data based on a view node
// -----------------------------------------------------------------------------
//
CXnViewData* CXnViewManager::ViewData( CXnNode& aNode ) const
    {    
    if ( !aNode.ViewNodeImpl() )
        {
        return NULL;
        }

    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
    
    for ( TInt i = 0; i < views.Count(); i++ )
        {
        if ( views[i]->Occupied() )
            {
            if ( views[i]->Node()->LayoutNode() == &aNode )
                {
                return static_cast< CXnViewData* >( views[ i ] );                
                }
            }
        }

    return NULL;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ActiveAppData()
// Gets the active app data
// -----------------------------------------------------------------------------
//
CXnRootData& CXnViewManager::ActiveAppData() const
    {
    return *iRootData;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ActiveViewData()
// Gets the active view data
// -----------------------------------------------------------------------------
//
CXnViewData& CXnViewManager::ActiveViewData() const
    {
    return iRootData->ActiveViewData();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::PreviousViewData()
// Gets the previous view data 
// -----------------------------------------------------------------------------
//
CXnViewData& CXnViewManager::PreviousViewData() const
    {
    return iRootData->PreviousViewData();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NextViewData()
// Gets the next view data 
// -----------------------------------------------------------------------------
//
CXnViewData& CXnViewManager::NextViewData() const
    {
    return iRootData->NextViewData();
    }
    
// -----------------------------------------------------------------------------
// CXnViewManager::ActivateNextViewL()
// Activates the next view
// -----------------------------------------------------------------------------
//
void CXnViewManager::ActivateNextViewL( TInt /*aEffectId*/ )
    { 
    CXnViewData& next( NextViewData() );
    
    if ( !next.Occupied() )
        {    
        TInt err( next.Load() );
        
        if ( err )
            {
            HandleErrorNotes( err );            
            return;            
            }
        }
        
    // Activate view
    if ( next.Occupied() && !next.Active() )
        {
        iAppUiAdapter.ViewAdapter().ActivateContainerL( 
            next, EFalse, KGfxContextActivateNextView );                        
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ActivatePreviousViewL()
// Activates the previous view
// -----------------------------------------------------------------------------
//
void CXnViewManager::ActivatePreviousViewL( TInt /*aEffectId*/ )
    {    
    CXnViewData& prev( PreviousViewData() );

    if ( !prev.Occupied() )
        {
        TInt err( prev.Load() );
        
        if ( err )
            {
            HandleErrorNotes( err );            
            return;            
            }    
        }
        
    // Activate view
    if ( prev.Occupied() && !prev.Active() )
        {
        iAppUiAdapter.ViewAdapter().ActivateContainerL( 
            prev, EFalse, KGfxContextActivatePrevView );                                
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::AddViewL()
// Adds a new view based on info
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::AddViewL( const CHsContentInfo& aInfo )
    {    
    if ( iRootData->PluginData().Count() >= iRootData->MaxPages() )
        {
        return KErrGeneral;
        }

    // Add new view (template view) to hsps
    CAddPluginResult* result = iHspsWrapper->AddPluginL( 
        iRootData->ConfigurationId(), aInfo.Uid(),
        ViewIndex() + 1 ); 
    CleanupStack::PushL( result );

    TInt retval( result->Status() );
    
    if( retval == KErrDiskFull )
        {
        TRAP_IGNORE( ShowErrorL( R_QTN_HS_OPERATION_FAILED_NO_DISK ) );
        }        
    else if ( retval == KErrNone )
        {                             
        // Create new view        
        CXnViewData* newView = CXnViewData::NewLC( *iRootData );    
        
        newView->SetPluginIdL( result->PluginId() );
        
        newView->SetOwner( iRootData->Node() );
        
        retval = newView->Load();
                
        HandleErrorNotes( retval );
                
        if ( newView->Occupied() )
            {
            // Load succeed, add the new view behind the current view               
            RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
            
            TInt index( views.Find( &ActiveViewData() ) );
            
            views.InsertL( newView, index + 1 );
            
            // Root data owns the new view now
            CleanupStack::Pop( newView );            

            // Inform observers about added view
            NotifyViewAdditionL( *newView );
            
            UpdatePageManagementInformationL();
            
            iUiEngine->RenderUIL();
            }
        else
            {                                  
            // creation failed, remove it from hsps
            iHspsWrapper->RemovePluginL( result->PluginId() );
            
            // ... and destroy it
            CleanupStack::PopAndDestroy( newView );            
            
            retval = KErrGeneral;

            }
        }

    CleanupStack::PopAndDestroy( result );   
    
    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::AddViewL()
// Adds a new view
// -----------------------------------------------------------------------------
//
void CXnViewManager::AddViewL( TInt aEffectId )
    {
    if ( iRootData->PluginData().Count() >= iRootData->MaxPages() ) 
        { 
        TRAP_IGNORE( ShowErrorL( R_QTN_HS_MAX_AMOUNT_OF_PAGES_NOTE ) );
        
        return;        
        }

    // Add new view (template view) to hsps
    CAddPluginResult* result = iHspsWrapper->AddPluginL( 
        iRootData->ConfigurationId(), KTemplateViewUID,
        ViewIndex() + 1 ); 
    CleanupStack::PushL( result );
        
    TInt status( result->Status() );
    
    if( status == KErrDiskFull )
        {
        TRAP_IGNORE( ShowErrorL( R_QTN_HS_OPERATION_FAILED_NO_DISK ) );
        }            
    else if ( status == KErrNone )
        {                             
        // Create new view        
        CXnViewData* newView = CXnViewData::NewLC( *iRootData );    
        
        newView->SetPluginIdL( result->PluginId() );
        
        newView->SetOwner( iRootData->Node() );
        
        status = newView->Load();
        
        HandleErrorNotes( status );        
                
        if ( newView->Occupied() )
            {
            // Start transition effect
            if( aEffectId )
                {
                iAppUiAdapter.EffectManager()->BeginFullscreenEffectL(
                        aEffectId, ActiveViewData() );        
                }

            // Load succeed, add the new view behind the current view               
            RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
            
            TInt index( views.Find( &ActiveViewData() ) );
            
            views.InsertL( newView, index + 1 );
            
            // Root data owns the new view now
            CleanupStack::Pop( newView );
            
            // Activate view
            iAppUiAdapter.ViewAdapter().ActivateContainerL( *newView, ETrue );
            
            // Inform observers about added view
            NotifyViewAdditionL( *newView );
            }
        else
            {                      
            // creation failed, remove it from hsps
            iHspsWrapper->RemovePluginL( result->PluginId() );
            
            // ... and destroy it
            CleanupStack::PopAndDestroy( newView );            
            }
        }

    CleanupStack::PopAndDestroy( result );       
    }

// -----------------------------------------------------------------------------
// CXnViewManager::RemoveFaultyView()
// Removes a view which has failed to load
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::RemoveFaultyView( CXnViewData* aViewData )
    {
    TInt retval( KErrGeneral );
    
    if( aViewData )
        {
        RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
        
        TInt index( views.Find( aViewData ) );
        
        if ( index != KErrNotFound )
            {
            // Remove instance from the views array
            views.Remove( index );

            // Remove the faulty view configuration from the root configuration in HSPS
            TRAP_IGNORE( iHspsWrapper->RemovePluginL( aViewData->PluginId() ) ); 
                                                   
            // Update MSK from the remaining views
            TRAP_IGNORE( UpdatePageManagementInformationL() );
            
            TRAP_IGNORE( iUiEngine->RenderUIL() );
            
            retval = KErrNone;
            }
        }
    
    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::RemoveViewL()
// Removes view based info
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::RemoveViewL( const CHsContentInfo& aInfo )
    {
    TInt retval( KErrGeneral );
    
    if ( iRootData->PluginData().Count() <= 1 )
        {
        // Only one page left, not allowed to remove
        return retval;        
        }
    
    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );

    for ( TInt i = 0; i < views.Count(); i++ )
        {
        CXnViewData* view( static_cast< CXnViewData* >( views[i] ) );
        
        if ( view->PluginId() == aInfo.PluginId() )
            {
            if ( !view->Removable() )
                {
                return KErrArgument;
                }
            
            if ( view->Active() )
                {
                // Destroy publishers here, must be plugin shutdown
                view->DestroyPublishers( EAiFwPluginShutdown );
            
                // Activate the next view, or first if in the last view 
                CXnViewData& next( NextViewData() );
                
                iAppUiAdapter.ViewAdapter().ActivateContainerL( next );
                }

            // Remove wallpaper from cache
            iAppUiAdapter.ViewAdapter().BgManager().DeleteWallpaper( *view );

            retval = iHspsWrapper->RemovePluginL( view->PluginId() );
            
            // Notify observers of view list change
            TRAP_IGNORE( NotifyViewRemovalL( *view ) );

            iRootData->DestroyViewData( view );
                                                                   
            // Need to update after view is removed
            UpdatePageManagementInformationL();                
                                   
            break;
            }
        }
    
    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::RemoveViewL()
// Removes active view if more than one view.
// -----------------------------------------------------------------------------
//
void CXnViewManager::RemoveViewL( TInt aEffectId )
    {   
    if ( iRootData->PluginData().Count() <= 1 || 
        !ActiveViewData().Removable() )
        {
        // Only one page left, this should not happen,  
        // or active view is not removable
        return;        
        }
          
    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
    
    TInt index( views.Find( &ActiveViewData() ) );
           
    CAknQueryDialog* query = CAknQueryDialog::NewL(); 
    query->PrepareLC( R_YES_NO_HS_REMOVE_VIEW );
    
    HBufC* queryText( StringLoader::LoadLC( R_QTN_HS_DELETE_PAGE ) ); 
    
    query->SetPromptL( queryText->Des() );
    
    CleanupStack::PopAndDestroy( queryText );

    if ( query->RunLD() )
        { 
        // Start transition effect
        if( aEffectId )
            {
            iAppUiAdapter.EffectManager()->BeginFullscreenEffectL(
                    aEffectId, ActiveViewData() );        
            }

        // Activate the next view, or first if in the last view 
        CXnViewData& next( NextViewData() );

        if ( !next.Occupied() )
            {
            next.Load();
            }

        CXnViewData* view( static_cast< CXnViewData* >( views[ index ] ) );
        
        // Destroy publishers here, must be plugin shutdown
        view->DestroyPublishers( EAiFwPluginShutdown );
        
        iAppUiAdapter.ViewAdapter().ActivateContainerL( next );
                        
        // Remove wallpaper from cache
        iAppUiAdapter.ViewAdapter().BgManager().DeleteWallpaper( *view );

        // Remove plugin from HSPS
        iHspsWrapper->RemovePluginL( view->PluginId() );
        
        // Notify observers of view list change
        TRAP_IGNORE( NotifyViewRemovalL( *view ) );


        iRootData->DestroyViewData( view );
        
        // Need to update after view is removed
        UpdatePageManagementInformationL();        
        }       
    }

// -----------------------------------------------------------------------------
// CXnViewManager::AddObserver()
//
// -----------------------------------------------------------------------------
//
void CXnViewManager::AddObserver( const MXnViewObserver& aObserver )
    {
    TInt index( iObservers.Find( &aObserver ) );

    if ( index == KErrNotFound )
        {
        iObservers.Append( &aObserver );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::RemoveObserver()
//
// -----------------------------------------------------------------------------
//
void CXnViewManager::RemoveObserver( const MXnViewObserver& aObserver )
    {
    TInt index( iObservers.Find( &aObserver ) );

    if ( index != KErrNotFound )
        {
        iObservers.Remove( index );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ActivateAppL()
// Activates application configuration
// -----------------------------------------------------------------------------
TInt CXnViewManager::ActivateAppL( const TDesC8& aPluginUid )
    {
    if ( aPluginUid == KNullDesC8 )
        {
        return KErrArgument;
        }

    if ( iRootData->PluginUid().CompareF( aPluginUid ) == 0 )
        {
        // Nothing to do
        return KErrNone;
        }
    
    return iHspsWrapper->SetAppConfigurationL( aPluginUid );
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ActivateViewL()
// Activates view
// -----------------------------------------------------------------------------
TInt CXnViewManager::ActivateViewL( const TDesC8& aPluginId )
    {
    if ( aPluginId == KNullDesC8 )
        {
        return KErrArgument;
        }
           
    CXnViewData& current( ActiveViewData() );
       
    if ( current.PluginId() == aPluginId )
        {
        // Nothing to do
        return KErrNone;
        }

    TInt retval( KErrNotFound );
    
    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
        
    for ( TInt i = 0; i < views.Count(); i++ )
        {
        CXnViewData* view( static_cast< CXnViewData* >( views[ i ] ) );

        if( view->Occupied() && view->PluginId() == aPluginId )
            {
            iAppUiAdapter.ViewAdapter().ActivateContainerL( *view );
            
            retval = KErrNone;
            
            break;
            }
        }
    
    return retval;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ViewAmount()
// Gets current view amount
// -----------------------------------------------------------------------------
TInt CXnViewManager::ViewAmount() const
    {
    return iRootData->PluginData().Count();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ViewIndex()
// Gets index of current view
// -----------------------------------------------------------------------------
TInt CXnViewManager::ViewIndex() const
    {
    TInt index( KErrNotFound );
    CXnViewData* view = &( ActiveViewData() );
    RPointerArray< CXnPluginData >& views( iRootData->PluginData() );
    index = views.Find( view );
    return index;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::MaxPages()
// Gets the maximum allowed page count for this app configuration
// -----------------------------------------------------------------------------
//
TInt CXnViewManager::MaxPages() const
    {
    return iRootData->MaxPages();
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyContainerChangedL()
// Notifies container is changed, this is called always by CXnViewAdapter
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyContainerChangedL( CXnViewData& aViewToActivate )
    {
    iAsyncCb->Cancel();
    
    CXnViewData& viewToDeactivate( ActiveViewData() );
    
    TInt err( KErrNone );
        
    if ( &aViewToActivate != &viewToDeactivate )
        {               
        NotifyViewDeactivatedL( viewToDeactivate );
                      
        err = viewToDeactivate.SetActive( EFalse );
        aViewToActivate.SetActive( ETrue );
                                                        
        // Cache update is needed after view activation
        UpdateCachesL();               
        }
    else
        {
        // Activate first view
        err = aViewToActivate.SetActive( ETrue );

        // Cache update is needed after view activation
        UpdateCachesL();
        
        // Schedule remaining views loading
        iRootData->LoadRemainingViews();
        }
    
    HandleErrorNotes( err );         
               
    NotifyViewActivatedL( aViewToActivate );           
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyAllViewsLoadedL()
// Notifies that all views included in root configuration are loaded
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyAllViewsLoadedL()
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyAllViewsLoadedL();
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::PublishersReadyL()
// Notifies that aViewData activation is complete
// -----------------------------------------------------------------------------
//
void CXnViewManager::PublishersReadyL( CXnViewData& aViewData, TInt aResult )
    {
    if ( !aViewData.Active() )
        {
        return;
        }
           
    iAsyncCb->Cancel();
    
    TCallBack cb( ContainerActivated, this ) ;
    
    iAsyncCb->Start( KActivationCompleteInterval, 0, cb ); 
                     
    if ( !iUiReady )
        {
        iAppUiAdapter.HandleUiReadyEventL();
        iUiReady = ETrue;
        }
    
    if ( aResult == KErrNoMemory )
        {
        ShowErrorL( R_QTN_HS_HS_MEMORY_FULL );
        }
    else if ( aResult == KXnErrWidgetPluginFailure )
        {
        ShowErrorL( R_QTN_HS_ERROR_WIDGETS_REMOVED );
        }       
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ContainerActivated()
// Notifies that a container activation is complete
// -----------------------------------------------------------------------------
//
/* static */ TInt CXnViewManager::ContainerActivated( TAny* aAny )
    {
    CXnViewManager* self = static_cast< CXnViewManager* >( aAny );
    
    self->iAsyncCb->Cancel();
    
    CXnViewData& active( self->ActiveViewData() );
    
    TRAP_IGNORE( self->iHspsWrapper->SetActivePluginL( active.PluginId() ) );

    CXnBackgroundManager& bg( self->iAppUiAdapter.ViewAdapter().BgManager() ); 
        
    TRAP_IGNORE( bg.StoreWallpaperL() );

    self->NotifyContainerActivatedL( active );
    
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyViewActivatedL()
// Notifies view is activated
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyViewActivatedL( const CXnViewData& aViewData )
    {
    // Report widget amount in the view
    ReportWidgetAmountL( aViewData );

    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyViewActivatedL( aViewData );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyViewDeactivatedL()
// Notifies view is deactivated
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyViewDeactivatedL( const CXnViewData& aViewData )
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyViewDeactivatedL( aViewData );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyViewAdditionL()
// Notifies view is added
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyViewAdditionL( const CXnViewData& aViewData )
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyViewAdditionL( aViewData );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyViewRemovalL()
// Notifies view is removed
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyViewRemovalL( const CXnViewData& aViewData )
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyViewRemovalL( aViewData );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyConfigureWidgetL()
// Notifies to configure widget
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyConfigureWidgetL( const CHsContentInfo& aContentInfo,
    CXnPluginData& aPluginData )
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyConfigureWidgetL( aContentInfo, aPluginData );
        }    
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyWidgetAdditionL()
// Notifys widget is added
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyWidgetAdditionL( const CXnPluginData& aPluginData )
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyWidgetAdditionL( aPluginData );
        }
    
    if ( aPluginData.Active() )
        {
        // Update UI appearance after active view configuration is changed
        iUiEngine->RenderUIL();
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyWidgetRemovalL()
// Notifys widget is removed
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyWidgetRemovalL( const CXnPluginData& aPluginData )
    {
    // This loop is intend to go from "count - 1 to 0", because CXnEditor is
    // the first registered observer and it must be notified as the last one
    for ( TInt i = iObservers.Count() - 1; i >= 0 ; i-- )
        {
        iObservers[i]->NotifyWidgetRemovalL( aPluginData ); 
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::NotifyContainerActivatedL()
// Notifies view container is activated
// -----------------------------------------------------------------------------
//
void CXnViewManager::NotifyContainerActivatedL( const CXnViewData& aViewData )
    {
    for ( TInt i = 0; i < iObservers.Count(); i++ )
        {
        iObservers[i]->NotifyContainerActivatedL( aViewData );
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::UpdateCachesL()
//
// -----------------------------------------------------------------------------
//
void CXnViewManager::UpdateCachesL()
    {
    CXnViewData& activeViewData( ActiveViewData() );
    iControls.Reset();
    activeViewData.ControlsL( iControls );
    iAppearanceNodes.Reset();
    activeViewData.AppearanceNodesL( iAppearanceNodes );
    iResources->Reset();
    activeViewData.ResourcesL( *iResources );
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ReportWidgetAmountL()
//
// -----------------------------------------------------------------------------
//
void CXnViewManager::ReportWidgetAmountL( const CXnViewData& aViewData )
    {
    CXnNode* node( aViewData.ViewNode() );

    if ( !iWidgetAmountTrigger )
        {
        iWidgetAmountTrigger = BuildTriggerL( *iUiEngine,              
            XnPropertyNames::action::trigger::name::KWidgetAmount );
        }

    RPointerArray< CXnPluginData >& plugins( aViewData.PluginData() );
    TInt max( plugins.Count() );
    TInt count( 0 );

    for ( TInt i = 0; i < plugins.Count(); i++ )
        {
        CXnPluginData* plugin( plugins[i] );
        
        if ( plugin->Occupied() )
            {
            if( plugin->Removable() )
                {
                count++;
                }
            else
                {
                // non-removable widget consumes max amount
                max--;
                }                      
            }
        }

    CXnProperty* prop(
        iWidgetAmountTrigger->GetPropertyL( XnPropertyNames::action::KValue ) );

    if ( prop )
        {
        if ( count == max )
            {
            // All plugins occupied, report max widget amount reached
            _LIT8( KMax, "max" );
            
            static_cast< CXnDomPropertyValue* >(
                prop->Property()->PropertyValueList().Item( 0 ) )
                ->SetStringValueL( CXnDomPropertyValue::EString, KMax() );
            }
        else
            {
            // Report number of widgets
            TBuf8< 8 > value;
            
            value.AppendNum( count );
            
            static_cast< CXnDomPropertyValue* >(
                prop->Property()->PropertyValueList().Item( 0 ) )
                ->SetStringValueL( CXnDomPropertyValue::EString, value );
            }
        }

    node->ReportXuikonEventL( *iWidgetAmountTrigger );
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ShowErrorL
//
// -----------------------------------------------------------------------------
//
void CXnViewManager::ShowErrorL( TInt aResource ) const
    {       
    if ( aResource == R_QTN_HS_HS_MEMORY_FULL )
        {
        iOomSysHandler->HandlePotentialOomL();
        }
    else
        {
        HBufC* msg( StringLoader::LoadLC( aResource ) ); 
    
        CAknErrorNote* note = new ( ELeave ) CAknErrorNote;                       
        note->ExecuteLD( *msg );
                       
        CleanupStack::PopAndDestroy( msg );             
        }    
    }

// -----------------------------------------------------------------------------
// CXnViewManager::HandleErrorNotes
//
// -----------------------------------------------------------------------------
//
void CXnViewManager::HandleErrorNotes( const TInt aError ) const
    {
    switch( aError )
        {
        case KErrNoMemory:            
            TRAP_IGNORE( ShowErrorL( R_QTN_HS_HS_MEMORY_FULL ) );
            break;
            
        case KXnErrViewPluginFailure:
        case KXnErrWidgetPluginFailure:            
            TRAP_IGNORE( ShowErrorL( R_QTN_HS_ERROR_WIDGETS_REMOVED ) );
            break;
            
        default:
            break;
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::OOMSysHandler
//
// -----------------------------------------------------------------------------
//
CXnOomSysHandler& CXnViewManager::OomSysHandler() const
    {
    return *iOomSysHandler;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::UpdatePageManagementInformationL()
// -----------------------------------------------------------------------------
//
void CXnViewManager::UpdatePageManagementInformationL()
    {
    // Update MSK info
    // Obtain menu bar
    CXnNode* menuBar( iUiEngine->MenuBarNode() );

    if ( menuBar )
        {
        // Get object implementing MXnMenuInterface
        XnMenuInterface::MXnMenuInterface* menuIf( NULL );
        XnComponentInterface::MakeInterfaceL( menuIf, menuBar->AppIfL() );
        
        if ( menuIf )
            {
            // Get count of views in array and index of actual view
            TInt count( ViewAmount() );
            TInt current( ViewIndex() + 1 );

            // Update MSK icon
            /*
            TInt index = ResolveIconIndex( count, current );
            menuIf->SetSoftKeyImageL( KSkinIds[index],
                                      KNullDesC, 
                                      0,
                                      0,
                                      XnMenuInterface::MXnMenuInterface::ECenter, 
                                      ETrue );
            */
            TInt index = ResolveIconIndex( count, current );
            TAknsItemID iconId = ResolveIconId( index );
            menuIf->SetSoftKeyImageL( iconId,
                                      KNullDesC, 
                                      0,
                                      0,
                                      XnMenuInterface::MXnMenuInterface::ECenter, 
                                      ETrue );            
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ResolveIconIndex
// 
// -----------------------------------------------------------------------------
TInt CXnViewManager::ResolveIconIndex( TInt aPageCount, TInt aPageNum ) const
    {
    TInt iconCount( 0 );

    // Calculate total amount of icons. Each page has a aPage amount of icons.
    for ( TInt i( aPageCount ); 0 < i; i-- )
        {
        iconCount += i;
        }

    TInt index( iconCount - aPageCount + aPageNum - 1 );

    return index;
    }

// -----------------------------------------------------------------------------
// CXnViewManager::SystemStabileTimerCallback 
// -----------------------------------------------------------------------------
TInt CXnViewManager::SystemStabileTimerCallback( TAny* aAny )
    {
    CXnViewManager* self = static_cast<CXnViewManager*>( aAny );
    
    self->ResetCrashCount();

    if( self->iStabilityTimer )
        {
        self->iStabilityTimer->Cancel();
        }    
    
    return KErrNone;    
    }

// -----------------------------------------------------------------------------
// CXnViewManager::ResetCrashCount 
//
// -----------------------------------------------------------------------------
void CXnViewManager::ResetCrashCount()
    {
    RProperty::Set( TUid::Uid( KPSCategoryUid ), KPSCrashCountKey, 0 );    
    }

// -----------------------------------------------------------------------------
// CXnViewManager::DoRobustnessCheckL
//
// -----------------------------------------------------------------------------
void CXnViewManager::DoRobustnessCheckL()
    {
    TInt crashCount = 0;
    
    RProperty::Get( TUid::Uid( KPSCategoryUid ),
                    KPSCrashCountKey,
                    crashCount );    
    if( crashCount == KCrashRestoreDefaultTreshold )
        {
        // Try to activate another root configuration with a licensee default status
        iHspsWrapper->RestoreDefaultConfL();
        
        CAknQueryDialog* query = CAknQueryDialog::NewL();
        query->PrepareLC( R_HS_CONTENT_REMOVED_VIEW );

        HBufC* queryText( StringLoader::LoadLC( R_HS_ERROR_CONTENT_REMOVED ) );    
        query->SetPromptL( queryText->Des() );    
        CleanupStack::PopAndDestroy( queryText );

        query->RunLD();
        }
    else if( crashCount == KCrashRestoreAllTreshold )
        {                 
        // Reinstall all plugins from the ROM, UDA and eMMC drives
        iHspsWrapper->RestoreAllConfL();                           
        }
    else if( crashCount == KCrashRestoreRomTreshold )
        {
        // Reinstall from the ROM drive only
        iHspsWrapper->RestoreRomConfL();                         
        }
    else if( crashCount >= KCrashRestoreViewsTreshold )
        {
        // Remove all the Homescreen pages and widgets        
        iHspsWrapper->RestoreViewsL();
                 
        ResetCrashCount();
        return;
        }
    
    if( crashCount > 0 )
        {        
        // Start stability timer to ensure that
        // if system is stabile at least KStabilityInterval
        // then crash count is reset to 0. 
        iStabilityTimer = CPeriodic::NewL( CActive::EPriorityStandard );
        iStabilityTimer->Start( KStabilityInterval,
                                KStabilityInterval,
                                TCallBack( SystemStabileTimerCallback, this ) );
        }           
    }

// End of file
