from AST import ASTNode, getParseTreeNodes
from TypeNodes import InterNode, ClassNode
from Environment import Env, CompEnv

# compilation unit
class CompNode(ASTNode):
    # always list all fields in the init method to show the class structure
    def __init__(self, parseTree):
        self.parseTree = parseTree
        self.packageName = ''
        self.importNames = []
        self.env = None
        self.typeDcl = None
        self.children = []

        for node in parseTree.children:
            if node.name == 'packageDcl':
                nameNodes = getParseTreeNodes(['ID', 'COMPID'], node)
                for n in nameNodes:
                    self.packageName = n.lex
            elif node.name == 'importDcls':
                nameNodes = getParseTreeNodes(['ID', 'COMPID', 'IMPORTALL'], node)
                for n in nameNodes:
                    self.importNames.append(n.lex)
            elif node.name == 'topDcls':
                typeNode = getParseTreeNodes('classDcl', node)
                if not typeNode:
                    typeNode = getParseTreeNodes('interfaceDcl', node)
                    self.typeDcl = InterNode(typeNode[0], self.packageName)
                else:
                    self.typeDcl = ClassNode(typeNode[0], self.packageName)

        # always populate the children list
        self.children.append(self.typeDcl)

    def buildEnv(self, parentEnv):
        env = CompEnv(parentEnv, self.importNames, self.packageName)
        env.addtoEnv(self.typeDcl)
        self.env = env
        return env

    def linkType(self):
        seenImports = set() # check for repeated Imports, which are allowed

        for i in self.importNames:
            if ".*" not in i:
                # add single Type import to self.env under their simple name
                sImport = self.env.getNode(i, "type")
                if not sImport:
                    raise Exception("ERROR: Importing non existing type.")

                if i not in seenImports and sImport != self.typeDcl:  # can import self
                    self.env.addtoEnv(sImport)
                seenImports.add(i)
            else:
                # check if on demand import package exists
                # remove last two char .* to get package name
                p = self.env.parentEnv.ExistPackage(i[:-2])