/*
* Copyright (c) 2006-2009 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: 
* @internalComponent * @released
* Driveimage class implementation.
*
*/


#include <stdlib.h>
#include <string>
#include "fsnode.h"
#include "fatimagegenerator.h"
#include <boost/filesystem.hpp>
#include <stack>
#include <utility>
#include <new>
using namespace boost ;
#ifdef __LINUX__
	
	#include <dirent.h>
	#ifndef MKDIR
		#define MKDIR(a)	mkdir(a,0777)
	#endif
#else
	#ifdef _STLP_INTERNAL_WINDOWS_H
	#define __INTERLOCKED_DECLARED
	#endif
	#include <windows.h>
	#include <direct.h>
	#ifndef MKDIR
		#define MKDIR		mkdir
	#endif
#endif
#include <sys/stat.h>
#include <sys/types.h>
using namespace std;


#include <f32file.h>
#include "h_utl.h"
#include "r_obey.h"
#include "r_romnode.h"
#include "r_rofs.h"
#include "r_driveimage.h"
 
/**
Constructor: CDriveImage class 

@param aObey - pointer to Drive obey file.
*/
CDriveImage::CDriveImage(CObeyFile *aObey)
	: iObey( aObey )
{
}


CDriveImage::~CDriveImage()
{
 
}
/**
	* 
  */
TFSNode* CDriveImage::PrepareFileSystem(TRomNode* aRomNode){ 
	TUint8 attrib ;
	TFSNode* root = 0;
	TRomNode* romNode = aRomNode;
	stack<pair<TRomNode*,TFSNode*> > nodesStack ;
	TFSNode* parentFS = 0 ;
	TFSNode* curFS = 0;
	bool err = false ;
    while(1) {
        attrib = 0 ;
        if(romNode->iAtt & KEntryAttReadOnly)
			attrib |= ATTR_READ_ONLY ;
		if(romNode->iAtt & KEntryAttHidden)
			attrib |= ATTR_HIDDEN ;
		if(romNode->iAtt & KEntryAttSystem)
			attrib |= ATTR_SYSTEM ;  
		if(romNode->IsDirectory()) {		  
			curFS = new(std::nothrow)  TFSNode(parentFS,romNode->iName,attrib | ATTR_DIRECTORY);
			if(!curFS){
					err = true ;
					break ;
			} 
			if(!root) root = curFS ;  
			time_t now = time(NULL); 
			curFS->Init(now,now,now,0); 
			TRomNode* child = romNode->Currentchild();
			if(child){
				TRomNode* sibling = romNode->Currentsibling(); 
				if(sibling)
					nodesStack.push(make_pair(sibling,parentFS));
				romNode = child ;
				parentFS = curFS ;
				continue ;
			}			
		}
		else { // file             
				curFS = new(std::nothrow) TFSNode(parentFS,romNode->iEntry->iName,attrib,romNode->iEntry->iFileName);
				if(!curFS){
					err = true ;
					break ;
				} 
					
				if(!root) root = curFS ;  
				struct stat statbuf ;
				stat(romNode->iEntry->iFileName, &statbuf);             
				curFS->Init(statbuf.st_ctime,statbuf.st_atime,statbuf.st_mtime,statbuf.st_size);   
		 
		}
		
		TRomNode* sibling = romNode->Currentsibling(); 
		if(sibling) {
			romNode = sibling ; 
		}
		else { 
			if(nodesStack.empty()) {
				break ;
			}
			else {
				romNode = nodesStack.top().first;
				parentFS = nodesStack.top().second ;
				nodesStack.pop() ;
				
			}
		}		
    }
	if(err) {
		if(root) delete root ;
		return NULL ;
	}
    return root ;
} 

/**
Creates the Image/Call to file system module.

Updates the required operations to generate the data drive images.
Deletes the temp folder if created.
Calls the file system modules with required parameters.

@param alogfile - Logfile name required for file system module.
@return Status(r) - returns the status of file system module.
                   'KErrGeneral' - Unable to done the above operations properly.
*/
TInt CDriveImage::CreateImage(const char* alogfile) {
	
	TSupportedFatType fst = EFatUnknown ;
	if(stricmp(iObey->iDriveFileFormat,"FAT16") == 0)
	    fst = EFat16 ;
	else if(stricmp(iObey->iDriveFileFormat,"FAT32") == 0)
	        fst = EFat32 ;
	if(EFatUnknown == fst){
        Print(EError,"Unsupported FAT type : %s",iObey->iDriveFileFormat);
        return KErrGeneral ;
	}
	 
	TFatImgGenerator generator(fst,iObey->iConfigurableFatAttributes);
	
	if(!generator.IsValid()){
	    return KErrGeneral; 
	}
	TFSNode* root = PrepareFileSystem(iObey->iRootDirectory);
	if(!root)
	    return KErrGeneral;
	
 
	TInt retVal = generator.Execute(root,iObey->iDriveFileName) ? KErrNone : KErrGeneral;
	
	delete root ;
		
	return 	retVal;
}
