/*
* Copyright (c) 2006 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:   Application Sever
*
*/



#include <coemain.h>
#include <coedef.h>
#include <apgwgnam.h>
#include <eiksvdef.h>
#include <ecom.h>
#include <uiacceltk/HuiUtil.h>
#include <f32file.h>
#include <TfxSrvEcomIds.h>
#include <mtransitionserver.h>
#include "alf/alfappserver.h"
#include "alf/alfappui.h"
#include "alf/alfconstants.h"
#include "alfappsrvsession.h"
#include "alflogger.h"
#include "alfsrvsubsessionbase.h"
#include "alf/alfextensionfactory.h"
#include "alfstaticfactory.h"
#include "alfsrvtranseffect.h"
#include "alf/AlfTransEffectPlugin.h"
#include <uiacceltk/HuiDisplay.h> //@todo::
#include "alfclientserver.h"
#include "alfsrvtexturemanager.h"
#include "alfsrvscreenbuffermanager.h"

// ----------------------------

/**
 * Common command batch buffer size. This must always be larger than command 
 * header size. In practice, this should be always larger than 128.
 */
const TInt KAlfCommonCommandBatchBufferSize = 
    KAlfClientServerDefaultCommandBatchBufferSize;

// a kind of cleanup item for ecom info array
NONSHARABLE_CLASS(CCleanupEcomArray):public CBase
    {
    public:
    ~CCleanupEcomArray()
        {
        iArray.ResetAndDestroy();
        iArray.Close();
        }
    RImplInfoPtrArray iArray;
    };


// ECom notify helper.
NONSHARABLE_CLASS(CAlfEcomUtil): public CActive
    {
    public:    
    
    CAlfEcomUtil(CAlfAppServer& aServer)
    :CActive(EActivePriorityDefault), iOwner(aServer)
	    {
	    CActiveScheduler::Add(this);
	    }

    void ConstructL()
	    {
	    iEComSession = &REComSession::OpenL();
    	}

    ~CAlfEcomUtil()
	    {
	    Cancel();
	    if (iEComSession)
	        {
	        iEComSession->Close();
	        }
	    iEComSession = NULL;
	    }

    static CAlfEcomUtil* NewL(CAlfAppServer& aServer)
	    {
	    CAlfEcomUtil* self = new (ELeave) CAlfEcomUtil(aServer);
	    CleanupStack::PushL(self);
	    self->ConstructL();
	    CleanupStack::Pop(self);
	    return self;
	    }

    void Start()
	    {
	    if (!IsActive())
	        {
    	    iEComSession->NotifyOnChange(iStatus);
	        SetActive();
	        }
	    }

    void RunL()
	    {
	    // if there was an error, just breathe a moment, i.e. don't activate new request immediately
        if (iStatus.Int() == KErrNone )
            {
    	    //Check wether plugin was installed or removed
     	    TRAP_IGNORE(iOwner.CheckForEcomPluginInstallUninstallL())
    	    Start();
            }
        __ALFLOGSTRING1( "CAlfEcomUtil::RunL: status %d", iStatus.Int() )
	    }

    void DoCancel()
	    {
	    iEComSession->CancelNotifyOnChange(iStatus);
	    }
	
	private:    
        CAlfAppServer& iOwner;
        REComSession* iEComSession;
    };
    

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


EXPORT_C CAlfAppServer* CAlfAppServer::NewAppServerL()
    {
    return new (ELeave) CAlfAppServer();
    }


// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CAlfAppServer::CAlfAppServer():
      iLastActiveClientWg(KErrNotFound)
    {
    CCoeEnv* coe = CCoeEnv::Static();
    if (coe)
        {
        iWs = &coe->WsSession();
        }
    }

// ---------------------------------------------------------------------------
// Second phase constructor
// ---------------------------------------------------------------------------
//
void CAlfAppServer::ConstructL( const TDesC& aFixedServerName )
    {
    CAknAppServer::ConstructL( aFixedServerName );

    iCommonCommandBatchBuffer = HBufC8::NewL( KAlfCommonCommandBatchBufferSize );
    iTextureManager = CAlfSrvTextureManager::NewL();
    iScreenBufferManager = CAlfSrvScreenBufferManager::NewL(*this);
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CAlfAppServer::~CAlfAppServer()
    {
	#ifdef TFXSERVER_API_V2
    if (iTfxServer)
    	{
        iTfxServer->Disconnect();
    	delete iTfxServer;
    	iTfxServer = NULL;
    	REComSession::DestroyedImplementation( iTfxServerEComDestructorUID );
    	iTfxServerEComDestructorUID.iUid = 0;	
    	}
	#endif

    delete iBackgroundTimer;
    delete iTransitionEffects;
    
    delete iEcomWatcher;
    
    iWindowChangeObservers.Close();
    
    if (iAsynchOneShot)
        {
        iAsynchOneShot->Cancel();
        }
    
    delete iAsynchOneShot;
    iRemovedArray.Close();
    
    delete iObjectConIx;

    for (TInt ii = iCustomSessions.Count()-1; ii >= 0; ii--)
        {
        delete iCustomSessions[ii].iImpl;
        REComSession::DestroyedImplementation(
                iCustomSessions[ii].iDestructorUid);
        }
        
    iCustomSessions.Close();
    
    // Todo: check remaining implementations
    for (TInt ii = iFactories.Count()-1; ii >= 0; ii--)
        {
        iFactories[ii].iImpl->Release();
        if (iFactories[ii].iDestructorUid.iUid)
            {
            REComSession::DestroyedImplementation(
                iFactories[ii].iDestructorUid);
            }
        }

    iFactories.Close();
        
    iMetricsInterface = NULL;
    iAppUi= NULL;

    delete iCommonCommandBatchBuffer;
	delete iScreenBufferManager;
    delete iTextureManager;
    }

// ---------------------------------------------------------------------------
// Called when client application exist.
// All allocated resources for that application should be freed.
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfAppServer::HandleClientExit(TInt aClientId)
    {
	if (MetricsInterface())
	    {
		MetricsInterface()->SessionTerminated(aClientId);
		}
  
    SyncEcomImplementations(aClientId);  
    
    CAlfAppSrvSessionBase* session = reinterpret_cast<CAlfAppSrvSessionBase*>(aClientId);
    
    ScreenBufferManager().RemoveScreenBufferObservers(session);
    
    if (session == iOldSession)
        {
        iOldSession = 0;
        }
    
    if (iAppUi)
        {
        iAppUi->FreeResourcesForClient(aClientId);
        }
    else 
        {
        return;
        }
        
    for (TInt i = iWindowChangeObservers.Count()-1; i >= 0 ; i--)
        {
        if (iWindowChangeObservers[i].iId == aClientId)
            {
            iWindowChangeObservers.Remove(i);
            }
        }
        
    // todo, is it true that we have no other way to check the count than using iterator?
    TInt count = 0;
    iSessionIter.SetToFirst();
    for(;iSessionIter;iSessionIter++)
        {
        count++;
        }
    
    // if this was the last client, it is ok to bail out here    
    if (count == 1)
        {
        AppUi()->UpdateActiveSession( 0 );
        AdjustWindowGroupPositionL(*CHuiStatic::RootWin(0),0,EAbsoluteBackground);
        return;
        }

    // Set wg position based in the topmost client app
    TInt parentWg = KErrNotFound;    
    CAlfAppSrvSessionBase* dying = reinterpret_cast<CAlfAppSrvSessionBase*>(aClientId);

    if ( dying->ClientWindowGroup() == KErrNotFound )
        {
        // debugging trash
        // just bail out w/o changing the order of window groups
        return;       
        }
    
    if ( dying->ClientWindowGroup() == iLastActiveClientWg )
        {
        iLastActiveClientWg = KErrNotFound;
        parentWg = dying->ParentWindowGroupId();
        }

    CAlfAppSrvSessionBase* newFocusSession = 0;

    // if parent of embedded app found, check if it ALF app and set it to focus
    if (parentWg != KErrNotFound)
        {
        iSessionIter.SetToFirst();
        while (iSessionIter)
            {
            CAlfAppSrvSessionBase* session = reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);
            if ( session && session->ClientWindowGroup() == parentWg)
                {
                newFocusSession = session;
                break;
                }
            }
        }
        
    if (CCoeEnv::Static() && !newFocusSession) // else find topmost app and move us behind that
        {
        parentWg = KErrNotFound; // just in case app had parent but that was not ALF app
        CArrayFixFlat<TInt>* wgs = new CArrayFixFlat<TInt>(4);
        if ( wgs )
            {
            iWs->WindowGroupList(wgs);
            for ( TInt ordinal = 0 ; ordinal < wgs->Count(); ordinal++ )
                {
                iSessionIter.SetToFirst();
                if( newFocusSession ) // session found from previous ordinal position.
                    {
                    break;
                    }
                while (iSessionIter)
                    {
                    CAlfAppSrvSessionBase* session = reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);
                    if ( session && 
                         session->ClientWindowGroup() == wgs->At( ordinal ) &&
                         (TInt)session != aClientId )
                        {
                        newFocusSession = session;
                        break;
                        }
                    }
                }
            }
        delete wgs;
        }
    
    TRAP_IGNORE(FocusedWindowGroupChangedL(newFocusSession, parentWg))
    }


// ---------------------------------------------------------------------------
// Static utility used in callback
// ---------------------------------------------------------------------------
// 
TInt SynchEcomImplementations(TAny* aThis)
    {
    ((CAlfAppServer*)aThis)->DoSynchEcomImplementations();
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Check if the exiting client is using ecom based session
// if so, set asynchronous callback for notifying Ecom FW about the change
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::SyncEcomImplementations(TInt aClientId)  
    {
    TBool isEcom(EFalse);
    for(TInt ii = iCustomSessions.Count()-1; ii >= 0 ; ii--)
        {
        if (iCustomSessions[ii] == aClientId)
            {
            isEcom = ETrue;
            iCustomSessions[ii].iImpl = 0; // session is about to terminate, null the pointer
            break;
            }
        }
    if (isEcom)
        {
        iRemovedArray.Append(aClientId);
        if (iAsynchOneShot && !iAsynchOneShot->IsActive())
            {
            iAsynchOneShot->CallBack();
            }
        
        }
    }

// ---------------------------------------------------------------------------
// Check and notify Ecom FW about removed implementations caused by client exit
// Called asynchronously after a client usin ecom based session has exited.
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::DoSynchEcomImplementations()
    {
    // check if the session was ECOM based and notify FW if so
    for (TInt i = iRemovedArray.Count()-1; i >= 0; i--)
        {
        for(TInt ii = iCustomSessions.Count()-1; ii >= 0 ; ii--)
            {
            if (iCustomSessions[ii] == iRemovedArray[i])
                {
                REComSession::DestroyedImplementation(
                    iCustomSessions[ii].iDestructorUid);            
                iCustomSessions.Remove(ii);
                }
            }
        
        }
    iRemovedArray.Reset();
    User::Heap().Compress();
    }
    
// ---------------------------------------------------------------------------
// From class CAknAppServer.
// Called when all clients have existed.
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::HandleAllClientsClosed()
    {
    if (iAppUi)
        iAppUi->AllClientsClosed();
    }
        
// ---------------------------------------------------------------------------
// From class CAknAppServer.
// Allocates the session instance
// ---------------------------------------------------------------------------
//
CApaAppServiceBase* CAlfAppServer::CreateServiceL( TUid aServiceType ) const
    {
    CApaAppServiceBase* session = 0;
    if (aServiceType == KAlfServiceUid)   
		{
		session = CAlfAppSrvSession::NewL(this);
		}
    else
	    { // nasty const cast
    	session = ((CAlfAppServer*)this)->LoadServiceExtensionL(aServiceType);		    
	    }
	
	if(session)	
	    {
		if (MetricsInterface())
		    {
		    const_cast<MAlfMetricsInterface*>(MetricsInterface())->SessionCreated(reinterpret_cast<TInt>(session));
		    }
		    
	    return session;
	    }
	else
		{
		return CAknAppServer::CreateServiceL(aServiceType);	
		}
    }
    
// ---------------------------------------------------------------------------
// Adjusts server's wg according to client's wg.
// ---------------------------------------------------------------------------
// 
EXPORT_C void CAlfAppServer::AdjustWindowGroupPositionL(
    RWindowGroup& aWindowGroup, 
    TInt aParentIdentifier, 
    TAlfWGPostion aPosition)
    {
    if (!iAppUi )
        {
        return;  
        }

    // Update the member variable based on the WG the server follows.
    if (aPosition != EAbsoluteBackground)
        {
        iLastActiveClientWg = aParentIdentifier;
        }
        
    if (!CCoeEnv::Static())
        {
        iAppUi->AdjustWindowGroupPositionL(
                    aParentIdentifier, 
                    aPosition);
        return;
        }
        
#ifdef _ALF_LOGGING
    LogWindowGroupsL();
    switch( aPosition )
        {
        case EBehindOfParent:
            __ALFLOGSTRING1( "CAlfAppServer::AdjWinGrpPosL EBehindOfParent parent id %d", aParentIdentifier )
            break;
        case EOnTopOfParent:
            __ALFLOGSTRING1( "CAlfAppServer::AdjWinGrpPosL EOnTopOfParent parent id %d", aParentIdentifier )
            break;
        case EAbsoluteBackground:
            __ALFLOGSTRING1( "CAlfAppServer::AdjWinGrpPosL EAbsoluteBackground parent id %d", aParentIdentifier )
            break;
        default:
            __ALFLOGSTRING2( "CAlfAppServer::AdjWinGrpPosL UNKNOWN parent id %d pos %d", aParentIdentifier, aPosition )
            break;
        }
#endif
    
    if (aPosition == EAbsoluteBackground) // just for convenience
        {
        aWindowGroup.SetOrdinalPosition(0,ECoeWinPriorityNeverAtFront);
        LogWindowGroupsL();
        return;
        }
            
    TInt parentPriority = iWs->GetWindowGroupOrdinalPriority(aParentIdentifier);

    // perhaps we should maintain wg-list elsewhere
    CArrayFixFlat<TInt>* wgs = new (ELeave) CArrayFixFlat<TInt>(1); 
    CleanupStack::PushL(wgs);
    iWs->WindowGroupList(parentPriority,wgs);
    
    TInt pos = KErrNotFound;
    TInt movingWgOldPos = KErrNotFound;
    TInt wgCount = wgs->Count();
    for (TInt i = 0; i < wgCount; i++)
        {
        if (aParentIdentifier == wgs->At(i))
            {
            if ( aPosition == EOnTopOfParent )
                {
                pos = i;
                }
            else
                {
                pos = i+1;
                }
            }
        if ( aWindowGroup.WindowGroupId() == wgs->At(i))
            {
            movingWgOldPos = i;
            }
           
        if ( pos != KErrNotFound && movingWgOldPos != KErrNotFound )
            {
            // Both found already.
            break;
            }
        }
    
    // If the moving window group has already been before the parent
    // we need to adjust the new position
    if ( movingWgOldPos < pos && movingWgOldPos != KErrNotFound )
        {
        pos--;
        }


    User::LeaveIfError(pos); // parenty not found, leave
    
    // if iBackDropWgIdentifier has been set, status pane is partly drawn to 
    // back drop window group
    if (aPosition == EBehindOfParent && 
        iBackDropWgIdentifier 
        && parentPriority == ECoeWinPriorityNormal ) // only apps with normal priority should use status pane
        {
        for (TInt ii = pos; ii < wgCount; ii++)
            {
            if (wgs->At(ii) == iBackDropWgIdentifier)
                {
                pos = ii+1; // right behind status pane
                break;
                }
            }    
        
        }
    CleanupStack::PopAndDestroy(wgs);
    
    aWindowGroup.SetOrdinalPosition(pos, parentPriority);
    
    LogWindowGroupsL();
    }
   
// ---------------------------------------------------------------------------
// Returns server's window server session.
// ---------------------------------------------------------------------------
// 
EXPORT_C RWsSession& CAlfAppServer::WsSession() const
    {
    return *iWs;
    }

// ---------------------------------------------------------------------------
// Returns the metrics interface.
// ---------------------------------------------------------------------------
// 
EXPORT_C MAlfMetricsInterface* CAlfAppServer::MetricsInterface()
    {
    return iMetricsInterface;
    }
    
// ---------------------------------------------------------------------------
// Returns the metrics interface.
// ---------------------------------------------------------------------------
// 
EXPORT_C const MAlfMetricsInterface* CAlfAppServer::MetricsInterface() const
    {
    return iMetricsInterface;
    }

// ---------------------------------------------------------------------------
// Sets the metrics interface.
// ---------------------------------------------------------------------------
// 
EXPORT_C void CAlfAppServer::SetMetricsInterface(
    MAlfMetricsInterface* aMetricsInterface)
    {
    iMetricsInterface = aMetricsInterface;
    }

// ---------------------------------------------------------------------------
// Sets the AppUi.
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::SetAppUi(CAlfAppUi* aAppUi)
    {
    iAppUi = aAppUi;
    iWs = &CHuiStatic::WsSession();
    }
    
// ---------------------------------------------------------------------------
// Returns the AppUi pointer.
// ---------------------------------------------------------------------------
// 
EXPORT_C CAlfAppUi* CAlfAppServer::AppUi()
    {
    __ASSERT_DEBUG(iAppUi, USER_INVARIANT());
    return iAppUi;
    }
   
// ---------------------------------------------------------------------------
// Called when the focused window group changes.
// ---------------------------------------------------------------------------
//     
void CAlfAppServer::FocusedWindowGroupChangedL( CAlfAppSrvSessionBase* aSession, TInt aWgId)
    {
    iOldSession = NULL;
    CancelBackgroundTimer();

    // Find new and old focused clients
    CAlfAppSrvSessionBase* newFocusedSession = aSession;
    CAlfAppSrvSessionBase* oldFocusedSession = NULL;
    
    iSessionIter.SetToFirst();
    while (iSessionIter)
        {
        CAlfAppSrvSessionBase* session =
            reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);

        if (  session && 
              !oldFocusedSession && 
              iLastActiveClientWg != KErrNotFound &&
              session->ClientWindowGroup() == iLastActiveClientWg )
            {
            oldFocusedSession = session;
            }
            
        // If found, stop the search. 
        if ( oldFocusedSession || iLastActiveClientWg == KErrNotFound )
            {
            break;
            }
        // Otherwise, keep going...
        }
        
    if ( !newFocusedSession )
        {
        // Another application got the focus
        // let the server follow the previous app wg
        if ( oldFocusedSession )
            {
            oldFocusedSession->ResetRootlayerTransformationsL();
            oldFocusedSession->FocusLostL( EFalse );
            AdjustWindowGroupPositionL(
                        *CHuiStatic::RootWin(),
                        oldFocusedSession->ClientWindowGroup(), 
                        oldFocusedSession->PreferredWindowGroupPosition());        
            }
        else // this will be the case when there is only direct client connections left
            {
            AdjustWindowGroupPositionL(*CHuiStatic::RootWin(0),0,EAbsoluteBackground);
            }
        AppUi()->UpdateActiveSession( 0 );
        AppUi()->SetContainerNonFading( EFalse );
        }
    else
        {
        // One of our clients got the focus
        AdjustWindowGroupPositionL( 
                *CHuiStatic::RootWin(), 
                newFocusedSession->ClientWindowGroup(), 
                newFocusedSession->PreferredWindowGroupPosition() );
#ifdef SYMBIAN_BUILD_GCE    
        newFocusedSession->ActivateContainerLayoutL(ETrue);
#endif // #ifdef SYMBIAN_BUILD_GCE    

        TBool didFadeOutTransition = EFalse; // default, just make sure that visual trees are restored
        if ( oldFocusedSession && newFocusedSession != oldFocusedSession) // switching between apps
            {
            if ((oldFocusedSession->ClientWindowGroup() == newFocusedSession->ParentWindowGroupId())
                || (newFocusedSession->ClientWindowGroup() == oldFocusedSession->ParentWindowGroupId() ))
                { // swithching into embedded app
                didFadeOutTransition = oldFocusedSession->FocusLostL( MAlfTransEffectPlugin::EContextEmbeddedExit );
                if (didFadeOutTransition)
                    {
                    didFadeOutTransition = MAlfTransEffectPlugin::EContextEmbeddedStart;
                    }
                }
            else // swithching between separate apps
                {
                didFadeOutTransition = oldFocusedSession->FocusLostL( MAlfTransEffectPlugin::EContextFocusLost );
                }    
            }
        else if (!oldFocusedSession ) // New app is being launched
            {                         // or previous app destroyed  
            if (aWgId == KErrNotFound)
                {
                didFadeOutTransition = MAlfTransEffectPlugin::EContextFocusGained; // enable default effect
                }
            else
                {
                didFadeOutTransition = MAlfTransEffectPlugin::EContextEmbeddedStart; // enable default effect
                }
            }
        else
            {
            // Fot PC-lint
            }
        newFocusedSession->FocusGainedL( didFadeOutTransition );
        }
#ifdef SYMBIAN_BUILD_GCE
/*
#ifdef HUI_FX
*/
    // Should test if transition is running
    // If transitions are disabled, no delay is needed
    if ( oldFocusedSession && oldFocusedSession != newFocusedSession )
        {
        if ( !newFocusedSession )
            {
            iOldSession = oldFocusedSession;
            StartBackgroundTimerL(iLastActiveClientWg);
            }
        else
            {
            oldFocusedSession->ActivateContainerLayoutL(EFalse);
            }
        }
/*        
#else  
    if (oldFocusedSession && oldFocusedSession != newFocusedSession )
        oldFocusedSession->ActivateContainerLayoutL(EFalse);
#endif    
*/
#endif // #ifdef SYMBIAN_BUILD_GCE    
    }


// ---------------------------------------------------------------------------
// Notify window visibility observers about change
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::WindowVisiblityChangedL( 
    TUint aVisibilityFlags, 
    CCoeControl* aDestination )
    {
    for (TInt i = 0; i < iWindowChangeObservers.Count(); i++)
        {
        if (iWindowChangeObservers[i].iPtr->CoeControl() == aDestination)
            {
            if ( aVisibilityFlags & 
                 TWsVisibilityChangedEvent::EPartiallyVisible )
                {
                iWindowChangeObservers[i].iPtr->WindowPartiallyVisible();
                }
            else if ( aVisibilityFlags & 
                      TWsVisibilityChangedEvent::EFullyVisible )
                {
                iWindowChangeObservers[i].iPtr->WindowFullyVisible();
                }
            else if ( aVisibilityFlags & 
                      TWsVisibilityChangedEvent::ENotVisible )
                {
                iWindowChangeObservers[i].iPtr->WindowNotVisible();
                }
            else
                {
                // For PC-lint
                }
            
            break;
            }
        }
    }
    
// ---------------------------------------------------------------------------
// Loads a session extension.
// ---------------------------------------------------------------------------
// 
CAlfAppSrvSessionBase* CAlfAppServer::LoadServiceExtensionL(TUid aServiceType)
    {
    CAlfAppSrvSessionBase* newSession = 0;
    // check if lib already loaded
    if (ImplementationExists(aServiceType)) // no need to scan
        {
        newSession = NewImplementationL(aServiceType);       
        }
    else
        {
        // perform plugin scan
        CCleanupEcomArray* ecomInfoArray = new (ELeave) CCleanupEcomArray;
        CleanupStack::PushL(ecomInfoArray);
        REComSession::ListImplementationsL(TUid::Uid(K_ALF_SERVICE_INTERFACE), ecomInfoArray->iArray);
        // check if plugin with implementation uid matches 
        TInt count = ecomInfoArray->iArray.Count();
        for (TInt ii = count-1; ii >= 0; ii-- )
            {
            if ((ecomInfoArray->iArray[ii])->ImplementationUid() 
                    == aServiceType)
                {
                newSession = NewImplementationL(aServiceType);       
                break;
                }
            }
        CleanupStack::PopAndDestroy();    
        }

    if (newSession && !iAsynchOneShot)
        { // instantiate remove callback here if it does not exist yet
        iAsynchOneShot = 
            new (ELeave) CAsyncCallBack(
                TCallBack(SynchEcomImplementations, this), 
                EActivePriorityDefault);
        }

    
    return newSession;
    }

// ---------------------------------------------------------------------------
// Checks if implementation of this type has been loaded already, 
// no need to perform scan if this is the case 
// ---------------------------------------------------------------------------
// 
TBool CAlfAppServer::ImplementationExists(TUid aServiceType) const
    {
    for(TInt ii = iCustomSessions.Count()-1; ii >= 0; ii--)
        {
        if (aServiceType==iCustomSessions[ii].iServiceUid)
            {
            return ETrue;
            }
        }

    return EFalse;
    }

// ---------------------------------------------------------------------------
// Loads and instantiates actual implementation using ECOM 
// ---------------------------------------------------------------------------
// 
CAlfAppSrvSessionBase* CAlfAppServer::NewImplementationL(TUid aServiceType)
    {
    TServiceExtension ext;
    ext.iServiceUid = aServiceType;
    ext.iImpl = 
        (CAlfAppSrvSessionBase*)REComSession::CreateImplementationL(
            aServiceType, 
            ext.iDestructorUid, 
            this);
    iCustomSessions.AppendL(ext);

    // set notify for changes in plugins (if it does not exist already) 
    if (!iEcomWatcher)
        {
        iEcomWatcher = CAlfEcomUtil::NewL(*this);
        iEcomWatcher->Start();
        }
  
    return ext.iImpl;
    }

// ---------------------------------------------------------------------------
// Something has changed in ECom, check if we are affected
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::CheckForEcomPluginInstallUninstallL()
    {
    // cross-check services loaded
    TInt csCount = iCustomSessions.Count();
    if (csCount)
        {
        CCleanupEcomArray* ecomInfoArray = new (ELeave) CCleanupEcomArray;
        CleanupStack::PushL(ecomInfoArray);
        REComSession::ListImplementationsL(TUid::Uid(K_ALF_SERVICE_INTERFACE), 
                                            ecomInfoArray->iArray);
        // check if plugin with implementation uid matches 
        TInt count = ecomInfoArray->iArray.Count();
        while (csCount > 0)
            {
            csCount--;
            TUid csUid = iCustomSessions[csCount].iServiceUid;
            TBool found(EFalse);
            for (TInt ii = count-1; ii >= 0; ii-- )
                {
                if ((ecomInfoArray->iArray[ii])->ImplementationUid() 
                    == csUid)
                    {
                    found = ETrue;       
                    break;
                    }
                }
            if (!found)
                { // notifies ECom about destroyed implementation
                delete iCustomSessions[csCount].iImpl;
                }
            }
            
        CleanupStack::PopAndDestroy();            
        }

    TInt factoryCount = iFactories.Count();
    if (factoryCount)
        {
        CCleanupEcomArray* ecomInfoArray = new (ELeave) CCleanupEcomArray;
        CleanupStack::PushL(ecomInfoArray);
        REComSession::ListImplementationsL(TUid::Uid( K_ALF_FACTORY_INTERFACE), 
                                            ecomInfoArray->iArray);
        // check if plugin with implementation uid matches 
        TInt count = ecomInfoArray->iArray.Count();
        while (factoryCount > 0 )
            {
            factoryCount--;
            TUid fUid = iFactories[factoryCount].iUid;
            if (fUid == KNullUid) // fixed factory
                {
                continue;                
                }
                
            TBool found(EFalse);
            for (TInt ii = count-1; ii >= 0; ii-- )
                {
                if ((ecomInfoArray->iArray[ii])->ImplementationUid() 
                    == fUid)
                    {
                    found = ETrue;       
                    break;
                    }
                }
            if (!found)
                { // notifies ECom about destroyed implementation
                NotifySessionsAboutDestroyedImplementation(iFactories[factoryCount].iUid.iUid);
                iFactories[factoryCount].iImpl->Release();
                }
            }
            
        CleanupStack::PopAndDestroy();            
        }

    if (iCustomSessions.Count() == 0 && 
        (iFactories.Count() == 0 || (iFactories.Count() == 1 && iFactories[0].iUid == KNullUid) ) )
        { // no active extensions -> cancel notify
        delete iEcomWatcher;
        iEcomWatcher = 0;    
        }
    
    }

// ---------------------------------------------------------------------------
// Appends new window visibility observer
// ---------------------------------------------------------------------------
// 
EXPORT_C void CAlfAppServer::SetWindowChangeObserverL(
    MWindowVisibilityObserver* aObserver, TInt aClientId) 
    {
    iWindowChangeObservers.AppendL(TWindowChangeObserver(aObserver,aClientId));
    }
    
TBool IsNewStatusPaneArchL()
    {
    _LIT(KS60ProductIDFile, "Series60v*.sis");
    _LIT(KROMInstallDir, "z:\\system\\install\\");

    TFindFile ff( CHuiStatic::FsSession());
    CDir* result;
    User::LeaveIfError( ff.FindWildByDir( KS60ProductIDFile, KROMInstallDir, result ) );
    CleanupStack::PushL( result );
    User::LeaveIfError( result->Sort( ESortByName|EDescending ) );

    TInt major = (*result)[0].iName[9] - '0';
    TInt minor = (*result)[0].iName[11] - '0';

    CleanupStack::PopAndDestroy(); // result
    return ((major>3) || (major == 3 && minor >= 2));
    }

void ResolveBdWgIdL(TInt& aId, RWsSession& aWs, CAlfAppUi& /*aAppUi*/)
    {
    if (!IsNewStatusPaneArchL())
        {
        CArrayFixFlat<TInt>* wgs = new (ELeave) CArrayFixFlat<TInt>(1); 
        CleanupStack::PushL(wgs);
        aWs.WindowGroupList(ECoeWinPriorityNormal,wgs);
        TInt wgCount = wgs->Count();

        CApaWindowGroupName* wgName = CApaWindowGroupName::NewLC(aWs); 
        HBufC* buf = HBufC::NewL(CApaWindowGroupName::EMaxLength);
        wgName->SetWindowGroupName(buf);

        for ( TInt spPos = 0; spPos < wgCount; spPos++)
            {
            TPtr des = buf->Des();
            TInt err = aWs.GetWindowGroupNameFromIdentifier(wgs->At(spPos), des);
            if (!err)
                {
                if ( wgName->Caption().Compare(EIKON_SERVER_BACKDROP_WINDOW_GROUP_NAME) == 0)
                    {
                    aId = wgs->At(spPos);
                    break;
                    }
                }
            }
        CleanupStack::PopAndDestroy(2); // wgName, wgs
        }
    }

// ---------------------------------------------------------------------------
// Creates container for session in which it holds the sub sessions.
// ---------------------------------------------------------------------------
// 
CObjectCon* CAlfAppServer::NewContainerL()
    {
    if ( !iObjectConIx )
        {
        iObjectConIx = CObjectConIx::NewL();
        // we don't have ConstructL, so this would be suitable place to do one-shot-only construction 
        if(CCoeEnv::Static())
            {
            ResolveBdWgIdL(iBackDropWgIdentifier, *iWs, *iAppUi);
            }
        }
        
    return iObjectConIx->CreateL();
    }

// ======== RnD FUNCTIONS ========

// ---------------------------------------------------------------------------
// Logs window groups
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::LogWindowGroupsL() const
    {
#ifdef _ALF_LOGGING
    // uncomment block if you want to log the window group order.
    /*
    CArrayFixFlat<TInt>* wgs = new (ELeave) CArrayFixFlat<TInt>(4); 
    CleanupStack::PushL(wgs);
    iWs->WindowGroupList(wgs);
    const TInt focusedWg = iWs->GetFocusWindowGroup();
    
    for ( TInt i = 0; i < wgs->Count() ; i++ )
        {
        TThreadId threadId;
        iWs->GetWindowGroupClientThreadId(wgs->At(i), threadId);
        RThread thread;
        if ( thread.Open(threadId) == KErrNone )
            {
            TName name = thread.Name();
            TPtrC ptr(name);
            if ( wgs->At(i) == focusedWg )
                {
                __ALFLOGSTRING3( " [%d] wg:%d %S FOCUSED",i,wgs->At(i), &ptr );
                }
            else
                {
                __ALFLOGSTRING3( " [%d] wg:%d %S",i,wgs->At(i), &ptr );
                }
            }
        }
    
    CleanupStack::PopAndDestroy( wgs );
    */
#endif
    }

MAlfExtension* CAlfAppServer::CreateExtensionL(TInt aImplementationUid, TInt aImplementationId, const RMessage2 & aMessage )
    {   
    TAlfElementFactory* factory = 0;

    if (iFactories.Count() == 0)
        {
        TAlfElementFactory ef;
        ef.iUid = KNullUid;
        ef.iImpl = new (ELeave) TAlfFixedFactory;
        ef.iDestructorUid = KNullUid;
        iFactories.AppendL(ef);
        }

    // Check if factory already loaded
    for(TInt ii = iFactories.Count()-1; ii>=0;ii--)
        {
        if (iFactories[ii].iUid == TUid::Uid(aImplementationUid))
            {
            factory = &iFactories[ii];
            break;
            }
        }

    if (!factory)
        {        
        // Todo should actually perform interface based scan and check that possible candidate (if any)
        // implements correct interface also
        // K_ALF_FACTORY_INTERFACE
        
        TAlfElementFactory ef;
        ef.iUid = TUid::Uid(aImplementationUid);
        ef.iImpl = (MAlfExtensionFactory*)REComSession::CreateImplementationL(
            ef.iUid, 
            ef.iDestructorUid);
        User::LeaveIfNull(ef.iImpl);
        iFactories.AppendL(ef);
        factory = &iFactories[iFactories.Count()-1];

        if (!iEcomWatcher)
            {
            iEcomWatcher = CAlfEcomUtil::NewL(*this);
            iEcomWatcher->Start();
            }
        }

    HBufC8* inBuf = 0;   
    TInt paramsLenght = aMessage.GetDesLength(1);
    if (paramsLenght > 0)
        {
        inBuf = HBufC8::NewLC(paramsLenght);        
        TPtr8 ptr = inBuf->Des();
        aMessage.ReadL(1,ptr);
        }

    // Create implementation    
    MAlfExtension* object = 0;
    if (inBuf)
        {
        object = factory->iImpl->CreateExtensionL(aImplementationId, inBuf->Des(), *((CAlfAppSrvSessionBase*)aMessage.Session()));
        CleanupStack::PopAndDestroy(inBuf);
        }
    else
        {
        object = factory->iImpl->CreateExtensionL(aImplementationId, KNullDesC8, *((CAlfAppSrvSessionBase*)aMessage.Session()));       
        }    
    
    factory->iAccessCount++;

    if (!object) // actually factory should leave
        {
        User::Leave(KErrNotSupported);
        } 

    return object;
    }
        

void CAlfAppServer::DestroyedObject(TInt aFactoryUid)
    {
    if (!aFactoryUid)
        {
        return;        
        }
 
    TInt ii = -1;
    for ( ii = iFactories.Count()-1; ii >= 0; ii--)
        {
        if (iFactories[ii] == aFactoryUid)
            {
            iFactories[ii].iAccessCount--;
            if (iFactories[ii].iAccessCount == 0)
                {
                iFactories[ii].iImpl->Release();
                if (iFactories[ii].iDestructorUid.iUid)
                    {
                    REComSession::DestroyedImplementation(
                            iFactories[ii].iDestructorUid);
                    }
                iFactories.Remove(ii);
                User::Heap().Compress();
                }
            break;
            }
        }
    }

void CAlfAppServer::NotifySessionsAboutDestroyedImplementation(TInt aFactoryUid)
    {
    iSessionIter.SetToFirst();
    while (iSessionIter)
        {
        CAlfAppSrvSessionBase* session =
            reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);
        
        session->FactoryDestroyed(aFactoryUid);
        }
    }


// ---------------------------------------------------------------------------
// Create a transition effect instance for the server if it does not exist
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::CreateTransitionEffectsL()
	{
	if ( iTransitionEffects == NULL )
		{
		iTransitionEffects = CAlfSrvTransEffect::NewL();
		}
	}


// ---------------------------------------------------------------------------
// Return a pointer to the transition effects instance 
// ---------------------------------------------------------------------------
// 
CAlfSrvTransEffect* CAlfAppServer::TransitionEffects()
	{
	return( iTransitionEffects );
	}

// -----------------------------------------------------------------------------
// Create Tfx Server client plugin and make a connection to Tfx Server
// -----------------------------------------------------------------------------
//
TInt CAlfAppServer::CreateTfxServerPlugin()
    {
    TInt err = KErrNone;
    
	#ifdef TFXSERVER_API_V2
    if (iTfxServer == NULL)
        {
        TUid implementationUidSrv = { KTfxSrv2EcomImpl };
        TRAP(err, iTfxServer = (MTransitionServer2*)
            REComSession::CreateImplementationL( implementationUidSrv, iTfxServerEComDestructorUID,
            	NULL ));
        }
   	if (!err && (iTfxServer != NULL))
		{
        if (!iTfxServer->IsConnected())
    		{
            err = iTfxServer->Connect();
            }	
		}
	#endif
		
	return err;	
    }
    
    
// -----------------------------------------------------------------------------
// Return Tfx Server client pointer if possible
// -----------------------------------------------------------------------------
//
MTransitionServer2* CAlfAppServer::TfxServer()
	{
	TInt err = KErrNone;
	#ifdef TFXSERVER_API_V2
    if (iTfxServer && !iTfxServer->IsConnected())
  		{
        err = iTfxServer->Connect();
        }	
	#endif
	return (err ? NULL : iTfxServer);
	}
	

// ---------------------------------------------------------------------------
// Triggers sending a system event to clients
// ---------------------------------------------------------------------------
// 
void CAlfAppServer::TriggerSystemEvent(TInt aEvent)
    {
    iSessionIter.SetToFirst();
    while (iSessionIter)
        {
        CAlfAppSrvSessionBase* session =
            reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);
        
        session->TriggerSystemEvent(aEvent);
        }        
    }
 
TBool CrossCheckForeground(TAny* aThis)
    {
    CAlfAppServer* me = (CAlfAppServer*)aThis;
    
//#ifdef HUI_FX
    if ( me->iOldSession )
        {
        TRAP_IGNORE( me->iOldSession->ActivateContainerLayoutL(EFalse); 
        me->iOldSession = NULL;
        me->CancelBackgroundTimer(); );
        return EFalse;
        }
//#endif    
    TRAP_IGNORE(me->FocusedWindowGroupChangedL(0)) // cancels the timer
    return EFalse; 
    }

void CAlfAppServer::StartBackgroundTimerL(TInt aClientWg)
    {
    if (aClientWg != iLastActiveClientWg)
        {
        CancelBackgroundTimer();
        return;
        }
        
    if (!iBackgroundTimer)
        {
        iBackgroundTimer = CPeriodic::NewL(EPriorityNormal);
        }
    CancelBackgroundTimer(); // reset the time in case of active timers
/*    
#ifdef HUI_FX    
*/
    if ( iOldSession )
        {
        // longer delay to allow the application to start properly
        iBackgroundTimer->Start(1500000,0,TCallBack(CrossCheckForeground, this));
        }
    else
        {
        iBackgroundTimer->Start(20000,0,TCallBack(CrossCheckForeground, this));
        }
/*        
#else    
    iBackgroundTimer->Start(20000,0,TCallBack(CrossCheckForeground, this));
#endif
*/    
    }
    
void CAlfAppServer::CancelBackgroundTimer()
    {
    if(iBackgroundTimer)
        {
        iBackgroundTimer->Cancel();
        }
    }
    
TInt CAlfAppServer::CommonCommandBatchBufferMaxLength() const
    {
    return iCommonCommandBatchBuffer->Des().MaxLength();
    }

TBool CAlfAppServer::AcquireCommonCommandBatchBuffer( TPtr8& aBuffer )
    {
    TBool result = EFalse;
    
    if ( !iCommonCommandBatchBufferInUse )
        {
        // In practice, iCommonCommandBatchBufferInUse might be true only
        // if MAlfExtension::HandleCmdL starts active scheduler.
        // (but then ServiceL should not be called again)

        result = ETrue;
        iCommonCommandBatchBufferInUse = ETrue;
        aBuffer.Set( iCommonCommandBatchBuffer->Des() );
        aBuffer.Zero();
        }

    return result;
    }

void CAlfAppServer::ReleaseCommonCommandBatchBuffer()
    {
    iCommonCommandBatchBufferInUse = EFalse;
    }
    
CAlfSrvTextureManager& CAlfAppServer::TextureManager()
    {
    return *iTextureManager;
    }
    
CAlfSrvScreenBufferManager& CAlfAppServer::ScreenBufferManager()
    {
    return *iScreenBufferManager;
    }

TBool CAlfAppServer::AlfClientHasFocus()
    {
    TBool result = EFalse;
    TInt focusWindowGroupId = WsSession().GetFocusWindowGroup();

    iSessionIter.SetToFirst();
    while (iSessionIter)
      {
      CAlfAppSrvSessionBase* session = reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);
      if ( session && session->ClientWindowGroup() == focusWindowGroupId )
          {
          result = ETrue;
          break;
          }
      }
    return result;
    }

CAlfAppSrvSessionBase* CAlfAppServer::UpMostClientAboveWg( TInt aWgId )
    {
    if (!iAppUi && !CCoeEnv::Static())
        return 0;
            
    CAlfAppSrvSessionBase* sessionAboveGivenWgId = NULL;
     
    CArrayFixFlat<TInt>* wgs = new CArrayFixFlat<TInt>(4);
    if ( wgs )
        {
        iWs->WindowGroupList( 0, wgs);
        TInt topmostWgId = wgs->At( 0 );
         for ( TInt ordinal = 0 ; ordinal < wgs->Count(); ordinal++ )
            {
            iSessionIter.SetToFirst();
            if( sessionAboveGivenWgId || aWgId == wgs->At( ordinal ) ) 
               {
                // either above client app's wg was found or there wasn't any client app's wg above given aWgId
                break;
                }
            while (iSessionIter)
                {
                CAlfAppSrvSessionBase* session = reinterpret_cast<CAlfAppSrvSessionBase*>(iSessionIter++);
                if ( session && 
                     session->ClientWindowGroup() == topmostWgId )
                    {
                    sessionAboveGivenWgId = session;
                    break;
                    }
                 }
            }
        }
    delete wgs;
    return sessionAboveGivenWgId;
    }

