/*
* Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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: 
*
*/


#include "backuprestore.h"

#include <s32mem.h>

#include "sisregistryentry.h"
#include "sisregistrywritableentry.h"
#include "siscontroller.h"
#include "cleanuputils.h"
#include "sisregistrypackage.h"
#include "log.h"
 

namespace Swi
	{
	
	EXPORT_C TInt RBackupSession::Connect()
		{
		DEBUG_PRINTF(_L8("RBackupSession::Connect"));
		return iSession.Connect();		
		}
		
	EXPORT_C void RBackupSession::Close()
		{
		DEBUG_PRINTF(_L8("RBackupSession::Close"));
		iSession.Close();		
		}

	// Format for metadata ( Ensure that nothing is added in between to maintain compatability) :
	// Drive ( for Base SA ) + No of Controllers ( SA + PU + SP ) + Controllers for SA and PU +
	// Controllers for Augmentation + File Count + File Names Array ( for SA,PU and SP ) + 
	// Augmentation Drives + Matching Supported Languages ( for SA and SP with ELANGNONE as separator )
		
	EXPORT_C HBufC8* RBackupSession::GetMetaDataL(TUid aPackageUid, RPointerArray<HBufC>& aFilesArray)
		{
		DEBUG_PRINTF2(_L8("Getting backup meta data for puid=0x%08x"), aPackageUid.iUid);
		RSisRegistryWritableEntry entry;
		User::LeaveIfError(entry.Open(iSession, aPackageUid));
		CleanupClosePushL(entry);
		
		RPointerArray<HBufC8> controllers;
		entry.ControllersL(controllers);
		CleanupResetAndDestroyPushL(controllers);
		
		const TInt KDefaultBufferSize = 2048;
		
		CBufFlat* tempBuffer = CBufFlat::NewL(KDefaultBufferSize);
		CleanupStack::PushL(tempBuffer);
		
		// Include the drive letter at the head of the metadata
		TChar drive = entry.SelectedDriveL();
		RArray<TLanguage> matchingSupportedLanguagesArray;
		CleanupClosePushL(matchingSupportedLanguagesArray);
		entry.GetMatchingSupportedLanguagesL(matchingSupportedLanguagesArray);
		// Appending ELangNone at the end as marker for the end of the language IDs
		// as we also append the language ID's from Augmentations
		matchingSupportedLanguagesArray.AppendL(ELangNone);

		RPointerArray<CSisRegistryPackage> packages;
		CleanupResetAndDestroyPushL(packages);
		entry.AugmentationsL(packages);

        TInt augmentationCount(packages.Count());
        TInt augCount = augmentationCount;
		
		RBufWriteStream stream(*tempBuffer);
		CleanupClosePushL(stream);
        stream.WriteUint32L(drive); 
        
		if (entry.RemovableL()) //Cannot Backup non-removable (NR) packages
	    {
	        // backup the base package (except for PA and ROM stubs) plus partial upgrades and augmentations.		
            entry.FilesL(aFilesArray);
		
            // Filter out any files on the Z drive
            TInt fileIndex = aFilesArray.Count() - 1;
            while (fileIndex >= 0)
                {
                TChar driveCh = (*aFilesArray[fileIndex])[0];
                if (driveCh == 'z' || driveCh == 'Z')
                    {
                    delete aFilesArray[fileIndex];
                    aFilesArray.Remove(fileIndex);
                    }
                --fileIndex;
                }

            TInt controllersCount = controllers.Count();
            TInt firstController = 0;
            if (entry.PreInstalledL() || entry.IsInRomL())
                {
                firstController = 1;	// Don't backup the controller for the ROM stub 
                if (controllersCount <= 1)
                    {				
                    DEBUG_PRINTF(_L8("Base package is pre-installed or in ROM and has not been upgraded"));				
                    stream.WriteInt32L(packages.Count());
                    if (entry.IsInRomL())
                        {
                        matchingSupportedLanguagesArray.Close();
                        }
                    }			
                else 
                    {
                    // Backup any PUs for the ROM stub.
                    DEBUG_PRINTF2(_L8("Found %d partial upgrades"), controllersCount - 1);				
                    stream.WriteInt32L(controllersCount - 1 + packages.Count());
                    }
                }
            else
                {
                // Standard SA package
                DEBUG_PRINTF2(_L8("Found %d controllers"), controllersCount);		
                stream.WriteInt32L(controllers.Count() + packages.Count());			
                }
		
            for (TInt i = firstController; i < controllersCount; ++i)
                {
                stream << *controllers[i];
                }
            
			}
		else
		    {
                if(!augmentationCount)
                {
                    DEBUG_PRINTF2(_L("RBackupSession::GetMetaDataL - Cannot Backup non-removable application; Uid: '0x%08x'"),aPackageUid.iUid);
                    CleanupStack::PopAndDestroy(6, &entry); // stream, controllers, matchingSupportedLanguagesArray, tempBuffer, packages, entry
                    User::Leave(KErrNotSupported); // cannot remove non-removable (NR) packages 
                }
                else
                {
                for (TInt i = 0; i < augmentationCount; ++i)
                    {           
                    RSisRegistryEntry augmentation;
                    augmentation.OpenL(iSession, *packages[i]);
                    CleanupClosePushL(augmentation);
                    
                     if (!augmentation.RemovableL())
                        {                      
                            augCount--;
                            CleanupStack::PopAndDestroy(1, &augmentation);
                            continue;
                        }
                     CleanupStack::PopAndDestroy(1, &augmentation);
                    }
                if(!augCount)
                    {
                    DEBUG_PRINTF2(_L("RBackupSession::GetMetaDataL - Cannot Backup non-removable augmentation; Uid: '0x%08x'"),aPackageUid.iUid);
                    CleanupStack::PopAndDestroy(6, &entry); // stream, controllers, matchingSupportedLanguagesArray, tempBuffer, packages, entry
                    User::Leave(KErrNotSupported); // cannot remove non-removable (NR) packages 
                    }
                else
                    {
                    stream.WriteInt32L(augCount); // Writing removable augmentations controller count  
                    if (entry.IsInRomL())
                        {
                        matchingSupportedLanguagesArray.Close();
                        }
                    }
                }
		    }

		RArray<TChar> augmentationDrives;
		CleanupClosePushL(augmentationDrives);
		
		TBool nonRemovableAugmentation = ETrue;
		
		for (TInt i = 0; i < augmentationCount; ++i)
			{			
			RSisRegistryEntry augmentation;
			augmentation.OpenL(iSession, *packages[i]);
			CleanupClosePushL(augmentation);
			
			if(augCount != augmentationCount)
			    {
                 if (!augmentation.RemovableL()) //if loops are not clubed to avoid augmentation.RemovableL() API Call
                    {		          
                        CleanupStack::PopAndDestroy(1, &augmentation);
                        continue;
                    }
			    }
		    nonRemovableAugmentation = EFalse;
		    
			augmentation.FilesL(aFilesArray);
			
			RPointerArray<HBufC8> augmentationControllers;
			CleanupResetAndDestroyPushL(augmentationControllers);
			augmentation.ControllersL(augmentationControllers);

			stream << *augmentationControllers[0];
			
			DEBUG_PRINTF3(_L("Augmentation %d installed to drive %d"), i, augmentation.SelectedDriveL().GetNumericValue());
			// The drives for all SPs need to be appended after the file to
			// list to preserve BC with backup data created before SP drives
			// were backed up.
			augmentationDrives.AppendL(augmentation.SelectedDriveL());
			// Get the matching supported languages
			entry.GetMatchingSupportedLanguagesL(matchingSupportedLanguagesArray);

			// Appending ELangNone at the end as marker for the end of the language IDs
			// as we also append the language ID's from other Augmentations
			matchingSupportedLanguagesArray.AppendL(ELangNone);

			CleanupStack::PopAndDestroy(2, &augmentation);
			}
			
		if(nonRemovableAugmentation && augmentationCount)
		    {
            DEBUG_PRINTF2(_L("RBackupSession::GetMetaDataL - Cannot Backup non-removable Augmentation; Uid: '0x%08x'"),aPackageUid.iUid);
            CleanupStack::PopAndDestroy(7, &entry); // augmentationDrives, stream, controllers, matchingSupportedLanguagesArray, tempBuffer, packages
            User::Leave(KErrNotSupported); // cannot remove non-removable (NR) packages 
		    }
		
		// Write the number of files originally installed,
  		// and their names to the backup metadata		
  		TInt filesCount(aFilesArray.Count());
		DEBUG_PRINTF2(_L8("Files installed originally %d"), filesCount);
  		stream.WriteInt32L(filesCount);
  		for (TInt i = 0; i < filesCount; ++i)
  			{
  			stream << *aFilesArray[i];
  			}

		// Add the selected drive for each augmentation in the same order as
		// as the list of controllers.  The augmentation controllers will
		// be counted on restore to be sure to correct number of drives.
  		for (TInt k = 0; k < augCount; ++k)
  			{
			stream.WriteUint32L(augmentationDrives[k]);
  			}

		//Add the array of matching device supported languages
  		TInt supportedLanguageCount = matchingSupportedLanguagesArray.Count();
  		
		stream.WriteInt32L(supportedLanguageCount);
  		for (TInt k = 0; k < supportedLanguageCount; ++k)
  			{
			stream.WriteInt32L(matchingSupportedLanguagesArray[k]);
  			}
        
		stream.CommitL();
		
		HBufC8* result = tempBuffer->Ptr(0).AllocL();
		CleanupStack::PopAndDestroy(7, &entry); // augmentationDrives, stream, controllers, matchingSupportedLanguagesArray, tempBuffer, packages
		return result; 
		
		}	
	}
