class CFG_Node:
    __counter = 1

    def __init__(self, ast_node=None):
        self.ast_node = ast_node
        self.children = set()
        self.parents = set()

        self.label = None
        self.dot_shape = 'box'
        self.dot_style = ''
        
        self.id = CFG_Node.__counter
        CFG_Node.__counter += 1

    def get_children(self):
        return self.children

    def get_parents(self):
        return self.parents

    def add_child(self, child: 'CFG_Node', propagate=True):
        if propagate:
            child.parents.add(self)
        self.children.add(child)

    def add_parent(self, parent: 'CFG_Node', propagate=True):
        if propagate:
            parent.add_child(self)
        self.parents.add(parent)

    def remove_child(self, child: 'CFG_Node', propagate=True):
        if propagate:
            child.parents.remove(self)
        self.children.remove(child)

    def remove_parent(self, parent: 'CFG_Node', propagate=True):
        if propagate:
            parent.children.remove(self)
        self.parents.remove(parent)

    def dot_label(self):
        # Prioritize custom label
        if self.label is not None:
            return self.label

        # Build label from AST node
        if self.ast_node is not None:
            return str(self.ast_node)

        return None

    def is_filled(self):
        return not self.is_empty()

    def is_empty(self):
        # Node is empty if it has no label and no related AST node
        if self.label is None or self.label == "None":
            if self.ast_node is not None:
                # Node belongs to a ast node
                return False
            return True
        # Node is required for the control flow
        return False

class CFG_START(CFG_Node):
    def __init__(self, ast_node=None):
        super().__init__(ast_node)
        self.dot_shape = "ellipse"
        self.dot_style = 'style=filled, color=green'
        self.label = "START"

class CFG_END(CFG_Node):
    def __init__(self, ast_node=None):
        super().__init__(ast_node)
        self.dot_shape = "ellipse"
        self.dot_style = 'style=filled, color=green'
        self.label = "END"

class CFG_DIAMOND(CFG_Node):
    def __init__(self, ast_node=None):
        super().__init__(ast_node)
        self.dot_shape = "diamond"
        self.label = "<?>"

class CFG_CALL(CFG_Node):
    def __init__(self, ast_node=None):
        super().__init__(ast_node)
        self.dot_style = 'style=filled, color=orange'
        self.dot_shape = "box"

class CFG_RETURN(CFG_Node):
    def __init__(self, ast_node=None):
        super().__init__(ast_node)
        self.dot_style = 'style=filled, color=orange'
        self.dot_shape = "box"
