/*
* 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:  Task monitor engine
 *
*/


#include "tsfswengine.h"
#include "tscpsnotifier.h"
#include "tsfswdatalist.h"
#include "tsfsalwaysshownapplist.h"
#include "tsfshiddenapplist.h"
#include "tsfswidgetlist.h"
#include "tspreviewprovider.h"
#include "tsfswclient.h"
#include <apgtask.h>
#include <AknDef.h>
#include <apgwgnam.h>
#include <mmf/common/mmfcontrollerpluginresolver.h> // for CleanupResetAndDestroyPushL
#include <featmgr.h>
#include <swi/swispubsubdefs.h>
#include <s32mem.h>
#include <bitmaptransforms.h>
#include "enginelogging.h"

// time to wait before refreshing content
const TInt KContentRefreshDelay = 50000; // 0.05 sec

// for screenshots, they are scaled down to (screensize/this_factor).
const TInt KScreenSizeFactor = 2;

const TUid KTsCameraUid = { 0x101F857a };

//close command for widget
const TInt KCloseWidgetCmd(9);
//handle close cmd for s60 widgets
_LIT(KWidgetAppName, "widgetlauncher.exe");
//handle close cmd for CWRT widgets
_LIT(KWidgetAppNameWgt,"wgtwidgetlauncher.exe");

// --------------------------------------------------------------------------
// CTsFswEngine::NewL
// --------------------------------------------------------------------------
//
EXPORT_C CTsFswEngine* CTsFswEngine::NewL( MTsFswEngineObserver& aObserver )
    {
    CTsFswEngine* self = NewLC( aObserver );
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::NewLC
// --------------------------------------------------------------------------
//
EXPORT_C CTsFswEngine* CTsFswEngine::NewLC( MTsFswEngineObserver& aObserver )
    {
    CTsFswEngine* self = new ( ELeave ) CTsFswEngine( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::CTsFswEngine
// --------------------------------------------------------------------------
//
CTsFswEngine::CTsFswEngine( MTsFswEngineObserver& aObserver )
        : CActive( EPriorityStandard ), iObserver( aObserver )
    {
    CActiveScheduler::Add( this );
    }

// --------------------------------------------------------------------------
// CTsFswEngine::ConstructL
// --------------------------------------------------------------------------
//
void CTsFswEngine::ConstructL()
    {
    iEnv = CEikonEnv::Static();

    User::LeaveIfError( iWsSession.Connect() );
    User::LeaveIfError( iAppArcSession.Connect() );

    iDataList = CTsFswDataList::NewL(*this);
    iWidgetsSupported = FeatureManager::FeatureSupported( KFeatureIdWebWidgets );

    // get an initial list of tasks
    iDataList->SetAppDataRefreshNeeded();
    CollectTasksL();

    // listen for app screenshots
    iPreviewProvider = CTsFastSwapPreviewProvider::NewL( *this );
    SetPreviewParams();
    UpdatePreviewContent();

    iUpdateStarter = CPeriodic::NewL( CActive::EPriorityStandard );
    
    // start listening for swi ps property
    if ( iSwiProp.Attach( KUidSystemCategory,
            Swi::KUidSoftwareInstallKey ) == KErrNone )
        {
        iSwiProp.Subscribe( iStatus );
        SetActive();
        }
    iCpsWidgetPublisher = CTSCpsNotifier::NewL(*this);
    }

// --------------------------------------------------------------------------
// CTsFswEngine::~CTsFswEngine
// --------------------------------------------------------------------------
//
CTsFswEngine::~CTsFswEngine()
    {
    Cancel();
    iSwiProp.Close();

    delete iUpdateStarter;
    delete iPreviewProvider;

    iWgIds.Close();

    iAppArcSession.Close();
    iWsSession.Close();

    for ( TInt i = 0; i < iRotaTasks.Count(); i++ )
        {
        iRotaTasks[i]->Cancel();
        delete iRotaTasks[i];
        }
    iRotaTasks.Close();
    delete iDataList;
    delete iCpsWidgetPublisher;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::FswDataL
// --------------------------------------------------------------------------
//
EXPORT_C const RTsFswArray& CTsFswEngine::FswDataL()
    {
    TSLOG_CONTEXT( FswDataL, TSLOG_LOCAL );
    TSLOG_OUT();
    return iDataList->FswDataL();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::CloseAppL
// --------------------------------------------------------------------------
//
EXPORT_C void CTsFswEngine::CloseAppL( TInt aWgId )
    {
    TSLOG_CONTEXT( CloseAppL, TSLOG_LOCAL );
    TSLOG1_IN( "aWgId = %d", aWgId );

    if( iWidgetsSupported && 0 > aWgId )
        {
        // convert aWgId to an index in the list of running widgets and close widget
        CloseWidgetL( -aWgId -1 );
        }
    else if( !iDataList->IsAlwaysShownAppL( aWgId ) )
        {
        // send window group event to kill the app
        TWsEvent event;
        event.SetTimeNow();
        event.SetType( KAknShutOrHideApp );
        iEnv->WsSession().SendEventToWindowGroup( aWgId, event );
        TSLOG0( TSLOG_INFO, "event sent to wg" );
        }
    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::SwitchToAppL
// --------------------------------------------------------------------------
//
EXPORT_C void CTsFswEngine::SwitchToAppL( TInt aWgId )
    {
    TSLOG_CONTEXT( SwitchToAppL, TSLOG_LOCAL );
    TSLOG1_IN( "aWgId = %d", aWgId );

    if ( iWidgetsSupported && aWgId < 0 )
        {
        // for widgets clients see a wgid that is -1*(index+1)
        const RWidgetInfoArray& arr( iDataList->Widgets()->RunningWidgets() );
        // convert aWgId to an index in the list of running widgets
        TInt idx = -aWgId - 1;
        // if index is valid then handle the widget specially
        if ( idx >= 0 && idx < arr.Count() )
            {
            SwitchToWidgetL( idx );
            TSLOG1_OUT( "switched to widget %d", idx );
            return;
            }
        }

    TApaTask task( iEnv->WsSession() );
    task.SetWgId( aWgId );
    task.BringToForeground();

    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::SwitchToWidgetL
// --------------------------------------------------------------------------
//
void CTsFswEngine::SwitchToWidgetL( TInt aWidgetIndex )
    {
    const RWidgetInfoArray& arr( iDataList->Widgets()->RunningWidgets() );
    CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
    cmdLine->SetCommandL( EApaCommandRun );
    TApaAppInfo info;
    iAppArcSession.GetAppInfo( info, arr[aWidgetIndex]->iUid ); // codescanner::accessArrayElementWithoutCheck2 (aWidgetIndex checked in SwitchToAppL())
    cmdLine->SetExecutableNameL( info.iFullName );
    iAppArcSession.StartApp( *cmdLine );
    CleanupStack::PopAndDestroy(cmdLine);
    }

// --------------------------------------------------------------------------
// CTsFswEngine::UpdateTaskList
// Callback from appui
// --------------------------------------------------------------------------
//
void CTsFswEngine::UpdateTaskList()
    {
    TSLOG_CONTEXT( UpdateTaskList, TSLOG_LOCAL );
    TSLOG_IN();

    // screenshot taking support - call Register and Unregister when needed
    UpdatePreviewContent();

    // get the foreground app uid and publish it to CFW if different than before
    TRAP_IGNORE( PublishFgAppUidL() );

    // There can be many calls in a row, use a timer to prevent degrading
    // device performance.
    if ( !iUpdateStarter->IsActive() )
        {
        iUpdateStarter->Start( KContentRefreshDelay, 0,
                TCallBack( UpdateStarterCallback, this ) );
        }
    
    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::ForegroundAppUidL
// --------------------------------------------------------------------------
//
EXPORT_C TUid CTsFswEngine::ForegroundAppUidL( TInt aType )
    {
    // Do not use GetFocusWindowGroup or others.
    // We want to see only "real" application uids in FgApp,
    // i.e. stuff that would also be shown in the task swapper
    // area of Taskswitcher.

    TUid result = KNullUid;
    RArray<RWsSession::TWindowGroupChainInfo> allWgIds;
    CleanupClosePushL( allWgIds );
    User::LeaveIfError( iWsSession.WindowGroupList( 0, &allWgIds ) );
    TInt count = allWgIds.Count();
    for ( TInt i = 0; i < count; ++i )
        {
        // Depending on aType we may not need to bother with iParentId here.
        // If aType == EUseEmbeddedUid => embedded apps are treated as others.
        // If aType == EUseStandaloneUid => embedded apps must be ignored.
        if ( allWgIds[i].iParentId > 0
                && aType == CTsFswClient::EUseStandaloneUid )
            {
            continue;
            }

        CApaWindowGroupName* wgn = CApaWindowGroupName::NewLC(
            iWsSession, allWgIds[i].iId );
        TUid newUid = wgn->AppUid();
        TBool hidden = wgn->Hidden() || iDataList->HiddenApps()->IsHiddenL(
            newUid, iWsSession, allWgIds[i].iId );
        CleanupStack::PopAndDestroy( wgn );

        if ( !hidden && newUid.iUid )
            {
            result = newUid;
            break;
            }
        }
    CleanupStack::PopAndDestroy( &allWgIds );
    
    return result;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::PublishFgAppUidL
// --------------------------------------------------------------------------
//
void CTsFswEngine::PublishFgAppUidL()
    {
    TSLOG_CONTEXT( PublishFgAppUidL, TSLOG_LOCAL );
    TSLOG_IN();

    TUid newUid = ForegroundAppUidL( CTsFswClient::EUseEmbeddedUid );
    TSLOG2( TSLOG_INFO, "ws says: %x we have: %x", newUid.iUid, iFgAppUid.iUid );
    if ( iFgAppUid != newUid && newUid.iUid )
        {
        iFgAppUid = newUid;
        iDataList->MoveEntryAtStart(newUid.iUid, EFalse);
        TBool change( iDataList->MoveEntryAtStart(newUid.iUid, EFalse) );
        if( change )
            {
            iObserver.FswDataChanged();
            }
        }

    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::UpdateStarterCallback
// Callback for the timer
// --------------------------------------------------------------------------
//
TInt CTsFswEngine::UpdateStarterCallback( TAny* aParam )
    {
    CTsFswEngine* self = static_cast<CTsFswEngine*>( aParam );
    self->iUpdateStarter->Cancel();
    // get list of tasks and notify observer if there is a change in the list
    TBool changed = EFalse;
    TRAPD( err, changed = self->CollectTasksL() );
    if ( err == KErrNone && changed )
        {
        self->iObserver.FswDataChanged();
        }
    return 0;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::CollectTasksL
// --------------------------------------------------------------------------
//
TBool CTsFswEngine::CollectTasksL()
    {
    TSLOG_CONTEXT( CollectTasksL, TSLOG_LOCAL );
    TBool changed = iDataList->CollectTasksL();
    TSLOG1_OUT( "change flag = %d", changed );
    return changed;
    }

    
// CTsFswEngine::HiddenAppListUpdated
// Callback from the hidden app list watcher
// --------------------------------------------------------------------------
//
void CTsFswEngine::HiddenAppListUpdated()
    {
    UpdateTaskList();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::CopyBitmapL
// --------------------------------------------------------------------------
//
CFbsBitmap* CTsFswEngine::CopyBitmapL( TInt aFbsHandle, TBool aKeepAspectRatio )
    {
    TSLOG_CONTEXT( CopyBitmapL, TSLOG_LOCAL );
    
    CFbsBitmap* ret = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( ret );
    CFbsBitmap* bmp = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( bmp );
    User::LeaveIfError( bmp->Duplicate( aFbsHandle ) );

    //Make bitmap width and height equal so that it will look better in FSW control.
    TSize size  = bmp->SizeInPixels();

    if ( !aKeepAspectRatio )
        {
        if ( size.iHeight > size.iWidth )
            {
            size.iHeight = size.iWidth;
            }
        else
            {
            size.iWidth = size.iHeight;
            }
        }

    // preserve size and mode
    User::LeaveIfError( ret->Create( size, EColor64K ) );

    CFbsBitmapDevice* doubleBufferDev = CFbsBitmapDevice::NewL( ret );
    CleanupStack::PushL( doubleBufferDev );

    CFbsBitGc* doubleBufferGc = 0;
    User::LeaveIfError( doubleBufferDev->CreateContext( doubleBufferGc ) );
    CleanupStack::PushL( doubleBufferGc );

    // preserve size
    doubleBufferGc->BitBlt( TPoint( 0, 0 ), bmp, TRect(size) );

    CleanupStack::PopAndDestroy( doubleBufferGc );
    CleanupStack::PopAndDestroy( doubleBufferDev );
    CleanupStack::PopAndDestroy( bmp );
    CleanupStack::Pop( ret );

    TSLOG_OUT();
    return ret;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::UpdatePreviewContent
// --------------------------------------------------------------------------
//
void CTsFswEngine::UpdatePreviewContent()
    {
    TSLOG_CONTEXT( UpdatePreviewContent, TSLOG_LOCAL );
    TSLOG_IN();

    RArray<RWsSession::TWindowGroupChainInfo> allWgIds;
    if ( iWsSession.WindowGroupList( 0, &allWgIds ) == KErrNone )
        {
        // check window groups that do not exist anymore
        for ( TInt i = 0, ie = iWgIds.Count(); i != ie; ++i )
            {
            TInt wgid = iWgIds[i];
            TBool present = EFalse;
            for ( TInt j = 0, je = allWgIds.Count(); j != je; ++j )
                {
                if ( allWgIds[j].iId == wgid )
                    {
                    present = ETrue;
                    break;
                    }
                }
            if ( !present )
                {
                TSLOG1( TSLOG_INFO, "unregister: %d", wgid );
                iPreviewProvider->Unregister( wgid );
                }
            }
        // check topmost window group
        if ( allWgIds.Count() )
            {
            if ( !iWgIds.Count() || allWgIds[0].iId != iWgIds[0] )
                {
                TInt wgid = allWgIds[0].iId;
                TSLOG1( TSLOG_INFO, "registering %d", wgid );
                iPreviewProvider->Register( wgid );
                }
            }
        // store the new list
        iWgIds.Reset();
        for ( TInt i = 0, ie = allWgIds.Count(); i != ie; ++i )
            {
            iWgIds.Append( allWgIds[i].iId );
            }
        }
    allWgIds.Close();

    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::HandleFswPpApplicationChange
// Callback from CTsFastSwapPreviewProvider
// Note: aWgId is for the window group for which the screenshot is taken,
// it may not be the same as the application's wgid (in case of embedded apps)
// --------------------------------------------------------------------------
//
void CTsFswEngine::HandleFswPpApplicationChange( TInt aWgId, TInt aFbsHandle )
    {
    TSLOG_CONTEXT( HandleFswPpApplicationChange, TSLOG_LOCAL );
    TSLOG2_IN( "aWgId = %d aFbsHandle = %d", aWgId, aFbsHandle );

    TUid appUid;
    TInt wgId = iDataList->FindMostTopParentWgId(aWgId);
    if ( wgId == KErrNotFound )
        {
        wgId = aWgId;
        }
    TInt err = iDataList->AppUidForWgId( wgId, appUid );
    if ( err || appUid == KTsCameraUid )
        {
        // Dont't assign screenshot to camera app
        TSLOG0( TSLOG_LOCAL, "Screenshot for camera - ignore" );
        iPreviewProvider->AckPreview(aFbsHandle);
        TSLOG_OUT();
        return;
        }
    
    CFbsBitmap* bmp = 0;
    TRAP( err, bmp = CopyBitmapL( aFbsHandle, EFalse ) );
    iPreviewProvider->AckPreview(aFbsHandle);
    if ( err == KErrNone )
        {
        StoreScreenshot(aWgId, bmp);
        }

    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::HandleFswPpApplicationUnregistered
// Callback from CTsFastSwapPreviewProvider
// --------------------------------------------------------------------------
//
void CTsFswEngine::HandleFswPpApplicationUnregistered( TInt aWgId )
    {
    TSLOG_CONTEXT( HandleFswPpApplicationUnregistered, TSLOG_LOCAL );
    TSLOG1_IN( "aWgId = %d", aWgId );

    RemoveScreenshot(aWgId);
    
    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::HandleFswPpApplicationBitmapRotation
// Callback from CTsFastSwapPreviewProvider
// --------------------------------------------------------------------------
//
void CTsFswEngine::HandleFswPpApplicationBitmapRotation( TInt aWgId, TBool aClockwise )
    {
    TSLOG_CONTEXT( HandleFswPpApplicationBitmapRotation, TSLOG_LOCAL );
    TSLOG1_IN( "aWgId = %d", aWgId );
    
    CFbsBitmap** bmp = iDataList->FindScreenshot(aWgId);
            
    if ( bmp )
        {
        // Rotate bitmap
        TRAP_IGNORE( RotateL( **bmp, aWgId, aClockwise ) );
        // Bitmap in a array is invalid, remove it
        RemoveScreenshot(aWgId);
        }
    
    TSLOG_OUT();
    }


// --------------------------------------------------------------------------
// CTsFswEngine::RotateL
// Callback from CTsFastSwapPreviewProvider
// --------------------------------------------------------------------------
//
void CTsFswEngine::RotateL( CFbsBitmap& aBitmap, TInt aWgId, TBool aClockwise )
    {
    CFbsBitmap* rotaBitmap = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( rotaBitmap );
    User::LeaveIfError( rotaBitmap->Duplicate( aBitmap.Handle() ) );
    CTsRotationTask* rotaTask = new (ELeave) CTsRotationTask( *this );
    CleanupStack::PushL( rotaTask );
    User::LeaveIfError( iRotaTasks.Append( rotaTask ) );
    rotaTask->StartLD( aWgId, rotaBitmap, aClockwise ); // ownership transferred
    CleanupStack::Pop( rotaTask );
    CleanupStack::Pop( rotaBitmap );
    }


// --------------------------------------------------------------------------
// CTsFswEngine::RotationComplete
// Callback from CTsFastSwapPreviewProvider
// --------------------------------------------------------------------------
//
void CTsFswEngine::RotationComplete( TInt aWgId,
        CFbsBitmap* aBitmap,
        CTsRotationTask* aCompletedTask,
        TInt aError )
    {
    TSLOG_CONTEXT( RotationComplete, TSLOG_LOCAL );
    TSLOG_IN();
    
    TSLOG1( TSLOG_INFO, "---> rotation completed with status: %d", aError );
    TInt idx = iRotaTasks.Find( aCompletedTask );
    if ( idx != KErrNotFound )
        {
        // Update task list
        iRotaTasks.Remove(idx);
        }
    
    if ( aError == KErrNone )
        {
        StoreScreenshot(aWgId, aBitmap);
        }
    else
        {
        // Rotation failed, cleanup bitmap
        delete aBitmap;
        }
    
    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::RunL
// --------------------------------------------------------------------------
//
void CTsFswEngine::RunL()
    {
    if ( iStatus != KErrCancel ) // when cancelling the subscribe it completes with KErrCancel
        {
        TInt value = 0;
        if ( iSwiProp.Get( value ) == KErrNone )
            {
            TInt operationStatus( value & Swi::KSwisOperationStatusMask );
            // When an (un)installation has finished change the flag to
            // refresh the app list during the next task list update.
            if ( operationStatus == Swi::ESwisStatusSuccess )
                {
                iDataList->SetAppDataRefreshNeeded();
                }
            }
        iSwiProp.Subscribe( iStatus );
        SetActive();
        }
    }

// --------------------------------------------------------------------------
// CTsFswEngine::DoCancel
// --------------------------------------------------------------------------
//
void CTsFswEngine::DoCancel()
    {
    iSwiProp.Cancel();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::RunError
// --------------------------------------------------------------------------
//
TInt CTsFswEngine::RunError( TInt /*aError*/ )
    {
    return KErrNone;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::HandleResourceChange
// callback from appui's HandleResourceChangeL
// --------------------------------------------------------------------------
//
void CTsFswEngine::HandleResourceChange( TInt aType )
    {
    TSLOG_CONTEXT( HandleResourceChange, TSLOG_LOCAL );
    TSLOG_IN();

    if ( iPreviewProvider && aType == KEikDynamicLayoutVariantSwitch )
        {
        SetPreviewParams();
        }

    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::SetPreviewParams
// --------------------------------------------------------------------------
//
void CTsFswEngine::SetPreviewParams()
    {
    TSize screenSize = iEnv->ScreenDevice()->SizeInPixels();
    iPreviewProvider->SetPreviewParam(
        TSize( screenSize.iWidth / KScreenSizeFactor,
            screenSize.iHeight / KScreenSizeFactor ),
        EColor64K ); // displaymode is ignored
    }

// --------------------------------------------------------------------------
// CTsFswEngine::CloseWidgetL
// --------------------------------------------------------------------------
//
void CTsFswEngine::CloseWidgetL(TInt aOffset )
    {
    TSLOG_CONTEXT( CloseWidgetL, TSLOG_LOCAL );
    TSLOG1_IN( "aOffset = %d", aOffset );
    if( iDataList->Widgets()->RunningWidgets().Count() <= aOffset )
        {
        User::Leave(KErrArgument);
        }
    const CWidgetInfo* widgetInfo(iDataList->Widgets()->RunningWidgets()[aOffset]);
    const TPtrC bundleName(*widgetInfo->iBundleName);
    CApaCommandLine* const cmdLine = CApaCommandLine::NewLC();
    
    HBufC8* const
        opaque( HBufC8::NewLC( bundleName.Size() + 3 * sizeof( TUint32 ) ) );
    TPtr8 des ( opaque->Des() );
    RDesWriteStream stream;
    stream.Open( des );
    CleanupClosePushL( stream );
    stream.WriteUint32L ( widgetInfo->iUid.iUid ); 
    stream.WriteUint32L ( bundleName.Length() );
    stream.WriteL ( reinterpret_cast< const TUint8* >( bundleName.Ptr() ), bundleName.Size());
    stream.WriteInt32L ( KCloseWidgetCmd );
    CleanupStack::PopAndDestroy( &stream );
    cmdLine->SetCommandL( EApaCommandBackgroundAndWithoutViews );
    cmdLine->SetOpaqueDataL( *opaque );
    CleanupStack::PopAndDestroy( opaque );
    
    if (iDataList->Widgets()->IsCWRTWidget(widgetInfo->iUid))
    	{
        cmdLine->SetExecutableNameL( KWidgetAppNameWgt);
    	}
    else
    	{
        cmdLine->SetExecutableNameL( KWidgetAppName );
    	}
    
    iAppArcSession.StartApp( *cmdLine );
    CleanupStack::PopAndDestroy( cmdLine );
    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsFswEngine::StoreScreenshot
// --------------------------------------------------------------------------
//
TBool CTsFswEngine::StoreScreenshot(TInt aWgId, CFbsBitmap* aBmp)
    {
    TSLOG_CONTEXT( StoreScreenshot, TSLOG_LOCAL );
    //iDataList would take ownership
    TBool change = EFalse;
    change = iDataList->StoreScreenshot(aWgId, aBmp);
    if(change)
        {
        iObserver.FswDataChanged();
        }
    TSLOG1_OUT( "Screenshot for  = %d", aWgId );
    return change;
    }

// --------------------------------------------------------------------------
// CTsFswEngine::RemoveScreenshot()
// --------------------------------------------------------------------------
//
void CTsFswEngine::RemoveScreenshot(TInt aWgId)
    {
    TBool change = EFalse;
    change = iDataList->RemoveScreenshot(aWgId);
    if( change )
        {
        iObserver.FswDataChanged();
        }
    }

// --------------------------------------------------------------------------
// CTsFswEngine::HandleWidgetUpdateL()
// --------------------------------------------------------------------------
//
void CTsFswEngine::HandleWidgetUpdateL(TInt aWidgetId, TInt aBitmapHandle)
    {
	TSLOG_CONTEXT( HandleWidgetUpdateL, TSLOG_LOCAL );
    
	TBool contentChanged( iDataList->MoveEntryAtStart(aWidgetId, ETrue) );
    
	CFbsBitmap* bmp = 0;
    if( aBitmapHandle )
    	{
		TRAPD( err, bmp = CopyBitmapL( aBitmapHandle, EFalse ) );
		if ( err == KErrNone )
			{
            contentChanged = StoreScreenshot(aWidgetId, bmp);
			}
		}
	if(!contentChanged)
		{
		iObserver.FswDataChanged();
		}
 
    TSLOG_OUT();
    }

// --------------------------------------------------------------------------
// CTsRotationListener::CTsRotationListener
// --------------------------------------------------------------------------
//
CTsRotationTask::CTsRotationTask(CTsFswEngine& aEngine )
: CActive(EPriorityStandard),
  iEngine(aEngine)
    {
    CActiveScheduler::Add( this );
    }


// --------------------------------------------------------------------------
// CTsRotationListener::~CTsRotationListener
// --------------------------------------------------------------------------
//
CTsRotationTask::~CTsRotationTask()
    {
    Cancel();
    delete iRotator;
    delete iBitmap;
    }


// --------------------------------------------------------------------------
// CTsRotationListener::Start
// --------------------------------------------------------------------------
//
void CTsRotationTask::StartLD( TInt aWgId,
        CFbsBitmap* aBitmap,
        TBool aClockwise )
    {
    TSLOG_CONTEXT( StartLD, TSLOG_LOCAL );
    TSLOG_IN();
    
    iWgId = aWgId;
    iBitmap = aBitmap;
    iRotator = CBitmapRotator::NewL();
    if ( aClockwise )
        {
        iRotator->Rotate(&iStatus, *iBitmap, CBitmapRotator::ERotation90DegreesClockwise);
        }
    else
        {
        iRotator->Rotate(&iStatus, *iBitmap, CBitmapRotator::ERotation270DegreesClockwise);
        }
    SetActive();
    
    TSLOG_OUT();
    }


// --------------------------------------------------------------------------
// CTsRotationListener::RunL
// --------------------------------------------------------------------------
//
void CTsRotationTask::RunL()
    {
    iEngine.RotationComplete( iWgId, iBitmap, this, iStatus.Int() ); // bitmap ownership transferred
    iBitmap = NULL;
    delete this;
    }


// --------------------------------------------------------------------------
// CTsRotationListener::DoCancel
// --------------------------------------------------------------------------
//
void CTsRotationTask::DoCancel()
    {
    iRotator->Cancel();
    }
    
// end of file
