## @file
# This file is used to define class objects of INF file [Sources] section.
# It will consumed by InfParser.
#
# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent

'''
InfSourcesObject
'''

import os

from edk2basetools.UPT.Logger import StringTable as ST
from edk2basetools.UPT.Logger import ToolError
import edk2basetools.UPT.Logger.Log as Logger
from edk2basetools.UPT.Library import GlobalData

from edk2basetools.UPT.Library.Misc import Sdict
from edk2basetools.UPT.Library.ExpressionValidate import IsValidFeatureFlagExp
from edk2basetools.UPT.Object.Parser.InfCommonObject import InfSectionCommonDef
from edk2basetools.UPT.Library.Misc import ValidFile
from edk2basetools.UPT.Library.ParserValidate import IsValidFamily
from edk2basetools.UPT.Library.ParserValidate import IsValidPath

## __GenSourceInstance
#
#
def GenSourceInstance(Item, CurrentLineOfItem, ItemObj):

    IsValidFileFlag = False

    if len(Item) < 6 and len(Item) >= 1:
        #
        # File | Family | TagName | ToolCode | FeatureFlagExpr
        #
        if len(Item) == 5:
            #
            # Validate Feature Flag Express
            #
            if Item[4].strip() == '':
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_INF_PARSER_FEATURE_FLAG_EXP_MISSING,
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])
            #
            # Validate FFE
            #
            FeatureFlagRtv = IsValidFeatureFlagExp(Item[4].strip())
            if not FeatureFlagRtv[0]:
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_INF_PARSER_FEATURE_FLAG_EXP_SYNTAX_INVLID%(FeatureFlagRtv[1]),
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])
            ItemObj.SetFeatureFlagExp(Item[4])
        if len(Item) >= 4:
            if Item[3].strip() == '':
                ItemObj.SetToolCode(Item[3])
            else:
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_INF_PARSER_TOOLCODE_NOT_PERMITTED%(Item[2]),
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])
        if len(Item) >= 3:
            if Item[2].strip() == '':
                ItemObj.SetTagName(Item[2])
            else:
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_INF_PARSER_TAGNAME_NOT_PERMITTED%(Item[2]),
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])
        if len(Item) >= 2:
            if IsValidFamily(Item[1].strip()):
                #
                # To align with UDP specification. "*" is not permitted in UDP specification
                #
                if Item[1].strip() == "*":
                    Item[1] = ""
                ItemObj.SetFamily(Item[1])
            else:
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_INF_PARSER_SOURCE_SECTION_FAMILY_INVALID%(Item[1]),
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])
        if len(Item) >= 1:
            #
            # Validate file name exist.
            #
            FullFileName = os.path.normpath(os.path.realpath(os.path.join(GlobalData.gINF_MODULE_DIR, Item[0])))
            if not (ValidFile(FullFileName) or ValidFile(Item[0])):
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_FILELIST_EXIST%(Item[0]),
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])

            #
            # Validate file exist/format.
            #

            if IsValidPath(Item[0], GlobalData.gINF_MODULE_DIR):
                IsValidFileFlag = True
            else:
                Logger.Error("InfParser",
                             ToolError.FORMAT_INVALID,
                             ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID%(Item[0]),
                             File=CurrentLineOfItem[2],
                             Line=CurrentLineOfItem[1],
                             ExtraData=CurrentLineOfItem[0])
                return False
            if IsValidFileFlag:
                ItemObj.SetSourceFileName(Item[0])
    else:
        Logger.Error("InfParser",
                     ToolError.FORMAT_INVALID,
                     ST.ERR_INF_PARSER_SOURCES_SECTION_CONTENT_ERROR,
                     File=CurrentLineOfItem[2],
                     Line=CurrentLineOfItem[1],
                     ExtraData=CurrentLineOfItem[0])

    return ItemObj

## InfSourcesItemObject()
#
#
class InfSourcesItemObject():
    def __init__(self, \
                 SourceFileName = '', \
                 Family = '', \
                 TagName = '', \
                 ToolCode = '', \
                 FeatureFlagExp = ''):
        self.SourceFileName = SourceFileName
        self.Family         = Family
        self.TagName        = TagName
        self.ToolCode       = ToolCode
        self.FeatureFlagExp = FeatureFlagExp
        self.HeaderString   = ''
        self.TailString     = ''
        self.SupArchList    = []

    def SetSourceFileName(self, SourceFilename):
        self.SourceFileName = SourceFilename
    def GetSourceFileName(self):
        return self.SourceFileName

    def SetFamily(self, Family):
        self.Family = Family
    def GetFamily(self):
        return self.Family

    def SetTagName(self, TagName):
        self.TagName = TagName
    def GetTagName(self):
        return self.TagName

    def SetToolCode(self, ToolCode):
        self.ToolCode = ToolCode
    def GetToolCode(self):
        return self.ToolCode

    def SetFeatureFlagExp(self, FeatureFlagExp):
        self.FeatureFlagExp = FeatureFlagExp
    def GetFeatureFlagExp(self):
        return self.FeatureFlagExp

    def SetHeaderString(self, HeaderString):
        self.HeaderString = HeaderString
    def GetHeaderString(self):
        return self.HeaderString

    def SetTailString(self, TailString):
        self.TailString = TailString
    def GetTailString(self):
        return self.TailString

    def SetSupArchList(self, SupArchList):
        self.SupArchList = SupArchList
    def GetSupArchList(self):
        return self.SupArchList
##
#
#
#
class InfSourcesObject(InfSectionCommonDef):
    def __init__(self):
        self.Sources = Sdict()
        InfSectionCommonDef.__init__(self)

    def SetSources(self, SourceList, Arch = None):
        __SupArchList = []
        for ArchItem in Arch:
            #
            # Validate Arch
            #
            if (ArchItem == '' or ArchItem is None):
                ArchItem = 'COMMON'
            __SupArchList.append(ArchItem)

        for Item in SourceList:
            ItemObj = InfSourcesItemObject()
            CurrentLineOfItem = Item[2]
            Item = Item[0]

            ItemObj = GenSourceInstance(Item, CurrentLineOfItem, ItemObj)

            ItemObj.SetSupArchList(__SupArchList)

            if (ItemObj) in self.Sources:
                SourceContent = self.Sources[ItemObj]
                SourceContent.append(ItemObj)
                self.Sources[ItemObj] = SourceContent
            else:
                SourceContent = []
                SourceContent.append(ItemObj)
                self.Sources[ItemObj] = SourceContent

        return True

    def GetSources(self):
        return self.Sources
