/*
* 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:   AlfEffectUtils contains small classes that enable layout switch and transition effects.
*
*/
#include <e32cmn.h>
#include <s32mem.h>
#include "alfeffectutils.h"
#include <akntransitionutils.h>
#include <alflogger.h>

// Delay after which first end check is performed.
const TInt KRosterFreezeEndTimeoutInMs = 100;
// Interval between end checks.
const TInt KRosterFreezeEndIntervalInMs = 50;
// Maximum amount of end checks to be performed. 
// This can be lower, should be visible enough to see, if heuristics fail.
const TInt KRosterFreezeEndAttempts = 50;
// Timeout for implicit blank off.
const TInt KAlfImplicitBlankerTimeoutInMs = 250;

// ---------------------------------------------------------
// CAlfRosterFreezeEndTimer
// ---------------------------------------------------------
//
CAlfRosterFreezeEndTimer::CAlfRosterFreezeEndTimer( CAlfBridge& aBridge )
    :CTimer ( EPriorityStandard ),
    iBridge( aBridge )
    {   
    }

void CAlfRosterFreezeEndTimer::ConstructL()
    {
    CTimer::ConstructL();
    CActiveScheduler::Add( this );
    }

CAlfRosterFreezeEndTimer* CAlfRosterFreezeEndTimer::NewL( CAlfBridge& aBridge )
    {
    CAlfRosterFreezeEndTimer* self = new ( ELeave ) CAlfRosterFreezeEndTimer( aBridge );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

CAlfRosterFreezeEndTimer::~CAlfRosterFreezeEndTimer()
    {
    Cancel();        
    }

void CAlfRosterFreezeEndTimer::Start( TTimeIntervalMicroSeconds32 aPeriod, TCallBack aCallBack  )
    {
    iCallBack = aCallBack;
    __ALFLOGSTRING("CAlfRosterFreezeEndTimer::Start");
    if (!IsActive())
        {
        iSafeCounter = 0;
        iSafeCounterDelta = Min(1, aPeriod.Int() / (KRosterFreezeEndIntervalInMs*1000));
        After( aPeriod );
        }
    }

void CAlfRosterFreezeEndTimer::RunL()
    {
    __ALFLOGSTRING("CAlfRosterFreezeEndTimer::RunL");
	
	TBool timeout = EFalse;
	
	if (iSafeCounter >= 0)	
	    {
		iSafeCounter += iSafeCounterDelta;
		if (iSafeCounter >= KRosterFreezeEndAttempts)
			{
			timeout = ETrue;
			iSafeCounter = 0;
			}
		}

	if(iSafeCounter==iSafeCounterDelta)
	    {
        iBridge.iHuiEnv->SetRefreshMode(EHuiRefreshModeManual);
	    }
	
    if (!iBridge.IsLayoutSwitchReady(iSafeCounter) && !timeout)
        {
        __ALFLOGSTRING("CAlfRosterFreezeEndTimer::RunL - Not ready in new orientation. waiting 50ms more");
        iSafeCounterDelta = 1;
        After( KRosterFreezeEndIntervalInMs * 1000 );
        return;
        }
    else
        {
        __ALFLOGSTRING("CAlfRosterFreezeEndTimer::RunL - Ready in new orientation.");
        iBridge.iHuiEnv->SetRefreshMode(EHuiRefreshModeAutomatic);
          
        iCallBack.CallBack();
        }
    }

void CAlfRosterFreezeEndTimer::DoCancel()
    {
    CTimer::DoCancel();
    }



CAlfLayoutSwitchEffectCoordinator::CAlfLayoutSwitchEffectCoordinator( CAlfBridge& aBridge ) :
    iBridge( aBridge ),
    iLayoutSwitchEffectContext(AknTransEffect::ENone),
    iCurrentState( EStateIdle )
    {
    RThread me = RThread();
    iOriginalPriority = me.Priority();    
    me.Close();
    }

CAlfLayoutSwitchEffectCoordinator::~CAlfLayoutSwitchEffectCoordinator()
    {   
    delete iRosterFreezeEndTimer;
    delete iImplicitBlankTimer;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::Blank
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::Blank(TBool aEnabled)
    {
    __ALFLOGSTRING1("CAlfLayoutSwitchEffectCoordinator::Blank %d", aEnabled);
    iAknBlankEnabled = aEnabled;
    HandleBlankChange();
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::ImplicitBlank
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::ImplicitBlank()
    {
    __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::ImplicitBlank");
        
    if (!iImplicitBlankTimer)
        {
        iImplicitBlankTimer = CPeriodic::New(CActive::EPriorityHigh);
        if (!iImplicitBlankTimer)
            {
            return;
            }
        }
        
    iImplicitBlankEnabled = ETrue;
    HandleBlankChange();
    
    if (iImplicitBlankTimer)
        {
        iImplicitBlankTimer->Cancel();
        iImplicitBlankTimer->Start(KAlfImplicitBlankerTimeoutInMs*1000, KAlfImplicitBlankerTimeoutInMs*1000, 
            TCallBack(DoImplicitBlankOff, this));
        }
    }
    
// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::DoImplicitBlankOff
// ---------------------------------------------------------
//
TInt CAlfLayoutSwitchEffectCoordinator::DoImplicitBlankOff(TAny* aAny)
    {
    __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::DoImplicitBlankOff");
        
    CAlfLayoutSwitchEffectCoordinator* self = static_cast<CAlfLayoutSwitchEffectCoordinator*>(aAny);
    self->iImplicitBlankTimer->Cancel();
    self->iImplicitBlankEnabled = EFalse;
    self->HandleBlankChange();
    
    return KErrNone;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::HandleBlankChange
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::HandleBlankChange()
    {
    TBool newBlankState = iAknBlankEnabled || iImplicitBlankEnabled;
    
    iBlankEnabled = newBlankState;
    Event( newBlankState ? EEventBlankOn : EEventBlankOff );
    }
    
// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::LowMemoryEvent
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::LowMemoryEvent()
    {
    __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::LowMemory");
    Event( EEventLowMemory );
    }
    
// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::BeginLayoutSwitch
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::BeginLayoutSwitch()
    {
    __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::BeginLayoutSwitch");
    Event( EEventLayoutSwitch );      
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::Event
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::Event(TEvent aEvent)
    {
    // States:
    // - EStateIdle - No layout switch effect ongoing
    // - EStateFreezeFx - Roster frozen, periodic fullscreen completeness checking
    // - EStateBlankFx - Roster frozen, expecting client to say when ready to unfreeze
    // - EStateThemeFx - Theme effect in use

    // Events:
    // - EEventBlankOn - Client requested blank on
    // - EEventBlankOff - Client requested blank off
    // - EEventLayoutSwitch - Layout switch noticed
    // - EEventLowMemory - Low memory indication
    // and implicit Finish - Effect finished
    
    // Transitions:
    // From EStateIdle:
    // - EEventBlankOn: EStateBlankFx
    // - EEventLayoutSwitch: If effect available, EStateThemeFx. Otherwise EStateFreezeFx.
    //
    // From EStateFreezeFx:
    // - implicit Finish - EStateIdle
    //
    // From EStateBlankFx:
    // - EEventBlankOff: EStateFreezeFx (we use freeze to ensure that result is ok)
    // - EEventLayoutSwitch: If effect available, EStateThemeFx. Otherwise EStateFreezeFx.
    //
    // From EStateThemeFx:
    // - EEventLowMemory: If blank still on, EStateBlankFx. Otherwise EStateFreezeFx.
    // - implicit Finish - EStateIdle
    //
    // There is special handling if layout switch event is received while previous
    // layout switch is ongoing.

    TState nextState = EStateIdle;
    
    switch ( iCurrentState )
        {    
    case EStateFreezeFx:
        nextState = NextFreezeState(aEvent);
        break;
        
    case EStateBlankFx:
        nextState = NextBlankState(aEvent);
        break;
        
    case EStateThemeFx:
        nextState = NextThemeState(aEvent);
        break;
        
    case EStateIdle:
    default:
        nextState = NextIdleState(aEvent);   
        break;
        }
    
    if ( nextState != iCurrentState )
        {
        Transition( nextState, iCurrentState );
        }
    else
        {
        // We stay in the same state, but still need special handling in a couple of scenarios
        if ( nextState == EStateFreezeFx )
            {
            HandleFreezeEvent( aEvent );
            }
        if ( nextState == EStateThemeFx )
            {
            HandleThemeEvent( aEvent );
            }                        
        }
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::HandleFreezeEvent
// Special handling for Freeze effect.
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::HandleFreezeEvent(TEvent aEvent)
    {
    if ( aEvent == EEventLayoutSwitch && iRosterFreezeEndTimer && iRosterFreezeEndTimer->IsActive() )
        {                                
        // New layout switch while previous is ongoing => restart freeze end timer.
        __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::HandleFreezeEvent restart timer");
        iRosterFreezeEndTimer->Cancel();
        iRosterFreezeEndTimer->Start(KRosterFreezeEndTimeoutInMs*1000, TCallBack(DoFreezeFinished, this));                
        }
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::HandleFreezeEvent
// Special handling for Theme effect.
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::HandleThemeEvent(TEvent aEvent)
    {
    if ( aEvent == EEventLayoutSwitch )
        {                                
        // If layout switch occurs while freeze end timer is ongoing, restart.
        if ( iRosterFreezeEndTimer && iRosterFreezeEndTimer->IsActive() )
            {
            __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::HandleThemeEvent restart timer");
            iRosterFreezeEndTimer->Cancel();
            iRosterFreezeEndTimer->Start(KRosterFreezeEndTimeoutInMs*1000, TCallBack(DoNextLayoutSwitchContext, this));                
            }

        // If layout switch occurs while theme effect is ongoing in exit phase, restart.
        if ( iLayoutSwitchEffectContext == AknTransEffect::ELayoutSwitchExit )
            {
            __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::HandleThemeEvent restart themefx");
            TBool oldLayoutSwitchNotCompleted = iLayoutSwitchNotCompleted;
            iLayoutSwitchNotCompleted = EFalse;
                
            Transition( EStateIdle, iCurrentState );
            Transition( EStateThemeFx, iCurrentState );
                
            if (oldLayoutSwitchNotCompleted)
                {
                iLayoutSwitchNotCompleted = ETrue;
                }  
            }
        }
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::Transition
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::Transition(
        TState aNewState, TState aPreviousState)
    {
    __ALFLOGSTRING2("CAlfLayoutSwitchEffectCoordinator::Transition from: %d to: %d", aPreviousState, aNewState);
    iCurrentState = aNewState;
        
    // Undo previous state - don't unfreeze roster.
    switch ( aPreviousState )
        {
    case EStateFreezeFx:
        if ( iRosterFreezeEndTimer )
            {
            iRosterFreezeEndTimer->Cancel();
            }
        break;
        
    case EStateBlankFx:        
        iBridge.iHuiEnv->iPauseDrawing = EFalse;
        break;
        
    case EStateThemeFx:
        {
        RThread me = RThread();
        me.SetPriority(iOriginalPriority);    
        me.Close();

        if ( iRosterFreezeEndTimer )
            {
            iRosterFreezeEndTimer->Cancel();
            }

        SetLayoutSwitchEffect( AknTransEffect::ENone );
        }
        break;
        
    case EStateIdle:
    default:    
        break;
        }
    
    // Do next state actions
    switch ( iCurrentState )
        {    
    case EStateFreezeFx:
        {
        if (!iRosterFreezeEndTimer)
            {
            TRAP_IGNORE(iRosterFreezeEndTimer = CAlfRosterFreezeEndTimer::NewL(iBridge));
            }
            
        if (iRosterFreezeEndTimer)
            {
            iRosterFreezeEndTimer->Cancel();
            
            FreezeRoster(ETrue);
                
            // Remove all other effects
            iBridge.HandleGfxStopEvent( EFalse );
            iBridge.CleanAllFxVisuals();

            // Set remove freeze timer
            __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::Transition - Freeze timer started");
            iRosterFreezeEndTimer->Start(KRosterFreezeEndTimeoutInMs*1000, TCallBack(DoFreezeFinished, this)); 
            }
        else
            {
            // if out of memory, go to idle
            iCurrentState = EStateIdle;
            
            // Undo everything to be sure
            RThread me = RThread();
            me.SetPriority(iOriginalPriority);    
            me.Close();
            
            SetLayoutSwitchEffect( AknTransEffect::ENone );
            
            iBridge.iHuiEnv->iPauseDrawing = EFalse;
            FreezeRoster(EFalse);
            iBridge.iHuiEnv->Display(0).SetDirty();
            iBridge.SetVisualTreeVisibilityChanged(ETrue);
            iBridge.AsynchRefresh();
            }
        }
        break;
        
    case EStateBlankFx:
        {
        // Start blanker
        iBridge.iHuiEnv->iPauseDrawing = ETrue;
        FreezeRoster(ETrue);        
        }
        break;
        
    case EStateThemeFx:
        {
        // Boost priority so that we are able to draw more frames for the effect
        RThread me = RThread();
        me.SetPriority(EPriorityAbsoluteHigh);    
        me.Close();
            
        // Freeze visual content
        iBridge.iHuiEnv->Display(0).SetDirty();
        FreezeRoster(ETrue);
            
        // Remove all other effects
        iBridge.HandleGfxStopEvent( EFalse );
        iBridge.CleanAllFxVisuals();
            
        // Set first layout switch effect 
        SetLayoutSwitchEffect(AknTransEffect::ELayoutSwitchStart);
        }
        break;
        
    case EStateIdle:
    default:
        {
        // Undo everything to be sure
        RThread me = RThread();
        me.SetPriority(iOriginalPriority);    
        me.Close();
        
        SetLayoutSwitchEffect( AknTransEffect::ENone );
        if ( iRosterFreezeEndTimer )
            {
            iRosterFreezeEndTimer->Cancel();
            }            
        
        iBridge.iHuiEnv->iPauseDrawing = EFalse;
        FreezeRoster(EFalse);
        iBridge.iHuiEnv->Display(0).SetDirty();
        iBridge.SetVisualTreeVisibilityChanged(ETrue);
        iBridge.AsynchRefresh();
        }
        break;
        }    
    
    // Inform bridge about layout switch actions
    if ( aNewState != EStateIdle && aPreviousState == EStateIdle )
        {
        iLayoutSwitchNotCompleted = ETrue;
        iBridge.LayoutSwitchStart();
        }
    if ( aNewState == EStateIdle && iLayoutSwitchNotCompleted )
        {
        iLayoutSwitchNotCompleted = EFalse;
        iBridge.LayoutSwitchComplete();
        }
    
    __ALFLOGSTRING("CAlfLayoutSwitchEffectCoordinator::Transition end");        
    }


// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::IsInFreezeState
// ---------------------------------------------------------
//
TBool CAlfLayoutSwitchEffectCoordinator::IsInHeuristicPeriod()
    {
    return ( iRosterFreezeEndTimer && iRosterFreezeEndTimer->IsActive());
    }


// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::NextIdleState
// ---------------------------------------------------------
//
CAlfLayoutSwitchEffectCoordinator::TState 
    CAlfLayoutSwitchEffectCoordinator::NextIdleState(
        TEvent aEvent)
    {
    TState state = EStateIdle;
    
    switch ( aEvent )
        {
    case EEventLayoutSwitch:
        if ( IsThemeEffectEnabled() )
            {
            state = EStateThemeFx;
            }
        else
            {
            state = EStateFreezeFx;
            }
        break;
        
    case EEventBlankOn:
        state = EStateBlankFx;
        break;
        
    case EEventBlankOff:
    case EEventLowMemory:
    default:
        break;     
        }
    
    return state;
    }
    
// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::NextFreezeState
// ---------------------------------------------------------
//
CAlfLayoutSwitchEffectCoordinator::TState 
    CAlfLayoutSwitchEffectCoordinator::NextFreezeState(
        TEvent aEvent)
    {
    TState state = EStateFreezeFx;
    
    switch ( aEvent )
        {
    case EEventBlankOn:
    case EEventLayoutSwitch:    
    case EEventBlankOff:
    case EEventLowMemory:
    default:
        break;     
        }
    
    return state;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::NextBlankState
// ---------------------------------------------------------
//
CAlfLayoutSwitchEffectCoordinator::TState 
    CAlfLayoutSwitchEffectCoordinator::NextBlankState(
        TEvent aEvent)
    {
    TState state = EStateBlankFx;
    
    switch ( aEvent )
        {
    case EEventLayoutSwitch:
        if ( IsThemeEffectEnabled() )
            {
            state = EStateThemeFx;
            }
        else
            {
            state = EStateFreezeFx;
            }
        break;
    
    case EEventBlankOff:
        state = EStateFreezeFx;
        break;
        
    case EEventBlankOn:        
    case EEventLowMemory:
    default:
        break;     
        }
    
    return state;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::NextThemeState
// ---------------------------------------------------------
//
CAlfLayoutSwitchEffectCoordinator::TState 
    CAlfLayoutSwitchEffectCoordinator::NextThemeState(
        TEvent aEvent)       
    {
    TState state = EStateThemeFx;
    
    switch ( aEvent )
        {
    case EEventLowMemory:
        // It would be a bit faster to go directly to freeze state,
        // but it could cause some flickering 
        state = iBlankEnabled ? EStateBlankFx : EStateFreezeFx;
        break;
            
    case EEventLayoutSwitch:    
    case EEventBlankOn:
    case EEventBlankOff:
    default:
        break;     
        }
    
    return state;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::FreezeFinished
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::FreezeFinished()
    {
    Transition(EStateIdle, iCurrentState);
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::SetLayoutSwitchEffectL
//
// This method sets correct effect based on the given 
// layout switch context.
//
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::SetLayoutSwitchEffect(AknTransEffect::TContext aContext)
    {
    MHuiEffectable* effectable = iBridge.iHuiEnv->Display(0).Roster().Effectable();
    CHuiFxEffect* effect = NULL;
    CHuiFxEngine* engine = iBridge.iHuiEnv->EffectsEngine();
    
    if (!effectable || !engine)
        {
        return;
        }    
            
    // Update current context
    iLayoutSwitchEffectContext = aContext;           
    
    if (aContext == AknTransEffect::ENone)
        {
        // Just remove effect
        //RDebug::Print(_L("CAlfLayoutSwitchEffectCoordinator::NextLayoutSwitchEffectL - removing effect"));
        effectable->EffectSetEffect(NULL); // This calls AlfGfxEffectEndCallBack         
        }
    else
        {    
        // Load correct effect
        for ( TInt i = 0; i<iBridge.iAlfRegisteredEffects.Count(); i++ )
            {             
            if ( iBridge.iAlfRegisteredEffects[i].iAction == aContext)
                {
                //RDebug::Print(_L("CAlfLayoutSwitchEffectCoordinator::SetLayoutSwitchEffectL - loading effect"));
                TRAP_IGNORE(engine->LoadEffectL(*iBridge.iAlfRegisteredEffects[i].iEffectFile, effect, effectable, NULL, this, iLayoutSwitchEffectContext, KHuiFxDelayRunUntilFirstFrameHasBeenDrawn ) );                    
                break;
                }
            }
        }    
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::AlfGfxEffectEndCallBack
//
// This method is callback which gets called when layout 
// switch effect has ended.
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::AlfGfxEffectEndCallBack( TInt aHandle )
    {
    //RDebug::Print(_L("CAlfLayoutSwitchEffectCoordinator::AlfGfxEffectEndCallBack")); 
    // KErrNotFound indicates callback from DoNextLayoutSwitchContext
    if (iLayoutSwitchEffectContext == aHandle || aHandle == KErrNotFound)
        {
        AknTransEffect::TContext nextContext = NextLayoutSwitchContext();

        // Unfreeze visible content. This reveals real roster content (in new orientation).
        if (nextContext == AknTransEffect::ELayoutSwitchExit)
            {
            #ifdef HUI_DEBUG_TRACK_DRAWING
            RDebug::Print(_L("CAlfLayoutSwitchEffectCoordinator::AlfGfxEffectEndCallBack unfreezing roster content"));
            #endif
            iBridge.iHuiEnv->Display(0).SetDirty();
            FreezeRoster(EFalse);
            iBridge.SetVisualTreeVisibilityChanged(ETrue);
            if ( iLayoutSwitchNotCompleted )
                {
                iLayoutSwitchNotCompleted = EFalse;
                iBridge.LayoutSwitchComplete();
                }
            }
        
        // Set next effect
        SetLayoutSwitchEffect(nextContext);
        
        if (nextContext == AknTransEffect::ENone)
            {
            // Restore normal priority
            if ( iCurrentState == EStateThemeFx )
                {
                Transition(EStateIdle, iCurrentState);
                }
            
            RThread me = RThread();
            me.SetPriority(iOriginalPriority);    
            me.Close();

            // Just in case refresh everything
            iBridge.iHuiEnv->Display(0).SetDirty();
            }        
        }
    else
        {
        //RDebug::Print(_L("CAlfLayoutSwitchEffectCoordinator::AlfGfxEffectEndCallBack - got different handle (normal, dont worry...) - %i"), aHandle);        
        }
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::NextLayoutSwitchContext
//
// This method automatically selects the next context in the 
// layout switch procedure.
//
// Contextes change in the following order during layout switch:
//
// 1. AknTransEffect::ENone
// 2. AknTransEffect::ELayoutSwitchStart
// 3. AknTransEffect::ELayoutSwitch
// 4. AknTransEffect::ELayoutSwitchExit
// 5. AknTransEffect::ENone
//
// After new context is selected, appropriate effect is set 
// (and/or removed) from the roster.
//
// ---------------------------------------------------------
//
// todo: rename
TInt CAlfLayoutSwitchEffectCoordinator::DoNextLayoutSwitchContext(
        TAny* aLayoutSwitchCoordinator)
    {
    CAlfLayoutSwitchEffectCoordinator* coordinator = (CAlfLayoutSwitchEffectCoordinator*)aLayoutSwitchCoordinator;
    coordinator->AlfGfxEffectEndCallBack(KErrNotFound);
    return 0;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::NextLayoutSwitchContext
// ---------------------------------------------------------
//
AknTransEffect::TContext CAlfLayoutSwitchEffectCoordinator::NextLayoutSwitchContext()
    {
    // Resolve next context based on current context
    AknTransEffect::TContext newContext = AknTransEffect::ENone;    
    switch (iLayoutSwitchEffectContext)
        {
        case AknTransEffect::ENone:
            {
            newContext = AknTransEffect::ELayoutSwitchStart;            
            break;
            }
        case AknTransEffect::ELayoutSwitchStart:
            {
            newContext = AknTransEffect::ELayoutSwitch;
            if (!iRosterFreezeEndTimer)
                {
                TRAP_IGNORE(iRosterFreezeEndTimer = CAlfRosterFreezeEndTimer::NewL(iBridge));
                }
            if (iRosterFreezeEndTimer)
                {
                iRosterFreezeEndTimer->Cancel();
                iRosterFreezeEndTimer->Start(KRosterFreezeEndTimeoutInMs*1000, TCallBack(DoNextLayoutSwitchContext, this));
                }
            else
                {
                newContext = AknTransEffect::ELayoutSwitchExit;
                }
            break;
            }
        case AknTransEffect::ELayoutSwitch:
            {
            newContext = AknTransEffect::ELayoutSwitchExit;                    
            break;
            }
        case AknTransEffect::ELayoutSwitchExit: // fallthrough
        default:
            {
            newContext = AknTransEffect::ENone;            
            break;
            }              
        }

    //RDebug::Print(_L("CAlfLayoutSwitchEffectCoordinator::NextLayoutSwitchEffectL old ctx = %i, new ctx = %i"), iLayoutSwitchEffectContext, newContext);
    return newContext;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::IsThemeEffectEnabled()
// Returns true if layout switch theme effect may be used
// ---------------------------------------------------------
//
TBool CAlfLayoutSwitchEffectCoordinator::IsThemeEffectEnabled() const
    {
    TBool memoryOk = !( iBridge.iHuiEnv->MemoryLevel() <= EHuiMemoryLevelLow );
    TBool tfxOn = CAknTransitionUtils::TransitionsEnabled(AknTransEffect::ELayoutswitchTransitionsOff );
    TBool tfxExists = LayoutSwitchEffectsExist();

    return 
        memoryOk && tfxOn && tfxExists;
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::LayoutSwitchEffectsExist()
// Returns true if layout switch effect exists
// ---------------------------------------------------------
//
TBool CAlfLayoutSwitchEffectCoordinator::LayoutSwitchEffectsExist() const
    {
    TBool appearExists = EFalse;
    TBool disAppearExists = EFalse;
    
    for ( TInt i = 0; i<iBridge.iAlfRegisteredEffects.Count(); i++ )
        {             
        if ( iBridge.iAlfRegisteredEffects[i].iAction == AknTransEffect::ELayoutSwitchStart)
            {
            disAppearExists = ETrue;
            break;
            }
        else if ( iBridge.iAlfRegisteredEffects[i].iAction == AknTransEffect::ELayoutSwitchExit)
            {
            appearExists = ETrue;
            break;
            }
        }
    
    return (appearExists || disAppearExists);    
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::EnableSafeCounter()
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::EnableSafeCounter(TBool aEnable)
    {
    if (iRosterFreezeEndTimer)
        {
        if (aEnable)
            {
            iRosterFreezeEndTimer->iSafeCounter = 0;
            }
        else
            {
            iRosterFreezeEndTimer->iSafeCounter = KErrNotFound;
            }
        }
    }        

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::FreezeRoster()
// Freeze visible content in roster.
// ---------------------------------------------------------
//
void CAlfLayoutSwitchEffectCoordinator::FreezeRoster(TBool aFrozen)
    {
    TRAP_IGNORE(iBridge.iHuiEnv->Display(0).Roster().FreezeVisibleContentL(aFrozen));
    }

// ---------------------------------------------------------
// CAlfLayoutSwitchEffectCoordinator::DoFreezeFinished()
// ---------------------------------------------------------
//
TInt CAlfLayoutSwitchEffectCoordinator::DoFreezeFinished(TAny* aAny)
    {
    static_cast<CAlfLayoutSwitchEffectCoordinator*>(aAny)->FreezeFinished();
    return KErrNone;
    }

// ---------------------------------------------------------
// CAlfFinishTimer
// ---------------------------------------------------------
//
CAlfEffectEndTimer::CAlfEffectEndTimer( CAlfBridge& aBridge )
    :CTimer(EPriorityHigh), 
    iBridge(aBridge)
    {   
    }

void CAlfEffectEndTimer::ConstructL()
    {
    CTimer::ConstructL();
    iHandles.ReserveL(5);
    CActiveScheduler::Add( this );
    }

CAlfEffectEndTimer* CAlfEffectEndTimer::NewL( CAlfBridge& aBridge )
    {
    CAlfEffectEndTimer* self = new ( ELeave ) CAlfEffectEndTimer( aBridge );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

CAlfEffectEndTimer::~CAlfEffectEndTimer()
    {
    Cancel();
    iHandles.Close();
    }

void CAlfEffectEndTimer::Start( TTimeIntervalMicroSeconds32 aPeriod )
    {
    After( aPeriod );
    }

void CAlfEffectEndTimer::AddFinishedHandleL(TInt aHandle)
    {
    iHandles.Append(aHandle);
    }

void CAlfEffectEndTimer::RunL()
    {
    //
    // timer completes and control is returned to caller
    //
    while(iHandles.Count())
        {
        iBridge.TransitionFinishedHandlerL( iHandles[0]);
        iHandles.Remove(0);
        }
    // We don't become active unless we are explicitly restarted
    }

void CAlfEffectEndTimer::DoCancel()
    {
    CTimer::DoCancel();
    }


CEffectState::CEffectState()
    {
    // CBase clears all variables
    }

CEffectState::~CEffectState()
    {
    delete iEffectName;
    }

void CEffectState::ResolveFileNameL(RMemReadStream& aStream)
    {
    HBufC* effectDirectory = HBufC::NewLC(aStream, 256);
    HBufC* effectFile = HBufC::NewLC(aStream, 256);

    // Add one extra because we want to be able to append a number to the filename
    HBufC* effectFullName = HBufC::NewL(effectDirectory->Des().Length()
            + effectFile->Des().Length() + 1);
    CleanupStack::PushL(effectFullName);

    effectFullName->Des().Copy(*(effectDirectory));
    effectFullName->Des().Append(*(effectFile));
    delete iEffectName;
    iEffectName = effectFullName; // ownership transferred
    CleanupStack::Pop(effectFullName);
    CleanupStack::PopAndDestroy(2, effectDirectory);
    }


CFullScreenEffectState::~CFullScreenEffectState()
    {
    }

void CFullScreenEffectState::ConstructL(const CFullScreenEffectState& aEffectState)
    {
    iAction = aEffectState.iAction;
    iHandle = aEffectState.iHandle;
    iType = aEffectState.iType;
    iLongAppStartTimeout = aEffectState.iLongAppStartTimeout;
    iTimeout = aEffectState.iTimeout;
    iToWg = aEffectState.iToWg;
    iFromWg = aEffectState.iFromWg;
    iToAppId = aEffectState.iToAppId;
    iFromAppId = aEffectState.iFromAppId;

    iToSecureId = aEffectState.iToSecureId;
    iFromSecureId = aEffectState.iFromSecureId;
    
    iRect.iTl.iX = aEffectState.iRect.iTl.iX;
    iRect.iTl.iY = aEffectState.iRect.iTl.iY;
    iRect.iBr.iX = aEffectState.iRect.iBr.iX;
    iRect.iBr.iY = aEffectState.iRect.iBr.iY;
    iState = aEffectState.iState;
    iEffectName = aEffectState.iEffectName->AllocL();
    iEffectType = aEffectState.iEffectType;
    iCompletionHandle = aEffectState.iCompletionHandle;
    iTwoPhaseEffect = CFullScreenEffectState::EOnlyOnePart;
    }

void CFullScreenEffectState::ConstructL(
        TInt aAction,
        RMemReadStream& aStream)
    {
    iAction = aAction;
    iHandle = aStream.ReadInt32L();
    iType = aStream.ReadInt32L();
    iLongAppStartTimeout = aStream.ReadInt32L();
    iTimeout = aStream.ReadInt32L();
    iToWg = aStream.ReadInt32L();
    iFromWg = aStream.ReadInt32L();
    iToAppId = aStream.ReadInt32L();
    iFromAppId = aStream.ReadInt32L();

    iToSecureId = aStream.ReadInt32L();
    iFromSecureId = aStream.ReadInt32L();
    
    iFlags = aStream.ReadInt32L();
    iRect.iTl.iX = aStream.ReadInt32L();
    iRect.iTl.iY = aStream.ReadInt32L();
    iRect.iBr.iX = aStream.ReadInt32L();
    iRect.iBr.iY = aStream.ReadInt32L();

    ResolveFileNameL(aStream);

    iCompletionHandle = iHandle;
    iTwoPhaseEffect = CFullScreenEffectState::EOnlyOnePart;
    }

void CFullScreenEffectState::SetState(TEffectState aState)
    {
    if (aState >= iState)
        {
        __ALFFXLOGSTRING2("CFullScreenEffectState::SetState - Set %d -> %d", iState, aState);
        iState = aState;
        }
    else
        {
        __ALFFXLOGSTRING2("CFullScreenEffectState::SetState - WARNING! Trying to set to previous state. %d -> %d", iState, aState);
        }
    };
        
TEffectState CFullScreenEffectState::State()
    {
    __ALFFXLOGSTRING1("CFullScreenEffectState::State - %d", iState);
    return iState;
    }
      

void CControlEffectState::ConstructL(TInt aAction,
        RMemReadStream& aStream)
    {
    iAction = aAction;
    TInt operation = aStream.ReadInt32L();
    iHandle = aStream.ReadInt32L();
    iClientHandle = aStream.ReadInt32L();
    iClientGroupHandle = aStream.ReadInt32L();
    TInt screenNumber = aStream.ReadInt32L(); // this has always value 0
    iSetDistractionWindow = ENoOperation;
    // Are Symbian full filename+directory combinations still max 256 characters long?
    ResolveFileNameL(aStream);
    }

void CControlEffectState::ConstructL(TUint32 aClientHandle, TUint32 aClientGroupHandle, TInt aSetDistractionWindow)
    {
    iClientHandle = aClientHandle;
    iClientGroupHandle = aClientGroupHandle;
    if (aSetDistractionWindow)
        {
        iSetDistractionWindow = CControlEffectState::ESetDistractionWindow;
        }
    else
        {
        iSetDistractionWindow = CControlEffectState::ERemoveDistractionWindow;
        }
    }
