## @file
# process FFS generation from FILE statement
#
#  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
#  SPDX-License-Identifier: BSD-2-Clause-Patent
#

##
# Import Modules
#
from __future__ import absolute_import
from io import BytesIO
from struct import pack
from CommonDataClass.FdfClass import FileStatementClassObject
from Common import EdkLogger
from Common.BuildToolError import GENFDS_ERROR
from Common.Misc import GuidStructureByteArrayToGuidString, SaveFileOnChange
import Common.LongFilePathOs as os
from .GuidSection import GuidSection
from .FvImageSection import FvImageSection
from .Ffs import FdfFvFileTypeToFileType
from .GenFdsGlobalVariable import GenFdsGlobalVariable
import shutil

## generate FFS from FILE
#
#
class FileStatement (FileStatementClassObject):
    ## The constructor
    #
    #   @param  self        The object pointer
    #
    def __init__(self):
        FileStatementClassObject.__init__(self)
        self.FileName = None
        self.InfFileName = None
        self.SubAlignment = None

    ## GenFfs() method
    #
    #   Generate FFS
    #
    #   @param  self         The object pointer
    #   @param  Dict         dictionary contains macro and value pair
    #   @param  FvChildAddr  Array of the inside FvImage base address
    #   @param  FvParentAddr Parent Fv base address
    #   @retval string       Generated FFS file name
    #
    def GenFfs(self, Dict = None, FvChildAddr=[], FvParentAddr=None, IsMakefile=False, FvName=None):

        if self.NameGuid and self.NameGuid.startswith('PCD('):
            PcdValue = GenFdsGlobalVariable.GetPcdValue(self.NameGuid)
            if len(PcdValue) == 0:
                EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \
                            % (self.NameGuid))
            if PcdValue.startswith('{'):
                PcdValue = GuidStructureByteArrayToGuidString(PcdValue)
            RegistryGuidStr = PcdValue
            if len(RegistryGuidStr) == 0:
                EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \
                            % (self.NameGuid))
            self.NameGuid = RegistryGuidStr

        Str = self.NameGuid
        if FvName:
            Str += FvName
        OutputDir = os.path.join(GenFdsGlobalVariable.FfsDir, Str)
        if os.path.exists(OutputDir):
            shutil.rmtree(OutputDir)
        if not os.path.exists(OutputDir):
            os.makedirs(OutputDir)

        if Dict is None:
            Dict = {}

        Dict.update(self.DefineVarDict)
        SectionAlignments = None
        if self.FvName:
            Buffer = BytesIO()
            if self.FvName.upper() not in GenFdsGlobalVariable.FdfParser.Profile.FvDict:
                EdkLogger.error("GenFds", GENFDS_ERROR, "FV (%s) is NOT described in FDF file!" % (self.FvName))
            Fv = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(self.FvName.upper())
            FileName = Fv.AddToBuffer(Buffer)
            SectionFiles = [FileName]

        elif self.FdName:
            if self.FdName.upper() not in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
                EdkLogger.error("GenFds", GENFDS_ERROR, "FD (%s) is NOT described in FDF file!" % (self.FdName))
            Fd = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(self.FdName.upper())
            FileName = Fd.GenFd()
            SectionFiles = [FileName]

        elif self.FileName:
            if hasattr(self, 'FvFileType') and self.FvFileType == 'RAW':
                if isinstance(self.FileName, list) and isinstance(self.SubAlignment, list) and len(self.FileName) == len(self.SubAlignment):
                    FileContent = BytesIO()
                    MaxAlignIndex = 0
                    MaxAlignValue = 1
                    for Index, File in enumerate(self.FileName):
                        try:
                            f = open(File, 'rb')
                        except:
                            GenFdsGlobalVariable.ErrorLogger("Error opening RAW file %s." % (File))
                        Content = f.read()
                        f.close()
                        AlignValue = 1
                        if self.SubAlignment[Index]:
                            AlignValue = GenFdsGlobalVariable.GetAlignment(self.SubAlignment[Index])
                        if AlignValue > MaxAlignValue:
                            MaxAlignIndex = Index
                            MaxAlignValue = AlignValue
                        FileContent.write(Content)
                        if len(FileContent.getvalue()) % AlignValue != 0:
                            Size = AlignValue - len(FileContent.getvalue()) % AlignValue
                            for i in range(0, Size):
                                FileContent.write(pack('B', 0xFF))

                    if FileContent.getvalue() != b'':
                        OutputRAWFile = os.path.join(GenFdsGlobalVariable.FfsDir, self.NameGuid, self.NameGuid + '.raw')
                        SaveFileOnChange(OutputRAWFile, FileContent.getvalue(), True)
                        self.FileName = OutputRAWFile
                        self.SubAlignment = self.SubAlignment[MaxAlignIndex]

                if self.Alignment and self.SubAlignment:
                    if GenFdsGlobalVariable.GetAlignment (self.Alignment) < GenFdsGlobalVariable.GetAlignment (self.SubAlignment):
                        self.Alignment = self.SubAlignment
                elif self.SubAlignment:
                    self.Alignment = self.SubAlignment

            self.FileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FileName)
            #Replace $(SAPCE) with real space
            self.FileName = self.FileName.replace('$(SPACE)', ' ')
            SectionFiles = [GenFdsGlobalVariable.MacroExtend(self.FileName, Dict)]

        else:
            SectionFiles = []
            Index = 0
            SectionAlignments = []
            for section in self.SectionList:
                Index = Index + 1
                SecIndex = '%d' %Index
                # process the inside FvImage from FvSection or GuidSection
                if FvChildAddr != []:
                    if isinstance(section, FvImageSection):
                        section.FvAddr = FvChildAddr.pop(0)
                    elif isinstance(section, GuidSection):
                        section.FvAddr = FvChildAddr
                if FvParentAddr and isinstance(section, GuidSection):
                    section.FvParentAddr = FvParentAddr

                if self.KeepReloc == False:
                    section.KeepReloc = False
                sectList, align = section.GenSection(OutputDir, self.NameGuid, SecIndex, self.KeyStringList, None, Dict)
                if sectList != []:
                    for sect in sectList:
                        SectionFiles.append(sect)
                        SectionAlignments.append(align)

        #
        # Prepare the parameter
        #
        FfsFileOutput = os.path.join(OutputDir, self.NameGuid + '.ffs')
        GenFdsGlobalVariable.GenerateFfs(FfsFileOutput, SectionFiles,
                                         FdfFvFileTypeToFileType.get(self.FvFileType),
                                         self.NameGuid,
                                         Fixed=self.Fixed,
                                         CheckSum=self.CheckSum,
                                         Align=self.Alignment,
                                         SectionAlign=SectionAlignments
                                        )

        return FfsFileOutput
