## @file
# Store a Module class object to an INF file.
#
# 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
#
from LoadMsa import LoadMsa
from CommonDataClass.ModuleClass import *
from Common.MigrationUtilities import *

## Get the produced library class.
#
# Return the item of Library Class based on Library .
#
# @param  LibraryClasses     A list of library classes the module produces.
#
# @retval LibraryClassItem   A text format library class item.
#
def GetModuleLibraryClass(LibraryClasses):
    ProducedLibraryClasses = []
    for LibraryClass in LibraryClasses:
        ProducedLibraryClass = LibraryClass.LibraryClass
        SupportedModueTypes = " ".join(LibraryClass.SupModuleList)
        if SupportedModueTypes != "":
            ProducedLibraryClass += "|" + SupportedModueTypes
        ProducedLibraryClasses.append(ProducedLibraryClass)

    return "|".join(ProducedLibraryClasses)


## Store Defines section.
#
# Write [Defines] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Defines section.
# @param  Module               An input Module class object.
#
def StoreModuleDefinesSection(InfFile, Module):
    ModuleHeader = Module.Header
    
    DefinesTupleList = []
    DefinesTupleList.append(("INF_VERSION", ModuleHeader.InfVersion))
    
    if ModuleHeader.Name != "":
        DefinesTupleList.append(("BASE_NAME", ModuleHeader.Name))

    if ModuleHeader.Guid != "":
        DefinesTupleList.append(("FILE_GUID", ModuleHeader.Guid))

    if ModuleHeader.Version != "":
        DefinesTupleList.append(("VERSION_STRING", ModuleHeader.Version))
        
    if ModuleHeader.ModuleType != "":
        DefinesTupleList.append(("MODULE_TYPE", ModuleHeader.ModuleType))

    if ModuleHeader.UefiSpecificationVersion != "":
        DefinesTupleList.append(("UEFI_SPECIFICATION_VERSION", ModuleHeader.UefiSpecificationVersion))
    
    if ModuleHeader.EdkReleaseVersion != "":
        DefinesTupleList.append(("EDK_RELEASE_VERSION", ModuleHeader.EdkReleaseVersion))
    
    ProducedLibraryClass = GetModuleLibraryClass(ModuleHeader.LibraryClass)
    if ProducedLibraryClass != "":
        DefinesTupleList.append(("LIBRARY_CLASS", ProducedLibraryClass))

    if ModuleHeader.MakefileName != "":
        DefinesTupleList.append(("MAKEFILE_NAME", ModuleHeader.MakeFileName))

    if ModuleHeader.PcdIsDriver != "":
        DefinesTupleList.append(("PCD_DRIVER", "TRUE"))

    if len(Module.ExternImages) > 0:
        ModuleEntryPoint = Module.ExternImages[0].ModuleEntryPoint
        ModuleUnloadImage = Module.ExternImages[0].ModuleUnloadImage
        if ModuleEntryPoint != "":
            DefinesTupleList.append(("ENTRY_POINT", ModuleEntryPoint))
        if ModuleUnloadImage != "":
            DefinesTupleList.append(("UNLOAD_IMAGE", ModuleUnloadImage))

    if len(Module.ExternLibraries) > 0:
        Constructor = Module.ExternLibraries[0].Constructor
        Destructor = Module.ExternLibraries[0].Destructor
        if Constructor != "":
            DefinesTupleList.append(("CONSTRUCTOR", Constructor))
        if Destructor != "":
            DefinesTupleList.append(("DESTRUCTOR", Destructor))

    StoreDefinesSection(InfFile, DefinesTupleList)
    

## Return a Module Source Item.
#
# Read the input ModuleSourceFile class object and return one line of Source Item.
#
# @param  ModuleSourceFile     An input ModuleSourceFile class object.
#
# @retval SourceItem           A Module Source Item.
#
def GetModuleSourceItem(ModuleSourceFile):
    Source = []
    Source.append(ModuleSourceFile.SourceFile)
    Source.append(ModuleSourceFile.ToolChainFamily)
    Source.append(ModuleSourceFile.TagName)
    Source.append(ModuleSourceFile.ToolCode)
    Source.append(ModuleSourceFile.FeatureFlag)
    return "|".join(Source).rstrip("|")
    

## Store Sources section.
#
# Write [Sources] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Sources section.
# @param  Module               An input Module class object.
#
def StoreModuleSourcesSection(InfFile, Module):
    Section = GetSection("Sources", GetModuleSourceItem, Module.Sources)
    StoreTextFile(InfFile, Section)


## Return a Module Binary Item.
#
# Read the input ModuleBinaryFile class object and return one line of Binary Item.
#
# @param  ModuleBinaryFile     An input ModuleBinaryFile class object.
#
# @retval BinaryItem           A Module Binary Item.
#
def GetModuleBinaryItem(ModuleBinaryFile):
    Binary = []
    Binary.append(ModuleBinaryFile.FileType)
    Binary.append(ModuleBinaryFile.BinaryFile)
    Binary.append(ModuleBinaryFile.Target)
    Binary.append(ModuleBinaryFile.FeatureFlag)
    return "|".join(Binary).rstrip("|")


## Store Binaries section.
#
# Write [Binaries] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Binaries section.
# @param  Module               An input Module class object.
#
def StoreModuleBinariesSection(InfFile, Module):
    Section = GetSection("Binaries", GetModuleBinaryItem, Module.Binaries)
    StoreTextFile(InfFile, Section)


## Return a Module Library Class Item.
#
# Read the input LibraryClass class object and return one line of Library Class Item.
#
# @param  LibraryClass         An input LibraryClass class object.
#
# @retval LibraryClassItem     A Module Library Class Item.
#
def GetModuleLibraryClassItem(LibraryClass):
    if "ALWAYS_PRODUCED" in LibraryClass.Usage:
        return ""

    LibraryClassList = []
    LibraryClassList.append(LibraryClass.LibraryClass)
    LibraryClassList.append(LibraryClass.RecommendedInstance)
    LibraryClassList.append(LibraryClass.FeatureFlag)
    
    return "|".join(LibraryClassList).rstrip("|")


## Store Library Classes section.
#
# Write [LibraryClasses] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Library Classes section.
# @param  Module               An input Module class object.
#
def StoreModuleLibraryClassesSection(InfFile, Module):
    Section = GetSection("LibraryClasses", GetModuleLibraryClassItem, Module.LibraryClasses)
    StoreTextFile(InfFile, Section)


## Return a Module Package Item.
#
# Read the input PackageDependency class object and return one line of Package Item.
#
# @param  PackageDependency    An input PackageDependency class object.
#
# @retval PackageItem          A Module Package Item.
#
def GetModulePackageItem(PackageDependency):
    return PackageDependency.FilePath


## Store Packages section.
#
# Write [Packages] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Packages section.
# @param  Module               An input Module class object.
#
def StoreModulePackagesSection(InfFile, Module):
    Section = GetSection("Packages", GetModulePackageItem, Module.PackageDependencies)
    StoreTextFile(InfFile, Section)
    

## Return a Module Guid C Name Item.
#
# Read the input Guid class object and return one line of Guid C Name Item.
#
# @param  Guid                 An input Guid class object.
#
# @retval GuidCNameItem        A Module Guid C Name Item.
#
def GetModuleGuidCNameItem(Guid):
    try:
        return Guid.GuidCName
    except:
        return Guid.CName


## Store Protocols section.
#
# Write [Protocols] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Protocols section.
# @param  Module               An input Module class object.
#
def StoreModuleProtocolsSection(InfFile, Module):
    Section = GetSection("Protocols", GetModuleGuidCNameItem, Module.Protocols)
    StoreTextFile(InfFile, Section)
    

## Store Ppis section.
#
# Write [Ppis] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Ppis section.
# @param  Module               An input Module class object.
#
def StoreModulePpisSection(InfFile, Module):
    Section = GetSection("Ppis", GetModuleGuidCNameItem, Module.Ppis)
    StoreTextFile(InfFile, Section)


## Store Guids section.
#
# Write [Guids] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Guids section.
# @param  Module               An input Module class object.
#
def StoreModuleGuidsSection(InfFile, Module):
    Guids = []
    Guids += Module.Guids
    Guids += Module.Events
    Guids += Module.Hobs
    Guids += Module.Variables
    Guids += Module.SystemTables
    Guids += Module.DataHubs
    Guids += Module.HiiPackages
    Section = GetSection("Guids", GetModuleGuidCNameItem, Guids)
    StoreTextFile(InfFile, Section)


## Return a Module Pcd Item.
#
# Read the input Pcd class object and return one line of Pcd Item.
#
# @param  Pcd                  An input Pcd class object.
#
# @retval PcdItem              A Module Pcd Item.
#
def GetModulePcdItem(Pcd):
    PcdItem = "%s.%s" % (Pcd.TokenSpaceGuidCName, Pcd.CName)
    if Pcd.DefaultValue != "":
        PcdItem = "%s|%s" % (PcdItem, Pcd.DefaultValue)

    return PcdItem


## DEC Pcd Section Name dictionary indexed by PCD Item Type.
mInfPcdSectionNameDict = {
    "FEATURE_FLAG" : "FeaturePcd",
    "FIXED_AT_BUILD" : "FixedPcd",
    "PATCHABLE_IN_MODULE" : "PatchPcd",
    "DYNAMIC" : "Pcd",
    "DYNAMIC_EX" : "PcdEx"
    }
    
## Store Pcds section.
#
# Write [(PcdType)] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Pcds section.
# @param  Module               An input Module class object.
#
def StoreModulePcdsSection(InfFile, Module):
    PcdsDict = {}
    for Pcd in Module.PcdCodes:
        PcdSectionName = mInfPcdSectionNameDict.get(Pcd.ItemType)
        if PcdSectionName:
            PcdsDict.setdefault(PcdSectionName, []).append(Pcd)
        else:
            EdkLogger.info("Unknown Pcd Item Type: %s" % Pcd.ItemType)

    Section = ""
    for PcdSectionName in PcdsDict:
        Pcds = PcdsDict[PcdSectionName]
        Section += GetSection(PcdSectionName, GetModulePcdItem, Pcds)
        Section += "\n"

    StoreTextFile(InfFile, Section)
    

## Return a Module Depex Item.
#
# Read the input Depex class object and return one line of Depex Item.
#
# @param  Depex                An input Depex class object.
#
# @retval DepexItem            A Module Depex Item.
#
def GetModuleDepexItem(Depex):
    return Depex.Depex


## Store Depex section.
#
# Write [Depex] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Depex section.
# @param  Module               An input Module class object.
#
def StoreModuleDepexSection(InfFile, Module):
    Section = GetSection("Depex", GetModuleDepexItem, Module.Depex)
    StoreTextFile(InfFile, Section)
    

## Return a Module Build Option Item.
#
# Read the input BuildOption class object and return one line of Build Option Item.
#
# @param  BuildOption          An input BuildOption class object.
#
# @retval BuildOptionItem      A Module Build Option Item.
#
def GetModuleBuildOptionItem(BuildOption):
    BuildTarget = BuildOption.BuildTarget
    if BuildTarget == "":
        BuildTarget = "*"

    TagName = BuildOption.TagName
    if TagName == "":
        TagName = "*"
        
    ToolCode = BuildOption.ToolCode
    if ToolCode == "":
        ToolCode = "*"

    Item = "_".join((BuildTarget, TagName, "*", ToolCode, "Flag"))

    ToolChainFamily = BuildOption.ToolChainFamily
    if ToolChainFamily != "":
        Item = "%s:%s" % (ToolChainFamily, Item)

    return "%-30s = %s" % (Item, BuildOption.Option)


## Store Build Options section.
#
# Write [BuildOptions] section to the InfFile based on Module class object.
# Different CPU architectures are specified in the subsection if possible.
#
# @param  InfFile              The output INF file to store the Build Options section.
# @param  Module               An input Module class object.
#
def StoreModuleBuildOptionsSection(InfFile, Module):
    Section = GetSection("BuildOption", GetModuleBuildOptionItem, Module.BuildOptions)
    StoreTextFile(InfFile, Section)


## Store User Extensions section.
#
# Write [UserExtensions] section to the InfFile based on Module class object.
#
# @param  InfFile              The output INF file to store the User Extensions section.
# @param  Module               An input Module class object.
#
def StoreModuleUserExtensionsSection(InfFile, Module):
    Section = "".join(map(GetUserExtensions, Module.UserExtensions))
    StoreTextFile(InfFile, Section)


## Store a Module class object to a new INF file.
#
# Read an input Module class object and save the contents to a new INF file.
#
# @param  INFFileName          The output INF file.
# @param  Module               An input Package class object.
#
def StoreInf(InfFileName, Module):
    InfFile = open(InfFileName, "w+")
    EdkLogger.info("Save file to %s" % InfFileName)

    StoreHeader(InfFile, Module.Header)
    StoreModuleDefinesSection(InfFile, Module)
    StoreModuleSourcesSection(InfFile, Module)
    StoreModuleBinariesSection(InfFile, Module)
    StoreModulePackagesSection(InfFile, Module)
    StoreModuleLibraryClassesSection(InfFile, Module)
    StoreModuleProtocolsSection(InfFile, Module)
    StoreModulePpisSection(InfFile, Module)
    StoreModuleGuidsSection(InfFile, Module)
    StoreModulePcdsSection(InfFile, Module)
    StoreModuleDepexSection(InfFile, Module)
    StoreModuleBuildOptionsSection(InfFile, Module)
    StoreModuleUserExtensionsSection(InfFile, Module)

    InfFile.close()
    
if __name__ == '__main__':
    pass
