## @file GenDecFile.py
#
# This file contained the logical of transfer package object to DEC files.
#
# Copyright (c) 2011, 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.
#

'''
GenDEC
'''

from Library.Parsing import GenSection
from Library.CommentGenerating import GenHeaderCommentSection
from Library.CommentGenerating import GenGenericCommentF
from Library.CommentGenerating import GenDecTailComment
from Library.CommentGenerating import _GetHelpStr
from Library.Misc import GuidStringToGuidStructureString
from Library.Misc import SaveFileOnChange
from Library.Misc import ConvertPath
from Library.DataType import TAB_SPACE_SPLIT
from Library.DataType import TAB_COMMA_SPLIT
from Library.DataType import TAB_ARCH_COMMON
from Library.DataType import TAB_DEC_DEFINES_DEC_SPECIFICATION
from Library.DataType import TAB_DEC_DEFINES_PACKAGE_NAME
from Library.DataType import TAB_DEC_DEFINES_PACKAGE_GUID
from Library.DataType import TAB_DEC_DEFINES_PACKAGE_VERSION


def GenPcd(Package, Content):
    #
    # generate [Pcd] section
    # <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>    
    #
    ValidUsageDict = {}
    for Pcd in Package.GetPcdList():
        #
        # Generate generic comment
        #
        HelpTextList = Pcd.GetHelpTextList()
        HelpStr = _GetHelpStr(HelpTextList)
        CommentStr = GenGenericCommentF(HelpStr, 2)

        PcdErrList = Pcd.GetPcdErrorsList()
        if PcdErrList:
            CommentStr += GenPcdErrComment(PcdErrList[0])
        Statement = CommentStr

        CName = Pcd.GetCName()
        TokenSpaceGuidCName = Pcd.GetTokenSpaceGuidCName()
        DefaultValue = Pcd.GetDefaultValue()
        DatumType = Pcd.GetDatumType()
        Token = Pcd.GetToken()
        ValidUsage = Pcd.GetValidUsage()

        if ValidUsage == 'FeaturePcd':
            ValidUsage = 'PcdsFeatureFlag'
        elif ValidUsage == 'PatchPcd':
            ValidUsage = 'PcdsPatchableInModule'
        elif ValidUsage == 'FixedPcd':
            ValidUsage = 'PcdsFixedAtBuild'
        elif ValidUsage == 'Pcd':
            ValidUsage = 'PcdsDynamic'
        elif ValidUsage == 'PcdEx':
            ValidUsage = 'PcdsDynamicEx'
                                
        if ValidUsage in ValidUsageDict:
            NewSectionDict = ValidUsageDict[ValidUsage]
        else:
            NewSectionDict = {}
            ValidUsageDict[ValidUsage] = NewSectionDict
        Statement += TokenSpaceGuidCName + '.' + CName
        Statement += '|' + DefaultValue
        Statement += '|' + DatumType
        Statement += '|' + Token
        #
        # generate tail comment
        #
        if Pcd.GetSupModuleList():
            Statement += GenDecTailComment(Pcd.GetSupModuleList())

        ArchList = Pcd.GetSupArchList()
        ArchList.sort()
        SortedArch = ' '.join(ArchList)
        if SortedArch in NewSectionDict:
            NewSectionDict[SortedArch] = \
            NewSectionDict[SortedArch] + [Statement]
        else:
            NewSectionDict[SortedArch] = [Statement]            
        
    for ValidUsage in ValidUsageDict:
        Content += GenSection(ValidUsage, ValidUsageDict[ValidUsage])
    
    return Content

def GenGuidProtocolPpi(Package, Content):
    #
    # generate [Guids] section
    #
    NewSectionDict = {}
    for Guid in Package.GetGuidList():
        #
        # Generate generic comment
        #
        HelpTextList = Guid.GetHelpTextList()
        HelpStr = _GetHelpStr(HelpTextList)
        CommentStr = GenGenericCommentF(HelpStr, 2)

        Statement = CommentStr
        CName = Guid.GetCName()
        Value = GuidStringToGuidStructureString(Guid.GetGuid())
        Statement += CName + '  =  ' + Value
        #
        # generate tail comment
        #
        if Guid.GetSupModuleList():
            Statement += GenDecTailComment(Guid.GetSupModuleList())     
        ArchList = Guid.GetSupArchList()
        ArchList.sort()
        SortedArch = ' '.join(ArchList)
        if SortedArch in NewSectionDict:
            NewSectionDict[SortedArch] = \
            NewSectionDict[SortedArch] + [Statement]
        else:
            NewSectionDict[SortedArch] = [Statement]            

    Content += GenSection('Guids', NewSectionDict)    
 
    #
    # generate [Protocols] section
    #
    NewSectionDict = {}
    for Protocol in Package.GetProtocolList():
        #
        # Generate generic comment
        #
        HelpTextList = Protocol.GetHelpTextList()
        HelpStr = _GetHelpStr(HelpTextList)
        CommentStr = GenGenericCommentF(HelpStr, 2)        

        Statement = CommentStr        
        CName = Protocol.GetCName()
        Value = GuidStringToGuidStructureString(Protocol.GetGuid())
        Statement += CName + '  =  ' + Value

        #
        # generate tail comment
        #
        if Protocol.GetSupModuleList():
            Statement += GenDecTailComment(Protocol.GetSupModuleList())
        ArchList = Protocol.GetSupArchList()
        ArchList.sort()
        SortedArch = ' '.join(ArchList)
        if SortedArch in NewSectionDict:
            NewSectionDict[SortedArch] = \
            NewSectionDict[SortedArch] + [Statement]
        else:
            NewSectionDict[SortedArch] = [Statement]            

    Content += GenSection('Protocols', NewSectionDict) 

    #
    # generate [Ppis] section
    #
    NewSectionDict = {}
    for Ppi in Package.GetPpiList():
        #
        # Generate generic comment
        #
        HelpTextList = Ppi.GetHelpTextList()
        HelpStr = _GetHelpStr(HelpTextList)
        CommentStr = GenGenericCommentF(HelpStr, 2)

        Statement = CommentStr
        CName = Ppi.GetCName()
        Value = GuidStringToGuidStructureString(Ppi.GetGuid())
        Statement += CName + '  =  ' + Value

        #
        # generate tail comment
        #
        if Ppi.GetSupModuleList():
            Statement += GenDecTailComment(Ppi.GetSupModuleList())
        ArchList = Ppi.GetSupArchList()
        ArchList.sort()
        SortedArch = ' '.join(ArchList)
        if SortedArch in NewSectionDict:
            NewSectionDict[SortedArch] = \
            NewSectionDict[SortedArch] + [Statement]
        else:
            NewSectionDict[SortedArch] = [Statement]            

    Content += GenSection('Ppis', NewSectionDict)
    
    return Content

## Transfer Package Object to Dec files
#
# Transfer all contents of a standard Package Object to a Dec file 
#
# @param Package:  A Package 
#
def PackageToDec(Package):
    #
    # Init global information for the file
    #
    ContainerFile = Package.GetFullPath()
    
    Content = ''
    #
    # generate header comment section
    #
    Content += GenHeaderCommentSection(Package.GetAbstract(), \
                                       Package.GetDescription(), \
                                       Package.GetCopyright(), \
                                       Package.GetLicense())
    
    #
    # for each section, maintain a dict, sorted arch will be its key, 
    #statement list will be its data
    # { 'Arch1 Arch2 Arch3': [statement1, statement2],
    #   'Arch1' : [statement1, statement3] 
    #  }
    #
    
    #
    # generate [Defines] section                     
    #
    NewSectionDict = {TAB_ARCH_COMMON : []}
    SpecialItemList = []
    
    Statement = '%s = %s' % (TAB_DEC_DEFINES_DEC_SPECIFICATION, '0x00010017')
    SpecialItemList.append(Statement)
    
    BaseName = Package.GetBaseName()
    if BaseName.startswith('.') or BaseName.startswith('-'):
        BaseName = '_' + BaseName
    Statement = '%s = %s' % (TAB_DEC_DEFINES_PACKAGE_NAME, BaseName)
    SpecialItemList.append(Statement)
    Statement = '%s = %s' % (TAB_DEC_DEFINES_PACKAGE_VERSION, Package.GetVersion())
    SpecialItemList.append(Statement)
    Statement = '%s = %s' % (TAB_DEC_DEFINES_PACKAGE_GUID, Package.GetGuid())
    SpecialItemList.append(Statement)        
    for SortedArch in NewSectionDict:
        NewSectionDict[SortedArch] = \
        NewSectionDict[SortedArch] + SpecialItemList
    Content += GenSection('Defines', NewSectionDict)

    #
    # generate [Includes] section
    #
    NewSectionDict = {}
    IncludeArchList = Package.GetIncludeArchList()
    if IncludeArchList:            
        for Path, ArchList in IncludeArchList:
            Statement = Path
            ArchList.sort()
            SortedArch = ' '.join(ArchList)
            if SortedArch in NewSectionDict:
                NewSectionDict[SortedArch] = \
                NewSectionDict[SortedArch] + [ConvertPath(Statement)]
            else:
                NewSectionDict[SortedArch] = [ConvertPath(Statement)]

    Content += GenSection('Includes', NewSectionDict)                     

    Content = GenGuidProtocolPpi(Package, Content)

    #
    # generate [LibraryClasses] section
    #
    NewSectionDict = {}
    for LibraryClass in Package.GetLibraryClassList():
        #
        # Generate generic comment
        #
        HelpTextList = LibraryClass.GetHelpTextList()
        HelpStr = _GetHelpStr(HelpTextList)
        if HelpStr:
            HelpStr = '@libraryclass ' + HelpStr
        CommentStr = GenGenericCommentF(HelpStr, 2)

        Statement = CommentStr
        Name = LibraryClass.GetLibraryClass()
        IncludeHeader = LibraryClass.GetIncludeHeader()
        Statement += Name + '|' + ConvertPath(IncludeHeader)
        #
        # generate tail comment
        #
        if LibraryClass.GetSupModuleList():
            Statement += \
            GenDecTailComment(LibraryClass.GetSupModuleList())
        ArchList = LibraryClass.GetSupArchList()
        ArchList.sort()
        SortedArch = ' '.join(ArchList)
        if SortedArch in NewSectionDict:
            NewSectionDict[SortedArch] = \
            NewSectionDict[SortedArch] + [Statement]
        else:
            NewSectionDict[SortedArch] = [Statement]            

    Content += GenSection('LibraryClasses', NewSectionDict)

    Content = GenPcd(Package, Content)
    
    #
    # generate [UserExtensions] section
    #
    NewSectionDict = {}
    for UserExtension in Package.GetUserExtensionList():
        Statement = UserExtension.GetStatement()
        if not Statement:
            continue
        
        SectionList = []
        SectionName = 'UserExtensions'
        UserId = UserExtension.GetUserID()
        if UserId:
            if '.' in UserId:
                UserId = '"' + UserId + '"'
            SectionName += '.' + UserId
            if UserExtension.GetIdentifier():
                SectionName += '.' + '"' + UserExtension.GetIdentifier() + '"'
        if not UserExtension.GetSupArchList():
            SectionList.append(SectionName)
        else:
            for Arch in UserExtension.GetSupArchList():
                SectionList.append(SectionName + '.' + Arch)
        SectionName = ', '.join(SectionList)
        SectionName = ''.join(['[', SectionName, ']\n'])
        Content += '\n\n' + SectionName + Statement

    SaveFileOnChange(ContainerFile, Content, False)
    return ContainerFile

## GenPcdErrComment
#
#  @param PcdErrObject:  PcdErrorObject
#  
#  @retval CommentStr:   Generated comment lines, with prefix "#"
# 
def GenPcdErrComment (PcdErrObject):
    EndOfLine = "\n"    
    ValidValueRange = PcdErrObject.GetValidValueRange()
    if ValidValueRange:
        CommentStr = "# @ValidRange " + ValidValueRange + EndOfLine
    
    ValidValue = PcdErrObject.GetValidValue()
    if ValidValue:
        ValidValueList = \
        [Value for Value in ValidValue.split(TAB_SPACE_SPLIT) if Value]
        CommentStr = \
        "# @ValidList " + TAB_COMMA_SPLIT.join(ValidValueList) + EndOfLine
        
    Expression = PcdErrObject.GetExpression()
    if Expression:
        CommentStr = "# @Expression " + Expression + EndOfLine
        
    return CommentStr

