/*
* 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:  Active object that manages saving and deletion of images*
*/



// INCLUDE FILES
#include <badesca.h>
#include <eikenv.h>
#include <sysutil.h>
#include <AknProgressDialog.h>
#include <eikprogi.h>
#include <StringLoader.h>
#include <AknQueryDialog.h>
#include <pathinfo.h>

// includes to allow reporting to LifeBlog via publish and subscribe API
#include <e32property.h>

#include <cameraapp.rsg>
#include <vgacamsettings.rsg>

#include "CamImageSaveActive.h"
#include "CamPanic.h"
#include "CamUtility.h"
#include "CamPerformance.h"
#include "cambuffershare.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "CamImageSaveActiveTraces.h"
#endif
#include "camuidconstants.h" // KPSUidCamcorderNotifier

#include "CameraappPrivateCRKeys.h"

#include "CamAppController.h"
#include "CameraUiConfigManager.h"
#include "CamBurstCaptureArray.h"

const TUint32 KCamLatestFilePath      = 0x00000001;
const TInt    KArrayGranularity       = 2;
const TInt    KCapturedAlbumId        = 2; 

// CONSTANTS

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

// -----------------------------------------------------------------------------
// CCamImageSaveActive::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CCamImageSaveActive* CCamImageSaveActive::NewL( MCamImageSaveObserver& aObserver,  
                                                CCamAppController&  aController )
    {
    PRINT( _L("Camera => CCamImageSaveActive::NewL") );

    CCamImageSaveActive* self = new( ELeave ) CCamImageSaveActive( aObserver, 
                                                                   aController );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    PRINT( _L("Camera <= CCamImageSaveActive::NewL") );
    return self;
    }

    
// -----------------------------------------------------------------------------
// CCamImageSaveActive::~CCamImageSaveActive
// Destructor
// -----------------------------------------------------------------------------
//
CCamImageSaveActive::~CCamImageSaveActive()
    {
    PRINT( _L("Camera => ~CCamImageSaveActive") );
    delete iSaveArray;

    delete iNameArray;
    iSnapArray.ResetAndDestroy();
    delete iManager;
            
    ReleaseAllAndDestroy( iImageArray );
    iImageArray.Close();

    iThumbnailRequests.Close();
    DoDismissProgressNote();

#if defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)
    DeRegisterHarverterClientEvents();
#endif // defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)

    PRINT( _L("Camera <= ~CCamImageSaveActive") );
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::Cancel
// Cancel any current or pending actions
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::Cancel()
    {
    PRINT( _L( "Camera => CCamImageSaveActive::Cancel" ) );
 
    TBool storageOk( ETrue );
    if ( iController.SequenceCaptureInProgress() )
        {
        TCamMediaStorage storageLocation = static_cast<TCamMediaStorage> ( 
                iController.IntegerSettingValueUnfiltered(  
                        ECamSettingItemPhotoMediaStorage ) );
        if ( storageLocation == ECamMediaStorageCard )
            {
            // Avoid deleting and saving to drive which does not exist
            storageOk = CamUtility::MemoryCardStatus() == ECamMemoryCardInserted;
            PRINT1( _L( "Camera => CCamImageSaveActive::Cancel storageOk=%d" ), storageOk);
            }
        }

    // Since this function may be called in the destructor, we need to check
    // that iSaveArray is not null. 
    if(iSaveArray)
        {
        TInt count = iSaveArray->Count() - 1;
        TInt lowest = 0;
        if ( iSaveCurrent )
            {
            lowest = 1;
            }
        TInt i;

        // Delete all dummy files except any currently saving one
        for ( i = count; i >= lowest; i-- )
            {
            PRINT1( _L( "Camera Deleting file index %d" ), i );         
            if( storageOk )
                {
                DeleteFile( iSaveArray->MdcaPoint( i ), ETrue );  
                }
            }
        }
    // if a file is currently saving, delay cleanup till save completes
    // if ( iSaveCurrent )
    if ( IsActive() && storageOk )
        {
        PRINT( _L( "Camera File currently saving delay cleanup" ) );         
        iDoCancel = ETrue;
        if ( !iWait.IsStarted() )
          {
          iWait.Start();
          }
        }
    // otherwise, complete cleanup now
    else
        {
        PRINT( _L( "Camera No file saving cleanup now" ) );         
        DoDismissProgressNote();
        CActive::Cancel();
        if(iSaveArray)
            {
            iSaveArray->Reset();
            }
        ReleaseAllAndDestroy( iImageArray );
        }
    PRINT( _L( "Camera <= CCamImageSaveActive::Cancel" ) );         
    }

void CCamImageSaveActive::ForceCancel()
{
    CActive::Cancel();
}
// -----------------------------------------------------------------------------
// CCamImageSaveActive::AddToSave
// Add an image to the list of required saves, activate if needed
// -----------------------------------------------------------------------------
//
TBool CCamImageSaveActive::AddToSave( const TDesC&     aFilename, 
                                      CCamBufferShare* aImageData )
    {
    PRINT( _L("Camera => CCamImageSaveActive::AddToSave") );
    if( aImageData )
      {
      aImageData->Reserve();
      }

    // Keep note of how many items exist before we try to add a new one
    TInt count = iSaveArray->Count();
    TRAPD( err, iSaveArray->AppendL( aFilename ) );
    if ( !err )
        {
        TRAP( err, iImageArray.AppendL( aImageData ) );
        }
    // if any of the appends failed then clean out the partial item
    if ( err )
        {
        if ( iSaveArray->Count() > count )
            {
            iSaveArray->Delete( count );
            }
        if ( iImageArray.Count() > count )
            {
            iImageArray.Remove( count );
            if( aImageData )
              {
              aImageData->Release();
              }
            }
        PRINT( _L("Camera <= CCamImageSaveActive::AddToSave, error!") );
        return EFalse;
        }
    // the item is successfully added, start the save now if not currently saving
    if ( !IsActive() )
        {
        SetActiveAndCompleteRequest();
        }

    PRINT( _L("Camera <= CCamImageSaveActive::AddToSave, ok") );
    return ETrue;
    }
 
 
// -----------------------------------------------------------------------------
// CCamImageSaveActive::FileSize
// Returns the size of the data for the specified file
// -----------------------------------------------------------------------------
//    
TInt CCamImageSaveActive::FileSize( const TDesC& aFilename ) const
    {    
    TInt size = KErrNotFound;
    TInt count = iSaveArray->Count();
    TInt i;
    
    // Check to see if it is in the "to be saved" array
    for ( i = 0; i < count ; i++ )
        {
        TPtrC ptr = (*iSaveArray)[i];
        if ( aFilename.Compare( ptr ) == 0 )    
            {
            TRAP_IGNORE( size = iImageArray[i]->SharedBuffer()->DataL( 0 )->Size() );
            // size = iImageArray[i]->Size();
            return size;
            }
        }   
        
    // If we have got here, the requested file is NOT in the array
    // Check the file system to see if we have already saved it.
    RFs& fs = CEikonEnv::Static()->FsSession();
    RFile file;
    TInt ret = file.Open( fs, aFilename, EFileShareAny | EFileRead );    
    if ( ret == KErrNone )
        {
        file.Size( size );                
        }
    file.Close();        
    return size;
    }
    
    
    
// -----------------------------------------------------------------------------
// CCamImageSaveActive::DeleteFile
// Delete a file, cancelling any pending save
// -----------------------------------------------------------------------------
//
TInt CCamImageSaveActive::DeleteFile( const TDesC& aFilename, 
                                      TBool aSaveRequested )
    {
    RFs& fs = CEikonEnv::Static()->FsSession();
    if ( aSaveRequested )
        {
        TInt index;
        if ( iSaveArray->Find( aFilename, index ) == 0 )
            {
            // if the file is currently being saved
            if ( index == 0 && iSaveCurrent )
                {
                iDeleteCurrent = ETrue;
                return ETrue;
                }
            else
                {
                iSaveArray->Delete( index );
                iSaveArray->Compress();

                CCamBufferShare* item = iImageArray[index];
                iImageArray.Remove( index );
                if( item )
                  {
                  item->Release();
                  item = NULL;
                  }

                iImageArray.Compress();
                }
            } 
        }

    // Dummy files are read only for protection, make sure the file is writable
    fs.SetAtt( aFilename, 0, KEntryAttReadOnly );
    TInt ret = fs.Delete( aFilename );  
    ReportToObserver( ECamSaveEventDeleted );

    return ret;
    }

// ---------------------------------------------------------------------------
// CCamImageSaveActive::AlreadySavedFile
// Returns whether a particular file has already been saved.
// ---------------------------------------------------------------------------
//
TBool CCamImageSaveActive::AlreadySavedFile( const TDesC& aFilename ) const
    {
    TInt index;
    return iSaveArray->Find( aFilename, index );
    }

// ---------------------------------------------------------------------------
// CCamImageSaveActive::CurrentlySavingFile
// Returns whether a particular file is in the process of being saved.
// ---------------------------------------------------------------------------
//
TBool CCamImageSaveActive::CurrentlySavingFile( const TDesC& aFilename ) const
    {
    TInt index;
    if ( iSaveCurrent && ( iSaveArray->Find( aFilename, index ) == 0 ) &&
        ( index == 0 ) )
        {
        return ETrue;
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DisplayProgressNote
// Display the saving progress note until cancelled or completed
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::DisplayProgressNote( TInt aExpectedImages )
    {
    __ASSERT_DEBUG( !iDismissNote, CamPanic( ECamPanicInvalidState ) );
    // Initialise for a new burst set
    iSaveProgressCount = 0;
    iExpectedImages = aExpectedImages;
    iShowNote = ETrue;
    if ( !IsActive() )
        {
        SetActiveAndCompleteRequest();
        }
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DismissProgressNote
// Dismiss the saving progress note when completed
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::DismissProgressNote()
    {
    // if the progress note is still pending
    if ( iShowNote )
        {
        // the burst has completed already
        iShowNote = EFalse;
        ReportToObserver( ECamSaveEventBurstComplete );
        }

    // No saves are pending, dismiss the note now
    if ( !IsActive() )
        {
        DoDismissProgressNote();
        }
    else // otherwise, wait till all the saves complete
        {
        iDismissNote = ETrue;
        }
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::SetAddImageToAlbum
// Set the "Add to album" feature on or off for photos
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::SetAddImageToAlbum( const TBool aAdding, 
                                              const TUint32 aDefaultAlbumId )
    {
    iAddImageToAlbum = aAdding;
    iDefaultAlbumId = aDefaultAlbumId;
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::AddToAlbum
// Add the specified photo or video to the default capture album
// -----------------------------------------------------------------------------
//
#if defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)
void CCamImageSaveActive::AddToAlbum( const TDesC& aFilename,
                                      const TBool aAddToAlbum,
                                      const TUint32 aDefaultAlbumId )
    {
    OstTrace0( CAMERAAPP_PERFORMANCE_DETAIL, CCAMIMAGESAVEACTIVE_ADDTOALBUM, "e_CCamImageSaveActive_AddToAlbum 1" );
    PRINT( _L("Camera => CCamImageSaveActive::AddToAlbum") );

    TInt err = KErrNone;
    RArray<TUint32> harvestAlbumIds;
    TUint32 harvestAlbumId;
    err = harvestAlbumIds.Append( KCapturedAlbumId ); 

    /*
    * NOTE: The default value of album Id defined as per CenRep key is 0, so 
    *       we add the any other album other than the default one as above
    *       Secondly, if there is no album set as default album from the 
    *       precapture settings views then we pass empty array to the harvester
    *       and MDS harvests the file to camera album directly i.e. captured.
    */

    if ( aAddToAlbum && aDefaultAlbumId > 0 )
       {
       harvestAlbumId = aDefaultAlbumId;
       err = harvestAlbumIds.Append( harvestAlbumId );
       }
    
    if ( !iHarvesterClientConnected )
        {
        PRINT( _L("Camera <> calling iHarvesterClient.Connect") );
        err = iHarvesterClient.Connect();
        if ( !err )
            {
            iHarvesterClientConnected = ETrue;
            }
        PRINT1( _L("Camera <> iHarvesterClient.Connect returned %d"), err );
        }
    
    if ( KErrNone == err )
        {
        RegisterForHarvesterEvents();

        PRINT( _L("Camera <> calling iHarvesterClient.HarvestFile") );

#ifdef RD_MDS_2_5   
        if ( iController.UiConfigManagerPtr() && iController.UiConfigManagerPtr()->IsLocationSupported() )
            {
            TBool location ;
			//Never save location information in second camera
			if(iController.ActiveCamera() == ECamActiveCameraSecondary)
				  {
				  location = EFalse;
				  }
			else
				  {
				  location = iController.IntegerSettingValue( ECamSettingItemRecLocation );
				  }
            iHarvesterClient.HarvestFile( aFilename,
                                          harvestAlbumIds,
                                          location );
            }
        else
            {
            iHarvesterClient.HarvestFile( aFilename,
                                          harvestAlbumIds,
                                          EFalse );
            }
#else // RD_MDS_2_5
        iHarvesterClient.HarvestFile( aFilename,
                                      harvestAlbumIds );
#endif // RD_MDS_2_5
        
        PRINT( _L("Camera <> iHarvesterClient.HarvestFile returned") );
        }
    harvestAlbumIds.Close();

    PRINT( _L("Camera <= CCamImageSaveActive::AddToAlbum") );
    OstTrace0( CAMERAAPP_PERFORMANCE_DETAIL, DUP1_CCAMIMAGESAVEACTIVE_ADDTOALBUM, "e_CCamImageSaveActive_AddToAlbum 0" );
    }
#else // defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)
void CCamImageSaveActive::AddToAlbum( const TDesC&  /*aFilename*/,
                                      const TBool   /*aAddToAlbum*/,
                                      const TUint32 /*aDefaultAlbumId*/ )
    {
    }
#endif // defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)

// -----------------------------------------------------------------------------
// CCamImageSaveActive::Count
// The number of items in the saving array
// -----------------------------------------------------------------------------
//
TInt CCamImageSaveActive::Count() const
    {
    return iSaveArray->Count();
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::CCamImageSaveActive
// C++ constructor
// -----------------------------------------------------------------------------
//
CCamImageSaveActive::CCamImageSaveActive( MCamImageSaveObserver& aObserver,         
                                          CCamAppController&  aController )
    : CActive( EPriorityStandard ), iObserver( aObserver ), 
    iController( aController ),
    iFlushing( EFalse )
    {
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::ConstructL
// 2nd phase construction
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::ConstructL()
    {
    PRINT( _L("Camera => CCamImageSaveActive::ConstructL") );

    iSaveArray = new( ELeave ) CDesCArraySeg( KArrayGranularity );
    iNameArray = new( ELeave ) CDesCArraySeg( KArrayGranularity );
    CActiveScheduler::Add( this );

    PRINT( _L("Camera <= CCamImageSaveActive::ConstructL") );
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::SetActiveAndCompleteRequest
// Schedule to run immediately
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::SetActiveAndCompleteRequest()
    {
    SetActive();
    TRequestStatus* statusPtr = &iStatus;
    User::RequestComplete( statusPtr, KErrNone );
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DoCancel
// Cancels the active object
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::DoCancel()
    {
    PRINT( _L( "Camera => CCamImageSaveActive::DoCancel" ) );      
    iDismissNote = ETrue;
    if ( iWait.IsStarted() )
        {
        iWait.AsyncStop(); 
        }
    iDoCancel = EFalse;
    // if no new saves have been requested since the cancellation
    if ( iSaveArray->Count() == 0 )
        {
        CActive::Cancel();
        iSaveArray->Reset();

        ReleaseAllAndDestroy( iImageArray );
        }
    PRINT( _L( "Camera <= CCamImageSaveActive::DoCancel" ) );                
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::RunL
// Clean up after any previous save, then run the next pending save
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::RunL()
    {
    PRINT( _L( "Camera => CCamImageSaveActive::RunL" ) ); 
    
    if( !iFlushing )
        {
        // if the progress note has been requested
        if ( iShowNote )
            {
            iShowNote = EFalse;
            DoDisplayProgressNoteL();
            }
        // if a save has just completed
        if ( iSaveCurrent )
            {
            CompleteSaveOperation( ETrue );
            //ReportToObserver( ECamSaveEventComplete );
            }
        else
            {
            // If cancellation has been requested
            if ( iDoCancel )
                {
                DoCancel();       
                }
            }
        }
    else
        {
        iFlushing = EFalse;
        CompleteSaveOperation( EFalse );
        ReportToObserver( ECamSaveEventComplete );
        }
    
    if ( !iSaveCurrent )
        {
        // if there are more images to save
        if ( iSaveArray->Count() > 0 )
            {
            DoSaveL();
            }
        // if all saves are complete and the progress note needs to be dismissed
        else if ( iDismissNote )
            {
            DoDismissProgressNote();
            }
        else if ( iNameArray->Count() > 0 )
            {
            DoCreateThumbnailL();
            }    
        else // Do nothing
            {
            }
        }
    PRINT( _L( "Camera <= CCamImageSaveActive::RunL" ) ); 
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::RunError
//
// -----------------------------------------------------------------------------
//
TInt
CCamImageSaveActive::RunError( TInt aError )
  {
  PRINT1( _L( "Camera => CCamImageSaveActive::RunError, error(%d)"), aError ); 
  Cancel();

  if( aError == KErrDiskFull || aError == KErrNotReady )
    {
    if( aError == KErrNotReady  )
      {
      iController.SetCaptureStoppedForUsb( ETrue );
      }
    
    ReportToObserver( ECamSaveEventSaveError );  
    }
  else
    {
    ReportToObserver( ECamSaveEventCriticalError );  
    }

  PRINT ( _L( "Camera <= CCamImageSaveActive::RunError") );
  return KErrNone;
  }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::CompleteSaveOperation
// Clean up after the previous save
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::CompleteSaveOperation( TBool aDoFlush )
    {
    OstTrace0( CAMERAAPP_PERFORMANCE_DETAIL, DUP1_CCAMIMAGESAVEACTIVE_COMPLETESAVEOPERATION, "e_CCamImageSaveActive_CompleteSaveOperation 1" );
    PRINT( _L( "Camera => CCamImageSaveActive::CompleteSaveOperation" ) );     
    if( aDoFlush )
        {
        iFile.Flush(iStatus);
        iFlushing = ETrue;
        SetActive();
        }
    else
        {
        iSaveProgressCount++;
        // if the saving progress note is open
        if ( iSaveProgressDialog && iSaveProgressInfo )
            {
            // Reset inactivity timer.  Need to call this periodically 
            // to keep the backlight on
            User::ResetInactivityTime();
            // Increment the progress in the progress bar
            iSaveProgressInfo->IncrementAndDraw( 1 );
            }
        iSaveCurrent = EFalse;
        iFile.Close();
        // If there is an error or a pending request for deletion
        if ( iDeleteCurrent || iStatus != KErrNone )
            {
            RFs fs = CEikonEnv::Static()->FsSession();
            fs.Delete( iSaveArray->MdcaPoint( 0 ) );
            ReportToObserver( ECamSaveEventDeleted );
            }
        else // the save is successful, add to album if required
            {
            PERF_EVENT_END_L2( EPerfEventSaveImage );         
    
            AddToAlbum( iSaveArray->MdcaPoint( 0 ), 
                        iAddImageToAlbum, 
                        iDefaultAlbumId );
    
            // report to LifeBlog
            RProperty::Set( KPSUidCamcorderNotifier, KCamLatestFilePath, iSaveArray->MdcaPoint( 0 ) ); 
            }
    
        iDeleteCurrent = EFalse;
        
        // Delete the item from the saving arrays
        iSaveArray->Delete( 0 );
        iSaveArray->Compress();
    
        CCamBufferShare* share = iImageArray[0];
        iImageArray.Remove( 0 );
        if( share )
          {
          share->Release();
          share = NULL;
          }
        iImageArray.Compress();
    
        // If cancellation has been requested
        if ( iDoCancel )
            {
            DoCancel();       
            }
        OstTrace0( CAMERAAPP_PERFORMANCE, CCAMIMAGESAVEACTIVE_COMPLETESAVEOPERATION, "e_CAM_APP_SAVE 0" ); 
        }
    PRINT1( _L("Camera <> CCamImageSaveActive .. After this file saving, total shared buffers in use: %d"), CCamBufferShare::TotalBufferShareCount() );
    PRINT( _L( "Camera <= CCamImageSaveActive::CompleteSaveOperation" ) );         
    OstTrace0( CAMERAAPP_PERFORMANCE_DETAIL, DUP2_CCAMIMAGESAVEACTIVE_COMPLETESAVEOPERATION, "e_CCamImageSaveActive_CompleteSaveOperation 0" );
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DoSaveL
// Start a saving operation
// -----------------------------------------------------------------------------
//
void 
CCamImageSaveActive::DoSaveL()
  {
  PERF_EVENT_START_L2( EPerfEventSaveImage );    
  PRINT( _L( "Camera => CCamImageSaveActive::DoSaveL" ) );     
  OstTrace0( CAMERAAPP_PERFORMANCE, CCAMIMAGESAVEACTIVE_DOSAVEL, "e_CAM_APP_SAVE 1" );  //CCORAPP_SAVE_START
  
  TPtrC filename = iSaveArray->MdcaPoint( 0 );

  PRINT1( _L( "Camera <> CCamImageSaveActive: trying to save file:[%S]"), &filename );     

  // Check disk space
  TInt drive = 0;
  __ASSERT_ALWAYS( !RFs::CharToDrive( filename[0], drive ),
      CamPanic( ECamPanicFileSystemError ) );

  RFs& fs = CEikonEnv::Static()->FsSession();

  TDesC8* data    = iImageArray[0]->SharedBuffer()->DataL( 0 );
  TBool   noSpace = SysUtil::DiskSpaceBelowCriticalLevelL( &fs, 
                                                           data->Length(), 
                                                           drive );
  if( noSpace )
    {
    Cancel();
    PRINT( _L( "Camera <> CCamImageSaveActive::DoSaveL .. [WARNING] Disk space below critical, LEAVE!" ) );     
    User::Leave( KErrDiskFull );
    }

  // The dummy file is read only for protection, make it writable now
  // Also unhide it so that media gallery can detect it
  fs.SetAtt( filename, 0, KEntryAttReadOnly|KEntryAttHidden );

  // Open the file
  TInt err = iFile.Open( fs, filename, EFileWrite );

  // if the file does not exist, create a new one
  if ( err == KErrNotFound )
      {
      User::LeaveIfError( iFile.Create( fs, filename, EFileWrite ) );
      }
  // if there was any other problem then leave
  else if ( err != KErrNone )
      {
      User::Leave( err );
      }
  // the file exists
  else
      {
      // Make sure the file is at the start
      TInt seek = 0;
      User::LeaveIfError( iFile.Seek( ESeekStart, seek ) );
      }

  if( iController.CurrentMode() == ECamControllerVideo )
      {
      // set size 
      User::LeaveIfError( iFile.SetSize( data->Size() ) );
      }
  // Write the image data to file
  PRINT( _L( "Camera call iFile.Write" ) );     
  iFile.Write( *(data), iStatus );
  iSaveCurrent = ETrue;
  SetActive();
  PRINT( _L( "Camera <= CCamImageSaveActive::DoSaveL" ) );     
  }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DoDisplayProgressNoteL
// Display the saving progress note
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::DoDisplayProgressNoteL()
    {
    PRINT( _L("Camera => CCamImageSaveActive::DoDisplayProgressNoteL") )
    __ASSERT_DEBUG( iSaveProgressDialog == NULL , CamPanic( ECamPanicUi ) );
    TBool reportOnExit = ETrue;
    // if there are images left to save in this burst set
    if ( iExpectedImages > iSaveProgressCount )
        {
        iSaveProgressDialog = new( ELeave ) CAknProgressDialog( 
            reinterpret_cast<CEikDialog**>( &iSaveProgressDialog ), ETrue );
        iSaveProgressDialog->PrepareLC( R_CAM_SAVING_IMAGES_PROGRESS_NOTE );
        iSaveProgressInfo = iSaveProgressDialog->GetProgressInfoL();
        iSaveProgressInfo->SetFinalValue( iExpectedImages );
        TInt i;
        for ( i = 0; i < iSaveProgressCount; i++ )
            {
            // Increment the progress in the bar for previous saves
            iSaveProgressInfo->IncrementAndDraw( 1 );
            }
        // display the dialog and wait until it is dismissed
        TInt exit = iSaveProgressDialog->RunLD();
        // the dialog has exited and deleted itself
        iSaveProgressDialog = NULL;
        iSaveProgressInfo = NULL;
        // if the dialog was cancelled by the user
        if ( exit == 0 )
            {
            reportOnExit = EFalse;
            iCompletedBurst = ETrue;                
            }
        }
    // if the burst has now completed
    if ( reportOnExit )
        {
        ReportToObserver( ECamSaveEventBurstComplete );            
        }
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DoDismissProgressNote
// Dismiss the progress note, if it is still open
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::DoDismissProgressNote()
    {
    iDismissNote = EFalse;
    if ( iSaveProgressDialog )
        {
        // Delete the dialog and end its RunLD()
        TRAPD( error, iSaveProgressDialog->ProcessFinishedL() ) 
        if (error != KErrNone)
            {
            delete iSaveProgressDialog;
            iSaveProgressDialog = NULL;
            iSaveProgressInfo = NULL;
            }
        }
    // if the progress note is still pending
    if ( iShowNote )
        {
        // report that the burst has completed
        iShowNote = EFalse;
        ReportToObserver( ECamSaveEventBurstComplete );                   
        }
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::ReportToObserver
// Indicate to the observer that saving has finished
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::ReportToObserver( TCamSaveEvent aEvent )
    {
    if ( aEvent == ECamSaveEventComplete && iCompletedBurst )
        {
        aEvent = ECamSaveEventBurstComplete;
        iCompletedBurst = EFalse;
        }    
    iObserver.HandleSaveEvent( aEvent );    
    }


// -----------------------------------------------------------------------------
// ReleaseAllAndDestroy
//
// -----------------------------------------------------------------------------
//
void 
CCamImageSaveActive::ReleaseAllAndDestroy( RPointerArray<CCamBufferShare>& aArray )
  {
  PRINT( _L("Camera => CCamImageSaveActive::ReleaseAllAndDestroy") );

  for( TInt i = aArray.Count()-1; i >= 0; i-- )
    {
    CCamBufferShare* share = aArray[i];
    aArray.Remove( i );
    if( share )
      {
      share->Release();
      share = NULL;
      }
    }

  __ASSERT_DEBUG( aArray.Count() == 0, User::Invariant() );

  // All the data is released.
  // CCamBufferShare destructor is not public, so cannot call ResetAndDestroy.
  aArray.Reset();

  PRINT( _L("Camera <= CCamImageSaveActive::ReleaseAllAndDestroy") );
  }

#if defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)
// -----------------------------------------------------------------------------
// HarvestingComplete
//
// Call Back method from the harvesting client once the harvesting is complete
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::HarvestingComplete( TDesC& aURI
#ifdef RD_MDS_2_5        
                                            , TInt aError 
#endif // RD_MDS_2_5
                                             )
    {
    PRINT( _L("Camera => CCamImageSaveActive::HarvestingComplete") );
#ifdef RD_MDS_2_5        
    PRINT1( _L("Camera <> aError = %d"), aError );

    if ( iController.UiConfigManagerPtr() && 
         iController.UiConfigManagerPtr()->IsThumbnailManagerAPISupported() && 
         iSnapArray.Count() &&
         iNameArray->Count() )
        {
        TRAP_IGNORE( DoCreateThumbnailL() ); 
        }

#endif // RD_MDS_2_5
    iObserver.HandleFileHarvestingComplete();
    PRINT( _L("Camera <= CCamImageSaveActive::HarvestingComplete") );
    }

//
//CCamImageSaveActive::DeRegisterHarverterClientEvents
//
void CCamImageSaveActive::DeRegisterHarverterClientEvents()
    {
    PRINT( _L("Camera => CCamImageSaveActive::DeRegisterHarverterClientEvents") );

    if ( iRegisteredForHarvesterEvents && iHarvesterClientConnected )
        {
        iHarvesterClient.RemoveObserver( this );
        iRegisteredForHarvesterEvents = EFalse;
        iHarvesterClient.Close();
        iHarvesterClientConnected = EFalse;
        }
    else
        {
        // do nothing
        }

    PRINT( _L("Camera <= CCamImageSaveActive::DeRegisterHarverterClientEvents") );
    }


//
//CCamImageSaveActive::RegisterForHarvesterEvents
//
void CCamImageSaveActive::RegisterForHarvesterEvents()
    {
    PRINT( _L("Camera => CCamImageSaveActive::RegisterForHarvesterEvents") );

    if ( !iRegisteredForHarvesterEvents && iHarvesterClientConnected )
        {
        iHarvesterClient.SetObserver( this );
        iRegisteredForHarvesterEvents = ETrue;
        }
    else
        {
        // do nothing
        }

    PRINT( _L("Camera <= CCamImageSaveActive::RegisterForHarvesterEvents") );
    }

#endif // defined(RD_MDS_2_5) && !defined(__WINSCW__) && !defined(__WINS__)

// -----------------------------------------------------------------------------
// CreateThumbnailsL
//
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::CreateThumbnailsL( const CCamBurstCaptureArray& aArray )
    {
    PRINT( _L("Camera => CCamImageSaveActive::CreateThumbnailsL") );
    TInt arrayCount = aArray.Count();
    if ( !iSnapArray.Count() )
      {
      iThumbnailRequests.Reset();
      iThumbnailRequests.ReserveL( arrayCount );
      }
    TInt count(0);
    TInt err(0);
    
    for ( TInt i=0; i < arrayCount; i++ )
        {
        count = iNameArray->Count();        

        CFbsBitmap* snapshot = new( ELeave ) CFbsBitmap();
        if ( aArray.Snapshot( i ) )
            {
            err = snapshot->Duplicate( aArray.Snapshot( i )->Handle() );
            }
        // in case the snapshot is missing, the newly created empty bitmap indicates
        // the thumbnail is created using the imagefile    
        if ( !err )
            {
            snapshot->SetDisplayMode( EColor64K );    
            TRAP( err, iSnapArray.AppendL( snapshot ) );            
            if ( !err ) 
                {
                //append filename (includes full path)
                PRINT1( _L("Camera <> CCamImageSaveActive::CreateThumbnails append file:%S"), &aArray.FileName( i ) );    
                TRAP( err, iNameArray->AppendL( aArray.FileName( i ) ) );
                if ( !err )
                    {
                    TRAP( err, iThumbnailRequests.AppendL( KErrNotFound ) );
                    }
                }
            if ( err  )
                {
                if ( iNameArray->Count() > count )
                    {
                    iNameArray->Delete( count );
                    }
                if ( iSnapArray.Count() > count )
                    {
                    iSnapArray.Remove( count );
                    }
                if ( iThumbnailRequests.Count() > count )
                    {
                    iThumbnailRequests.Remove( count );
                    }
                }
            }
        }     
    PRINT( _L("Camera <= CCamImageSaveActive::CreateThumbnailsL") );
    }

// -----------------------------------------------------------------------------
// CCamImageSaveActive::DoCreateThumbnail
// Add images to album
// -----------------------------------------------------------------------------
//
void CCamImageSaveActive::DoCreateThumbnailL()
    {
    PRINT( _L( "Camera => CCamImageSaveActive::DoCreateThumbnailL" ) );     
    if( !iManager )
        {
        PRINT( _L( "Camera <> CCamImageSaveActive::DoCreateThumbnail create manager" ) );         
        iManager = CThumbnailManager::NewL( *this );
        }
    // create object and call thumbnailmanager
    TSize size = iSnapArray[ 0 ]->SizeInPixels();
    CThumbnailObjectSource* source;
    if ( size.iHeight == 0 || size.iWidth == 0 )
        {
        PRINT( _L( "Camera <> CCamImageSaveActive::DoCreateThumbnail only URI" ) );         
        source = CThumbnailObjectSource::NewL( iNameArray->MdcaPoint( 0 ), 
                                               KNullDesC );
        }
    else
        {
        PRINT( _L( "Camera <> CCamImageSaveActive::DoCreateThumbnail URI and bitmap" ) );             
        source = CThumbnailObjectSource::NewL( iSnapArray[ 0 ], 
                                               iNameArray->MdcaPoint( 0 ) );
        }
    PRINT1( _L("Camera <> CCamImageSaveActive::DoCreateThumbnailL  filename:%S"), &iNameArray->MdcaPoint( 0 ) );        
    CleanupStack::PushL( source );        
    TThumbnailRequestId requestId = iManager->CreateThumbnails( *source );
    TInt index = iThumbnailRequests.Count() - iSnapArray.Count();
    PRINT2( _L( "Camera <> CCamImageSaveActive::DoCreateThumbnailL array index=%d, request id=%d" ), index, requestId );
    iThumbnailRequests[index] = requestId;
    CleanupStack::PopAndDestroy( source );

    iNameArray->Delete( 0 );
    iNameArray->Compress();

    iSnapArray.Remove( 0 );
    iSnapArray.Compress();

    if ( !IsActive() && iNameArray->Count() > 0  )
        {
        SetActiveAndCompleteRequest();
        }
    PRINT( _L( "Camera <= CCamImageSaveActive::DoCreateThumbnailL" ) );         
    }

void CCamImageSaveActive::CancelThumbnail( TInt aSnapshotIndex )
    {
    PRINT1( _L( "Camera => CCamImageSaveActive::CancelThumbnail - aSnapshotIndex=%d" ), aSnapshotIndex );
    if ( aSnapshotIndex >= iThumbnailRequests.Count() )
        {
        PRINT( _L( "Camera <= CCamImageSaveActive::CancelThumbnail request array not initialized yet" ) );
        return;
        }
    TThumbnailRequestId requestId = iThumbnailRequests[aSnapshotIndex];
    if ( requestId != KErrNotFound )
        {
        if ( iManager )
            {
            PRINT1( _L( "Camera <> CCamImageSaveActive::CancelThumbnail canceling request %d"), requestId );
            TInt err = iManager->CancelRequest( requestId );
            PRINT1( _L( "Camera <> CCamImageSaveActive::CancelThumbnail CancelRequest() returned %d"), err );
            iThumbnailRequests[aSnapshotIndex] = KErrNotFound;
            }
        }
    PRINT( _L( "Camera <= CCamImageSaveActive::CancelThumbnail" ) );
    }
void CCamImageSaveActive::ThumbnailPreviewReady( MThumbnailData& aThumbnail, 
                                                 TThumbnailRequestId aId )
    {
	// empty implementation
    }                                                 
          
void CCamImageSaveActive::ThumbnailReady( TInt aError, 
                                          MThumbnailData& aThumbnail, 
                                          TThumbnailRequestId aId )
    {
    PRINT1( _L( "Camera => CCamImageSaveActive::ThumbnailReady aId=%d" ), aId );
    for ( TInt i = 0; i < iThumbnailRequests.Count(); i++ )
        {
        if ( iThumbnailRequests[i] == aId )
            {
            PRINT1( _L( "Camera <> CCamImageSaveActive::ThumbnailReady thumbnail for snapshot %d ready" ), i );
            iThumbnailRequests[i] = KErrNotFound;
            }
        }
    PRINT( _L( "Camera <= CCamImageSaveActive::ThumbnailReady" ) );
    }
                                              
//  End of File  
