## @file
#
# PackageFile class represents the zip file of a distribution package.
#
# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution.  The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#

##
# Import Modules
#
import os
import sys
import zipfile
import tempfile

from Common import EdkLogger
from Common.Misc import *
from Common.BuildToolError import *

class PackageFile:
    def __init__(self, FileName, Mode="r"):
        self._FileName = FileName
        if Mode not in ["r", "w", "a"]:
            Mode = "r"
        try:
            self._ZipFile = zipfile.ZipFile(FileName, Mode, zipfile.ZIP_DEFLATED)
            self._Files = {}
            for F in self._ZipFile.namelist():
                self._Files[os.path.normpath(F)] = F
        except BaseException, X:
            EdkLogger.error("PackagingTool", FILE_OPEN_FAILURE, 
                            ExtraData="%s (%s)" % (FileName, str(X)))

        BadFile = self._ZipFile.testzip()
        if BadFile != None:
            EdkLogger.error("PackagingTool", FILE_CHECKSUM_FAILURE, 
                            ExtraData="[%s] in %s" % (BadFile, FileName))

    def __str__(self):
        return self._FileName

    def Unpack(self, To):
        for F in self._ZipFile.namelist():
            ToFile = os.path.normpath(os.path.join(To, F))
            print F, "->", ToFile
            self.Extract(F, ToFile)
    
    def UnpackFile(self, File, ToFile):
        File = File.replace('\\', '/')
        if File in self._ZipFile.namelist():
            print File, "->", ToFile
            self.Extract(File, ToFile)
            
            return ToFile
        
        return ''
    
    def Extract(self, Which, To):
        Which = os.path.normpath(Which)
        if Which not in self._Files:
            EdkLogger.error("PackagingTool", FILE_NOT_FOUND,
                            ExtraData="[%s] in %s" % (Which, self._FileName))
        try:
            FileContent = self._ZipFile.read(self._Files[Which])
        except BaseException, X:
            EdkLogger.error("PackagingTool", FILE_DECOMPRESS_FAILURE, 
                            ExtraData="[%s] in %s (%s)" % (Which, self._FileName, str(X)))
        try:
            CreateDirectory(os.path.dirname(To))
            ToFile = open(To, "wb")
        except BaseException, X:
            EdkLogger.error("PackagingTool", FILE_OPEN_FAILURE, 
                            ExtraData="%s (%s)" % (To, str(X)))

        try:
            ToFile.write(FileContent)
            ToFile.close()
        except BaseException, X:
            EdkLogger.error("PackagingTool", FILE_WRITE_FAILURE, 
                            ExtraData="%s (%s)" % (To, str(X)))

    def Remove(self, Files):
        TmpDir = os.path.join(tempfile.gettempdir(), ".packaging")
        if os.path.exists(TmpDir):
            RemoveDirectory(TmpDir, True)

        os.mkdir(TmpDir)
        self.Unpack(TmpDir)
        for F in Files:
            F = os.path.normpath(F)
            if F not in self._Files:
                EdkLogger.error("PackagingTool", FILE_NOT_FOUND, 
                                ExtraData="%s is not in %s!" % (F, self._FileName))
            #os.remove(os.path.join(TmpDir, F))  # no need to really remove file
            self._Files.pop(F)
        self._ZipFile.close()

        self._ZipFile = zipfile.ZipFile(self._FileName, "w", zipfile.ZIP_DEFLATED)
        Cwd = os.getcwd()
        os.chdir(TmpDir)
        self.PackFiles(self._Files)
        os.chdir(Cwd)
        RemoveDirectory(TmpDir, True)

    def Pack(self, Top):
        if not os.path.isdir(Top):
            EdkLogger.error("PackagingTool", FILE_UNKNOWN_ERROR, "%s is not a directory!" %Top)

        FilesToPack = []
        ParentDir = os.path.dirname(Top)
        BaseDir = os.path.basename(Top)
        Cwd = os.getcwd()
        os.chdir(ParentDir)
        for Root, Dirs, Files in os.walk(BaseDir):
            if 'CVS' in Dirs:
                Dirs.remove('CVS')
            if '.svn' in Dirs:
                Dirs.remove('.svn')
            for F in Files:
                FilesToPack.append(os.path.join(Root, F))
        self.PackFiles(FilesToPack)
        os.chdir(Cwd)

    def PackFiles(self, Files):
        for F in Files:
            try:
                print "packing ...", F
                self._ZipFile.write(F)
            except BaseException, X:
                EdkLogger.error("PackagingTool", FILE_COMPRESS_FAILURE, 
                                ExtraData="%s (%s)" % (F, str(X)))

    def PackFile(self, File, ArcName=None):
        try:
            print "packing ...", File
            self._ZipFile.write(File, ArcName)
        except BaseException, X:
            EdkLogger.error("PackagingTool", FILE_COMPRESS_FAILURE,
                            ExtraData="%s (%s)" % (File, str(X)))

    def PackData(self, Data, ArcName):
        try:
            self._ZipFile.writestr(ArcName, Data)
        except BaseException, X:
            EdkLogger.error("PackagingTool", FILE_COMPRESS_FAILURE,
                            ExtraData="%s (%s)" % (ArcName, str(X)))

    def Close(self):
        self._ZipFile.close()

if __name__ == '__main__':
    pass