/*
* Copyright (c) 2007-2009 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:  SysAp drive list implementation
 *
*/



// INCLUDES
#include <e32std.h>
#include <f32file.h>
#include <badesca.h>
#include <StringLoader.h>
#include <driveinfo.h>
#include "sysapdrivelist.h"
#include "SysAp.hrh"

// CONSTANTS
_LIT( KMemoryCardFSName, "Fat" );
const TInt KNameFormatArrayLen = 2;
#ifdef __WINS__
const TInt KMountDelay = 1000000; // 1s
#endif

// ============================ MEMBER FUNCTIONS =============================
// ---------------------------------------------------------------------------
// CSysApDriveList::NewL
// ---------------------------------------------------------------------------
//
CSysApDriveList* CSysApDriveList::NewL( RFs& aFs )
    {
    CSysApDriveList* self = new ( ELeave ) CSysApDriveList( aFs );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::ConstructL
// ---------------------------------------------------------------------------
//
void CSysApDriveList::ConstructL()
    {
    // Get the default memory card. If memory card is unavailable,
    // then get the next best suitable drive.
    iDefaultMemoryCard = 0;
    
    TInt err( DriveInfo::GetDefaultDrive(
        DriveInfo::EDefaultRemovableMassStorage, iDefaultMemoryCard ) );
    if ( err != KErrNone )
        {
        err = DriveInfo::GetDefaultDrive(
            DriveInfo::EDefaultMassStorage, iDefaultMemoryCard );
        }
    if ( err != KErrNone )
        {
        err = DriveInfo::GetDefaultDrive(
            DriveInfo::EDefaultPhoneMemory, iDefaultMemoryCard );
        }
    if ( err != KErrNone )
        {
        err = DriveInfo::GetDefaultDrive(
            DriveInfo::EDefaultSystem, iDefaultMemoryCard );
        }

    TRACES( RDebug::Print(
        _L( "CSysApDriveList::ConstructL: iDefaultMemoryCard: %d, err: %d" ),
        iDefaultMemoryCard, err ) );

    User::LeaveIfError( err );
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::CSysApDriveList
// ---------------------------------------------------------------------------
//
CSysApDriveList::CSysApDriveList( RFs& aFs ) :
        iFs( aFs )
    {
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::~CSysApDriveList
// ---------------------------------------------------------------------------
//
CSysApDriveList::~CSysApDriveList()
    {
    TRACES( RDebug::Print( _L( "CSysApDriveList::~CSysApDriveList" ) ) );
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::MountDrive
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::MountDrive( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::MountDrive: drive: %d" ), aDrive ) );

#ifdef __WINS__ // Let's sleep a second in WINS
    User::After( KMountDelay );
#endif
    TInt ret( iFs.MountFileSystem( KMemoryCardFSName, aDrive ) );
    if ( ret != KErrNone )
        {
        TRACES( RDebug::Print(
            _L( "CSysApDriveList::MountDrive: drive: %d, ret: %d" ),
            aDrive, ret ) );
        }
    return ret;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::DismountDrive
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::DismountDrive( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::DismountDrive: drive: %d" ), aDrive ) );

#ifdef __WINS__ // Let's sleep a second in WINS
    User::After( KMountDelay );
#endif
	TRequestStatus status;

	TRACES( RDebug::Print( _L("CSysApDriveList::Start DismountDrive: RFs::NotifyDismount()") ) );

	iFs.NotifyDismount( aDrive, status, EFsDismountForceDismount );

	User::WaitForRequest( status );

	TRACES( RDebug::Print( _L("CSysApDriveList::DismountDrive: RFs::NotifyDismount() returned: %d"), status.Int() ) );

    return status.Int();
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::MemoryCardStatus
// ---------------------------------------------------------------------------
//
TSysApMemoryCardStatus CSysApDriveList::MemoryCardStatus(
        TInt aDrive )
    {
    UpdateDrive( aDrive, EFalse );
    return iStatusCache[ aDrive ].iStatus;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::DefaultMemoryCard
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::DefaultMemoryCard() const
    {
    return iDefaultMemoryCard;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::GetMemoryCardsL
// ---------------------------------------------------------------------------
//
void CSysApDriveList::GetMemoryCardsL(
        RArray< TMemoryCardEntry >& aMemoryCardArray,
        TUint aInclusionMask )
    {
    aMemoryCardArray.Reset();
    TMemoryCardEntry entry;
    for ( TInt i( 0 ); i < KMaxDrives; ++i )
        {
        UpdateDrive( i, EFalse );
        TSysApMemoryCardStatus memoryCardStatus( iStatusCache[ i ].iStatus );
        if ( memoryCardStatus != ESysApMemoryCardStatusNotKnown )
            {
            entry.iDrive = i;
            entry.iStatus = memoryCardStatus;
            entry.iDriveStatus = iStatusCache[ i ].iDriveStatus;
            TBool append( EFalse );
            if ( aInclusionMask == EIncludeAll )
                {
                append = ETrue;
                }
            else if ( ( aInclusionMask & EIncludeInserted ) &&
                entry.iStatus == ESysApMemoryCardInserted ||
                entry.iStatus == ESysApMemoryCardLocked )
                {
                append = ETrue;
                }
            else if ( ( aInclusionMask & EIncludeNonInserted ) &&
                entry.iStatus == ESysApMemoryCardNotInserted )
                {
                append = ETrue;
                }
            else if ( ( aInclusionMask & EIncludeLocked ) &&
                entry.iStatus == ESysApMemoryCardLocked )
                {
                append = ETrue;
                }
            if ( append )
                {
                aMemoryCardArray.AppendL( entry );
                }
            }
        }

    TRACES( RDebug::Print(
        _L( "CSysApDriveList::GetMemoryCardsL: count: %d, inclusion: 0x%x" ),
        aMemoryCardArray.Count(), aInclusionMask ) );
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::GetFormattedDriveNameLC
// ---------------------------------------------------------------------------
//
HBufC* CSysApDriveList::GetFormattedDriveNameLC(
        const TInt aDrive,
        const TInt aTextIdForDefaultName,
        const TInt aTextIdForName ) const
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::GetFormattedDriveNameLC: drive: %d" ),
        aDrive ) );

    TDriveName drvLetter( TDriveUnit( aDrive ).Name() );
    TPtrC drvName;
    TVolumeInfo drvVolumeInfo;
    if ( iFs.Volume( drvVolumeInfo, aDrive ) == KErrNone )
        {
        drvName.Set( drvVolumeInfo.iName );
        }
    HBufC* ret = NULL;
    if ( aTextIdForName && ( drvName.Length() || !aTextIdForDefaultName ) )
        {
        CDesCArray* array = new( ELeave ) CDesCArrayFlat(
            KNameFormatArrayLen );
        CleanupStack::PushL( array );
        array->AppendL( drvLetter );
        array->AppendL( drvName );
        ret = StringLoader::LoadL( aTextIdForName, *array );
        CleanupStack::PopAndDestroy( array );
        }
    else if ( aTextIdForDefaultName )
        {
        ret = StringLoader::LoadL( aTextIdForDefaultName, drvLetter );
        }
    else
        {
        User::Leave( KErrNotFound );
        }
    CleanupStack::PushL( ret );
    return ret;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::UpdateDrive
// ---------------------------------------------------------------------------
//
void CSysApDriveList::UpdateDrive( TInt aDrive, TBool aForceUpdate )
    {
    TDriveStateEntry& entry( iStatusCache[ aDrive ] );
    if ( !aForceUpdate && ( entry.iState & EStateStatusUpdated ) )
        {
        return;
        }

    TUint drvStatus( 0 );
    DriveInfo::GetDriveStatus( iFs, aDrive, drvStatus );

    TSysApMemoryCardStatus memoryCardStatus( ESysApMemoryCardStatusNotKnown );
    if ( drvStatus & DriveInfo::EDriveRemovable )
        {
        // Set memory card status for physically 
        // removable memory cards only
        if ( drvStatus & DriveInfo::EDriveLocked )
            {
            memoryCardStatus = ESysApMemoryCardLocked;
            }
        else if ( drvStatus & DriveInfo::EDrivePresent )
            {
            memoryCardStatus = ESysApMemoryCardInserted;
            }
        else
            {
            memoryCardStatus = ESysApMemoryCardNotInserted;
            }
        }

    TRACES( RDebug::Print(
        _L( "CSysApDriveList::UpdateDrive: drive: %d, drvStatus: 0x%x, memoryCardStatus: %d" ),
        aDrive, drvStatus, memoryCardStatus ) );

    entry.iStatus = memoryCardStatus;
    entry.iState |= EStateStatusUpdated;
    entry.iDriveStatus = drvStatus;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::Find
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::Find(
        const RArray< TMemoryCardEntry >& aMemoryCardArray,
        TInt aDrive )
    {
    return aMemoryCardArray.Find( aDrive, TMemoryCardEntry::CompareFind );
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::MarkDriveToEject
// ---------------------------------------------------------------------------
//
void CSysApDriveList::MarkDriveToEject(
        TInt aDrive, TDriveEjectType aEjectUsed )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::MarkDriveToEject: drive: %d, ejectType:%d" ),
        aDrive, aEjectUsed ) );

    ResetDriveToEject( aDrive );
    switch ( aEjectUsed )
        {
        case EEjectFromMenu:
            {
            iStatusCache[ aDrive ].iState |= EStateEjectedFromMenu;
            break;
            }
        case EEjectRemovedWithoutEject:
            {
            iStatusCache[ aDrive ].iState |= EStateRemovedWithoutEject;
            break;
            }
        default:
            {
            break;
            }
        }
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::ResetDriveToEject
// ---------------------------------------------------------------------------
//
void CSysApDriveList::ResetDriveToEject( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::ResetDriveToEject: drive: %d" ), aDrive ) );

    iStatusCache[ aDrive ].iState &= ~EStateAllEjected;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::ResetDrivesToEject
// ---------------------------------------------------------------------------
//
void CSysApDriveList::ResetDrivesToEject()
    {
    for ( TInt i( 0 ); i < KMaxDrives; ++i )
        {
        ResetDriveToEject( i );
        }
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::DriveToEject
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::DriveToEject( TDriveEjectType& aEjectUsed )
    {
    aEjectUsed = EEjectNone;
    TInt ret( KErrNotFound );
    for ( TInt i( 0 ); i < KMaxDrives; ++i )
        {
        TUint state( iStatusCache[ i ].iState );
        if ( state & EStateAllEjected )
            {
            // Store current drive to eject
            ret = i;
            if ( state & EStateEjectedFromMenu )
                {
                aEjectUsed = EEjectFromMenu;
                }
            else if ( state & EStateRemovedWithoutEject )
                {
                aEjectUsed = EEjectRemovedWithoutEject;
                }
            break;
            }
        }
    return ret;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::IsDriveToEject
// ---------------------------------------------------------------------------
//
TBool CSysApDriveList::IsDriveToEject( TInt aDrive )
    {
    if ( iStatusCache[ aDrive ].iState & EStateAllEjected )
        {
        return ETrue;
        }
    return EFalse;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::MarkDrivesInsertBeepIgnored
// ---------------------------------------------------------------------------
//
void CSysApDriveList::MarkDrivesInsertBeepIgnored(
      const RArray< TMemoryCardEntry >& aArray )
    {
    TInt count( aArray.Count() );
    for( TInt i( 0 ); i < count; ++i )
        {
        MarkDriveInsertBeepIgnored( aArray[ i ].iDrive );
        }
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::MarkDriveInsertBeepIgnored
// ---------------------------------------------------------------------------
//
void CSysApDriveList::MarkDriveInsertBeepIgnored( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::MarkDriveInsertBeepIgnored: drive: %d" ),
        aDrive ) );

    iStatusCache[ aDrive ].iState |= EStateBeepIgnored;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::ResetDriveInsertBeepIgnored
// ---------------------------------------------------------------------------
//
void CSysApDriveList::ResetDriveInsertBeepIgnored( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::ResetDriveInsertBeepIgnored: drive: %d" ),
        aDrive ) );

    iStatusCache[ aDrive ].iState &= ~EStateBeepIgnored;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::ResetDrivesInsertBeepIgnored
// ---------------------------------------------------------------------------
//
void CSysApDriveList::ResetDrivesInsertBeepIgnored()
    {
    for ( TInt i( 0 ); i < KMaxDrives; ++i )
        {
        ResetDriveInsertBeepIgnored( i );
        }
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::IsDriveInsertBeepIgnored
// ---------------------------------------------------------------------------
//
TBool CSysApDriveList::IsDriveInsertBeepIgnored( TInt aDrive )
    {
    if ( iStatusCache[ aDrive ].iState & EStateBeepIgnored )
        {
        return ETrue;
        }
    return EFalse;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::MarkDriveUnlockQueryShown
// ---------------------------------------------------------------------------
//
void CSysApDriveList::MarkDriveUnlockQueryShown( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::MarkDriveUnlockQueryShown: drive: %d" ),
        aDrive ) );

    iStatusCache[ aDrive ].iState |= EStateUnlockQueryShown;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::ResetDriveUnlockQueryShown
// ---------------------------------------------------------------------------
//
void CSysApDriveList::ResetDriveUnlockQueryShown( TInt aDrive )
    {
    TRACES( RDebug::Print(
        _L( "CSysApDriveList::ResetDriveUnlockQueryShown: drive: %d" ),
        aDrive ) );

    iStatusCache[ aDrive ].iState &= ~EStateUnlockQueryShown;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::DriveToUnlock
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::DriveToUnlock()
    {
    TInt ret( KErrNotFound );
    for ( TInt i( 0 ); i < KMaxDrives; ++i )
        {
        TDriveStateEntry& entry( iStatusCache[ i ] );
        if ( entry.iStatus == ESysApMemoryCardLocked &&
            !( entry.iState & EStateUnlockQueryShown ) )
            {
            ret = i;
            break;
            }
        }
    return ret;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::TMemoryCardEntry::CompareFind
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::TMemoryCardEntry::CompareFind(
        const TInt* aDrive, const TMemoryCardEntry& aEntry )
    {
    return *aDrive == aEntry.iDrive;
    }

// ---------------------------------------------------------------------------
// CSysApDriveList::NonUsbDriveCount
// ---------------------------------------------------------------------------
//
TInt CSysApDriveList::NonUsbDriveCount( const RArray< TMemoryCardEntry >& aDriveArray )
    {
    TInt ret( 0 );
    TInt count( aDriveArray.Count() );
    for( TInt i( 0 ); i < count; ++i )
        {
        if ( !( aDriveArray[ i ].iDriveStatus & DriveInfo::EDriveUsbMemory ) )
            {
            ++ret;
            }
        }
    TRACES( RDebug::Print( _L( "CSysApDriveList::NonUsbDriveCount: %d" ), ret ) );
    return ret;
    }

// End of File
