## @file
# This file is used to define class objects for DEC file. It will consumed by
#DecParser
#
# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent

'''
DecObject
'''

## Import modules
#
import os.path

from Library.Misc import Sdict
from Library.DataType import TAB_GUIDS
from Library.DataType import TAB_PPIS
from Library.DataType import TAB_PROTOCOLS
from Library.DataType import TAB_DEC_DEFINES
from Library.DataType import TAB_INCLUDES
from Library.DataType import TAB_LIBRARY_CLASSES
from Library.DataType import TAB_USER_EXTENSIONS
from Library.DataType import TAB_PCDS
from Library.DataType import TAB_ARCH_COMMON

## _DecComments
#
# Base class for all data objects which have head and tail comments
#
class _DecComments:

    ##constructor
    #
    def __init__(self):
        self._HeadComment = []
        self._TailComment = []

    ## GetComments
    #
    def GetComments(self):
        return self._HeadComment, self._TailComment

    ## GetHeadComment
    #
    def GetHeadComment(self):
        return self._HeadComment

    ## SetHeadComment
    #
    # @param Comment: comment content
    #
    def SetHeadComment(self, Comment):
        self._HeadComment = Comment

    ## GetTailComment
    #
    def GetTailComment(self):
        return self._TailComment

    ## SetTailComment
    #
    # @param Comment: comment content
    #
    def SetTailComment(self, Comment):
        self._TailComment = Comment

## _DecBaseObject
#
# Base class that hold common info
#
class _DecBaseObject(_DecComments):
    def __init__(self, PkgFullName):
        _DecComments.__init__(self)
        #
        # Key is combined with (Arch, SectionType)
        # Default is common
        #
        self.ValueDict = Sdict()
        self._PkgFullName = PkgFullName
        self._PackagePath, self._FileName = os.path.split(PkgFullName)
        self._SecName = ''

    ## GetSectionName
    #
    def GetSectionName(self):
        return self._SecName

    ## GetPackagePath
    #
    def GetPackagePath(self):
        return self._PackagePath

    ## GetPackageFile
    #
    def GetPackageFile(self):
        return self._FileName

    ## GetPackageFullName
    #
    def GetPackageFullName(self):
        return self._PkgFullName

    ## AddItem
    # Add sub-item to current object, sub-class should override it if needed
    #
    # @param Item: Sub-item to be added
    # @param Scope: A list store section name and arch info
    #
    def AddItem(self, Item, Scope):
        if not Scope:
            return
        if not Item:
            return
        ArchModule = []
        for Ele in Scope:
            if Ele[1] in self.ValueDict:
                self.ValueDict[Ele[1]].append(Item)
            else:
                self.ValueDict[Ele[1]] = [Item]
            ArchModule.append(Ele[1])
        Item.ArchAndModuleType = ArchModule

    ## _GetItemByArch
    # Helper class used by sub-class
    # @param Arch:  arch
    #
    def _GetItemByArch(self, Arch):
        Arch = Arch.upper()
        if Arch not in self.ValueDict:
            return []
        return self.ValueDict[Arch]

    ## _GetAllItems
    # Get all items, union all arches, items in returned list are unique
    #
    def _GetAllItems(self):
        Retlst = []
        for Arch in self.ValueDict:
            for Item in self.ValueDict[Arch]:
                if Item not in Retlst:
                    Retlst.append(Item)
        return Retlst

## _DecItemBaseObject
#
# Module type and arch the item belongs to
#
class _DecItemBaseObject(_DecComments):
    def __init__(self):
        _DecComments.__init__(self)
        #
        # Item's arch, if PCD, also include PCD type
        #
        self.ArchAndModuleType = []

    ## GetArchList
    #
    def GetArchList(self):
        ArchSet = set()
        for Arch in self.ArchAndModuleType:
            ArchSet.add(Arch)
        return list(ArchSet)

## DecDefineObject
#
# Class to hold define section information
#
class DecDefineObject(_DecBaseObject):
    def __init__(self, PkgFullName):
        _DecBaseObject.__init__(self, PkgFullName)
        self._SecName = TAB_DEC_DEFINES.upper()
        self._DecSpec = ''
        self._PkgName = ''
        self._PkgGuid = ''
        self._PkgVersion = ''
        self._PkgUniFile = ''

    ## GetPackageSpecification
    #
    def GetPackageSpecification(self):
        return self._DecSpec

    def SetPackageSpecification(self, DecSpec):
        self._DecSpec = DecSpec

    ## GetPackageName
    #
    def GetPackageName(self):
        return self._PkgName

    def SetPackageName(self, PkgName):
        self._PkgName = PkgName

    ## GetPackageGuid
    #
    def GetPackageGuid(self):
        return self._PkgGuid

    def SetPackageGuid(self, PkgGuid):
        self._PkgGuid = PkgGuid

    ## GetPackageVersion
    #
    def GetPackageVersion(self):
        return self._PkgVersion

    def SetPackageVersion(self, PkgVersion):
        self._PkgVersion = PkgVersion

    ## GetPackageUniFile
    #
    def GetPackageUniFile(self):
        return self._PkgUniFile

    def SetPackageUniFile(self, PkgUniFile):
        self._PkgUniFile = PkgUniFile

    ## GetDefines
    #
    def GetDefines(self):
        return self._GetItemByArch(TAB_ARCH_COMMON)

    ## GetAllDefines
    #
    def GetAllDefines(self):
        return self._GetAllItems()

## DecDefineItemObject
#
# Each item of define section
#
class DecDefineItemObject(_DecItemBaseObject):
    def __init__(self):
        _DecItemBaseObject.__init__(self)
        self.Key = ''
        self.Value = ''

    ## __hash__
    #
    def __hash__(self):
        return hash(self.Key + self.Value)

    ## __eq__
    #
    def __eq__(self, Other):
        return id(self) == id(Other)

    ## __str__
    #
    def __str__(self):
        return str(self.ArchAndModuleType) + '\n' + self.Key + \
            ' = ' + self.Value

## DecIncludeObject
#
# Class to hold include section info
#
class DecIncludeObject(_DecBaseObject):
    def __init__(self, PkgFullName):
        _DecBaseObject.__init__(self, PkgFullName)
        self._SecName = TAB_INCLUDES.upper()

    ## GetIncludes
    #
    def GetIncludes(self, Arch=TAB_ARCH_COMMON):
        return self._GetItemByArch(Arch)

    ## GetAllIncludes
    #
    def GetAllIncludes(self):
        return self._GetAllItems()

## DecIncludeItemObject
#
# Item of include section
#
class DecIncludeItemObject(_DecItemBaseObject):
    def __init__(self, File, Root):
        self.File = File
        self.Root = Root
        _DecItemBaseObject.__init__(self)

    ## __hash__
    #
    def __hash__(self):
        return hash(self.File)

    ## __eq__
    #
    def __eq__(self, Other):
        return id(self) == id(Other)

    ## __str__
    #
    def __str__(self):
        return self.File

## DecLibraryclassObject
#
# Class to hold library class section info
#
class DecLibraryclassObject(_DecBaseObject):
    def __init__(self, PkgFullName):
        _DecBaseObject.__init__(self, PkgFullName)
        self._PackagePath, self._FileName = os.path.split(PkgFullName)
        self._SecName = TAB_LIBRARY_CLASSES.upper()

    ## GetLibraryclasses
    #
    def GetLibraryclasses(self, Arch=TAB_ARCH_COMMON):
        return self._GetItemByArch(Arch)

    ## GetAllLibraryclasses
    #
    def GetAllLibraryclasses(self):
        return self._GetAllItems()

## DecLibraryclassItemObject
# Item of library class section
#
class DecLibraryclassItemObject(_DecItemBaseObject):
    def __init__(self, Libraryclass, File, Root):
        _DecItemBaseObject.__init__(self)
        self.File = File
        self.Root = Root
        self.Libraryclass = Libraryclass

    ## __hash__
    #
    def __hash__(self):
        return hash(self.Libraryclass + self.File)

    ## __eq__
    #
    def __eq__(self, Other):
        return id(self) == id(Other)

    ## __str__
    #
    def __str__(self):
        return self.Libraryclass + '|' + self.File

## DecPcdObject
# Class to hold PCD section
#
class DecPcdObject(_DecBaseObject):
    def __init__(self, PkgFullName):
        _DecBaseObject.__init__(self, PkgFullName)
        self._SecName = TAB_PCDS.upper()

    ## AddItem
    #
    # Diff from base class
    #
    # @param Item: Item
    # @param Scope: Scope
    #
    def AddItem(self, Item, Scope):
        if not Scope:
            return
        if not Item:
            return
        ArchModule = []
        for Type, Arch in Scope:
            if (Type, Arch) in self.ValueDict:
                self.ValueDict[Type, Arch].append(Item)
            else:
                self.ValueDict[Type, Arch] = [Item]
            ArchModule.append([Type, Arch])
        Item.ArchAndModuleType = ArchModule

    ## GetPcds
    #
    # @param PcdType: PcdType
    # @param Arch: Arch
    #
    def GetPcds(self, PcdType, Arch=TAB_ARCH_COMMON):
        PcdType = PcdType.upper()
        Arch = Arch.upper()
        if (PcdType, Arch) not in self.ValueDict:
            return []
        return self.ValueDict[PcdType, Arch]

    ## GetPcdsByType
    #
    # @param PcdType: PcdType
    #
    def GetPcdsByType(self, PcdType):
        PcdType = PcdType.upper()
        Retlst = []
        for TypeInDict, Arch in self.ValueDict:
            if TypeInDict != PcdType:
                continue
            for Item in self.ValueDict[PcdType, Arch]:
                if Item not in Retlst:
                    Retlst.append(Item)
        return Retlst

## DecPcdItemObject
#
# Item of PCD section
#
# @param _DecItemBaseObject: _DecItemBaseObject object
#
class DecPcdItemObject(_DecItemBaseObject):
    def __init__(self, Guid, Name, Value, DatumType,
                 Token, MaxDatumSize=''):
        _DecItemBaseObject.__init__(self)
        self.TokenCName = Name
        self.TokenSpaceGuidCName = Guid
        self.DatumType = DatumType
        self.DefaultValue = Value
        self.TokenValue = Token
        self.MaxDatumSize = MaxDatumSize

    ## __hash__
    #
    def __hash__(self):
        return hash(self.TokenSpaceGuidCName + self.TokenCName)

    ## __eq__
    #
    def __eq__(self, Other):
        return id(self) == id(Other)

    ## GetArchListOfType
    #
    # @param PcdType: PcdType
    #
    def GetArchListOfType(self, PcdType):
        ItemSet = set()
        PcdType = PcdType.upper()
        for Type, Arch in self.ArchAndModuleType:
            if Type != PcdType:
                continue
            ItemSet.add(Arch)
        return list(ItemSet)

## DecGuidObjectBase
#
# Base class for PPI, Protocol, and GUID.
# Hold same data but has different method for clarification in sub-class
#
# @param _DecBaseObject: Dec Base Object
#
class DecGuidObjectBase(_DecBaseObject):
    def __init__(self, PkgFullName):
        _DecBaseObject.__init__(self, PkgFullName)

    ## GetGuidStyleItems
    #
    # @param Arch: Arch
    #
    def GetGuidStyleItems(self, Arch=TAB_ARCH_COMMON):
        return self._GetItemByArch(Arch)

    ## GetGuidStyleAllItems
    #
    def GetGuidStyleAllItems(self):
        return self._GetAllItems()

## DecGuidItemObject
#
# Item of GUID, PPI and Protocol section
#
# @param _DecItemBaseObject: Dec Item Base Object
#
class DecGuidItemObject(_DecItemBaseObject):
    def __init__(self, CName, GuidCValue, GuidString):
        _DecItemBaseObject.__init__(self)
        self.GuidCName = CName
        self.GuidCValue = GuidCValue
        self.GuidString = GuidString

    ## __hash__
    #
    def __hash__(self):
        return hash(self.GuidCName)

    ## __eq__
    #
    def __eq__(self, Other):
        return id(self) == id(Other)

    ## __str__
    #
    def __str__(self):
        return self.GuidCName + ' = ' + self.GuidCValue

## DecGuidObject
#
# Class for GUID section
#
# @param DecGuidObjectBase: Dec Guid Object Base
#
class DecGuidObject(DecGuidObjectBase):
    def __init__(self, PkgFullName):
        DecGuidObjectBase.__init__(self, PkgFullName)
        self._SecName = TAB_GUIDS.upper()

    ## GetGuids
    #
    # @param Arch: Arch
    #
    def GetGuids(self, Arch=TAB_ARCH_COMMON):
        return self._GetItemByArch(Arch)

    ## GetAllGuids
    #
    def GetAllGuids(self):
        return self._GetAllItems()

## DecPpiObject
#
# Class for PPI section
#
# @param DecGuidObjectBase: Dec Guid Object Base
#
class DecPpiObject(DecGuidObjectBase):
    def __init__(self, PkgFullName):
        DecGuidObjectBase.__init__(self, PkgFullName)
        self._SecName = TAB_PPIS.upper()

    ## GetPpis
    #
    # @param Arch: Arch
    #
    def GetPpis(self, Arch=TAB_ARCH_COMMON):
        return self._GetItemByArch(Arch)

    ## GetAllPpis
    #
    def GetAllPpis(self):
        return self._GetAllItems()

## DecProtocolObject
#
# Class for protocol section
#
# @param DecGuidObjectBase: Dec Guid Object Base
#
class DecProtocolObject(DecGuidObjectBase):
    def __init__(self, PkgFullName):
        DecGuidObjectBase.__init__(self, PkgFullName)
        self._SecName = TAB_PROTOCOLS.upper()

    ## GetProtocols
    #
    # @param Arch: Arch
    #
    def GetProtocols(self, Arch=TAB_ARCH_COMMON):
        return self._GetItemByArch(Arch)

    ## GetAllProtocols
    #
    def GetAllProtocols(self):
        return self._GetAllItems()

## DecUserExtensionObject
#
# Class for user extension section
#
# @param _DecBaseObject: Dec Guid Object Base
#
class DecUserExtensionObject(_DecBaseObject):
    def __init__(self, PkgFullName):
        _DecBaseObject.__init__(self, PkgFullName)
        self._SecName = TAB_USER_EXTENSIONS.upper()
        self.ItemList = []

    ## GetProtocols
    #
    # @param Item: Item
    # @param Scope: Scope
    #
    def AddItem(self, Item, Scope):
        if not Scope:
            pass
        if not Item:
            return
        self.ItemList.append(Item)

    ## GetAllUserExtensions
    #
    def GetAllUserExtensions(self):
        return self.ItemList


## DecUserExtensionItemObject
# Item for user extension section
#
# @param _DecItemBaseObject: Dec Item Base Object
#
class DecUserExtensionItemObject(_DecItemBaseObject):
    def __init__(self):
        _DecItemBaseObject.__init__(self)
        self.UserString = ''
        self.UserId = ''
        self.IdString = ''




