/*
* 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:  Memory state popup implementation
*
*/


// SYSTEM INCLUDES
#include <e32std.h>
#include <AknProgressDialog.h>
#include <aknlists.h>
#include <ConeResLoader.h>
#include <bautils.h>
#include <StringLoader.h>
#include <aknPopup.h>
#include <memstatepopup.rsg>
#include <f32file.h>
#include <data_caging_path_literals.hrh> 

// USER INCLUDES
#include "msputil.h"
#include "cmemstatepopup.h"
#include "cmemstatepopupimpl.h"
#include "cmemscaneventreceiver.h"

//  CONSTANTS
_LIT( KDirAndFile,"Z:MemStatePopup.RSC" );
_LIT( KMemListSeparator, "\t" );

// Max length of a list row
// Has to be big enough to hold "%N %U"
const TInt KListItemMaxLength = 32;

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

CMemStatePopupImpl::~CMemStatePopupImpl( )
    {
    Cancel();
    // Close the resource
    iResLoader.Close( );

    if( iWaitDialog )
        {
        iWaitDialog->SetObserver( NULL );
        delete iWaitDialog;
        }

    delete iEventReceiver; // deletes also scan engine and server 
     
    delete iGroupNames;
    delete iListModel;
    delete iListBox;
    delete iScanResults;


    if( iOwnsUtil )
        {
        // Delete only if the actual dialog was launched
        delete iUtil;
        }

    // Try to delete also iPopup in case of leave
    // Must call CBase's destructor
    // because CAknPopupList destructor is protected
    delete ( CBase* ) iPopup;
    }

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

CMemStatePopupImpl::CMemStatePopupImpl( TDriveNumber aDrive, const TDesC& aTitle ) :
            CActive(EPriorityStandard),
            iFinished( EFalse ),
            iDrive( aDrive ),
            iTitle( const_cast<TDesC*> (&aTitle) ),
            iCoeEnv( *CCoeEnv::Static( ) ),
            iResLoader( iCoeEnv ),
            iOwnsUtil( ETrue )
    {
    CActiveScheduler::Add(this);
    }

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

// Used by GetUtilL
CMemStatePopupImpl::CMemStatePopupImpl( ) :
            CActive(EPriorityStandard),
            iFinished( EFalse ),
            iDrive( EDriveC ),
            iCoeEnv( *CCoeEnv::Static( ) ),
            iResLoader( iCoeEnv ),
            iOwnsUtil( EFalse )
    {
    }

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

void CMemStatePopupImpl::ConstructL( )
    {
    OpenResourceAndReadArrayL( );

    // Instantiate event receiver, memory scan engine and server
    iEventReceiver = CMemScanEventReceiver::NewL( *this );

    // Get data group names from engine
    iGroupNames = iEventReceiver->DataGroupsL( );

    // Create popup
    ConstructPopupL( );

    // Create wait dialog
    iWaitDialog = new( ELeave ) CAknWaitDialog(
                    reinterpret_cast< CEikDialog** >( &iWaitDialog ) );
    iWaitDialog->SetCallback( this );
    iWaitDialog->PrepareLC( R_MEMSTATE_WAIT_NOTE );
    
    StartObserver();
    }

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

void CMemStatePopupImpl::RunLD( TDriveNumber aDrive, const TDesC& aTitle )
    {
    CMemStatePopupImpl* self = new( ELeave ) CMemStatePopupImpl( aDrive, aTitle );
    CleanupStack::PushL( self );
    self->ConstructL( );

    // Run the actual process
    self->ExecuteL( );

    CleanupStack::PopAndDestroy( self );
    }


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

void CMemStatePopupImpl::GetUtilL( CMSPUtil*& aUtil )
    {
    CMemStatePopupImpl* self = new( ELeave ) CMemStatePopupImpl;
    CleanupStack::PushL( self );

    // Read the unit array from resource
    self->OpenResourceAndReadArrayL( );
    aUtil = self->iUtil; // iUtil is not deleted

    CleanupStack::PopAndDestroy( self );
    }

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

void CMemStatePopupImpl::StartL( )
    {
#ifdef _DEBUG
    RDebug::Print( _L( "Scanning started!" ) );
#endif
    }

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

void CMemStatePopupImpl::QuitL( TInt /*aReason*/ )
    {
#ifdef _DEBUG
    RDebug::Print( _L( "Scanning ended!" ) );
#endif
    if( !iFinished )
        {
        // Tell waitdialog that it can quit now
        iWaitDialog->ProcessFinishedL( );
        iFinished = ETrue;
        }
    }

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

void CMemStatePopupImpl::ErrorL( TInt aError )
    {
#ifdef _DEBUG
    RDebug::Print( _L( "Error scanning memory: %d" ), aError );
#endif

    // getting rid of UREL compiler warning
    if( !aError ) 
        {
        aError = KErrNone;
        }
    }

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

void CMemStatePopupImpl::DialogDismissedL( TInt aButtonId )
    {

    // Cancel is pressed while scanning is in progress
    if( iEventReceiver->ScanInProgress( ) )
        {
        iFinished = ETrue;
        iEventReceiver->Cancel( ); // Stop scanning
        }

    // Cancel is pressed while wait note is on screen (scanning may be completed)
    if( aButtonId == EAknSoftkeyCancel ) // instead of EAknSoftkeyDone
        {
        iPopup->CancelPopup( ); // Remove memory state popup from screen
        return;
        }

    // Get the new result array
    delete iScanResults;
    iScanResults = NULL;
    TRAPD( err, iScanResults = iEventReceiver->ScanResultL( ) );
    if( err != KErrNone )
        {
        iPopup->CancelPopup( ); // Remove memory state popup from screen
        return;
        }
    RefreshL( );
    }

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

void CMemStatePopupImpl::ConstructPopupL( )
    {
    iListBox = new( ELeave ) CMemStateListBox( );

    iPopup = CAknPopupList::NewL( iListBox, R_AVKON_SOFTKEYS_OK_EMPTY,
                            AknPopupLayouts::EMenuGraphicHeadingWindow );
    iPopup->SetTitleL( *iTitle );

    // Set up listbox
    iListBox->ConstructL( iPopup, EAknListBoxViewerFlags );

    // Create listbox model and give the model to the listbox
    iListModel = new( ELeave ) CDesCArraySeg( iGroupNames->Count( ) );

    // Create scroll indicator
    iListBox->CreateScrollBarFrameL( ETrue );
    iListBox->ScrollBarFrame( )->SetScrollBarVisibilityL(
                    CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto );
    iListBox->Model( )->SetItemTextArray( iListModel );
    iListBox->Model( )->SetOwnershipType( ELbmDoesNotOwnItemArray );
    iListBox->ItemDrawer()->ColumnData()->EnableMarqueeL( ETrue );
    }

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

void CMemStatePopupImpl::ExecuteL( )
    {
    // Show wait dialog
    iWaitDialog->RunLD( );

    // Start the scanning
    User::LeaveIfError(iEventReceiver->ScanL( iDrive ));
    
    // Get the result array
    iScanResults = iEventReceiver->ScanResultL( );
   
    // Set all results zero, so that no actual results are shown
    // before the scan is done.
    NullifyResults( );

    // Update the list with initial values (0's)
    RefreshL( );

    // Show popup
    iPopup->ExecuteLD( );
    iPopup = NULL; // Has to be set NULL because deleted in destructor
    }

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

void CMemStatePopupImpl::RefreshL( )
    {
    //TBuf< KListItemMaxLength > result;
    TBuf< KListItemMaxLength > unitText;
    TBuf< KListItemMaxLength > tempText;
    TPtrC unit;
    TInt64 res64( 0 );
    TInt count( iScanResults ? iScanResults->Count( ) : 0 );
    TInt maxGroupName(0);
    
    for( TInt i = 0; i < iGroupNames->Count(); i++ )
        {
        if( maxGroupName < ( *iGroupNames )[ i ].Length() )
            {
            maxGroupName = ( *iGroupNames )[ i ].Length();
            }
        }
        
    // Allocate memory for size, unit text and actual group name
    HBufC* result = HBufC::NewLC( maxGroupName + 2*KListItemMaxLength );
    TPtr resultPtr( result->Des() );
    HBufC* unitFormatter = StringLoader::LoadLC( R_UNIT_FORMATTER, &iCoeEnv );

    iListModel->Reset( );

    // Go through the result array and append to the model as text
    for( TInt i = 0; i < count; i++ )
        {
        res64 = ( *iScanResults )[ i ];

        unit.Set( iUtil->SolveUnitAndSize( res64 ) );
        StringLoader::Format( tempText, *unitFormatter, 0, I64INT( res64 ) );
        StringLoader::Format( unitText, tempText, 1, unit );
        resultPtr.Zero( );

        // The actual listbox row is constructed here
        // iListModel is just an array of descriptors
        if ( User::Language() == ELangArabic )
            {
            resultPtr.Append( KRightToLeftMark );
            }
        resultPtr.Append( unitText );
        resultPtr.Append( KMemListSeparator );
        if( i < iGroupNames->Count() )
            {
            resultPtr.Append( ( *iGroupNames )[ i ] );
            }
        else
            {
            resultPtr.Append( ( *iGroupNames )[ 0 ] );
            }
        iListModel->AppendL( resultPtr );
        }

    CleanupStack::PopAndDestroy( unitFormatter );
    CleanupStack::PopAndDestroy( result );

    // Update the listbox
    iListBox->HandleItemAdditionL( );
    }

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

void CMemStatePopupImpl::NullifyResults( )
    {
    // Set all results to zero
    if( iScanResults )
        {
        TInt count( iScanResults->Count( ) );
        for( TInt t = 0; t < count; t++ )
            {
            ( *iScanResults )[ t ] = 0;
            }
        }
    }

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

void CMemStatePopupImpl::OpenResourceAndReadArrayL( )
    {
    // Open dll resource
    
    TParse* fp = new(ELeave) TParse(); 
    fp->Set(KDirAndFile, &KDC_RESOURCE_FILES_DIR, NULL); 
    TFileName fileName( fp->FullName() );
    delete fp;

    BaflUtils::NearestLanguageFile( iCoeEnv.FsSession( ),
                                    fileName );
    iResLoader.OpenL( fileName );

    // Read localised unit texts from resource
    TResourceReader reader;
    iCoeEnv.CreateResourceReaderLC( reader, R_ARRAY_UNITS );
    CDesCArrayFlat* units = reader.ReadDesCArrayL( );
    CleanupStack::PushL( units );
    iUtil = CMSPUtil::NewL( units ); // Give the array to the util class
    CleanupStack::Pop( units );
    CleanupStack::PopAndDestroy(); // Private HBufC8* variable
                                   // of CreateResourceReaderLC()
    }

// --------------------------------------------------------------------------- 
void CMemStatePopupImpl::RunL()
    {
    TVolumeInfo volInfo;
    TInt err = iCoeEnv.FsSession().Volume( volInfo, iDrive );
    if(err != KErrNone)
        {
        iPopup->CancelPopup( );
        }
    else
        {
        StartObserver();
        }
    }

// --------------------------------------------------------------------------- 
void CMemStatePopupImpl::DoCancel()
    {
    iCoeEnv.FsSession().NotifyChangeCancel();
    }

// --------------------------------------------------------------------------- 
void CMemStatePopupImpl::StartObserver()
    {
    if ( IsActive() ) 
        {
        Cancel();
        }
    iCoeEnv.FsSession().NotifyChange( ENotifyDisk, iStatus );
    SetActive();
    }

// End of File
