from Utils.utilities import *
from typing import Self, Generator, List, TypeVar
from enum import Enum, unique

Expr = TypeVar("Expr", bound="ASTNode")
ascii_force = False

class ContextType(Enum):
    VOID = "Void"
    SCALAR = "Scalar"
    LIST = "List"
    HASH = "Hash"
    UNSOLVED = "Unsolved context! Could be error!"


class ASTNode(object):
    """Base class for all nodes in the AST"""
    def __init__(self, nodetype: str, value: str | None, children: List[Self] = None):
        self.nodetype = nodetype
        self.value = value
        self.children: list[Expr] = children or []
        self._context = ContextType.UNSOLVED
        self._being_asigned_to = False

    def append_child(self, child) -> None:
        """Appends child to the node"""
        if child is not None:
            self.children.append(child)

    def __iter__(self) -> Generator[Self, None, None]:
        for child in self.children:
            yield child

    def __repr__(self):
        return f"{self.__class__.__name__} <{self._context.value}>{'AT' if self._being_asigned_to else ''}"

    def dump_tree(self, ) -> str:
        ret: str = str(self)
        for cn, child in enumerate(self.children):
            lines = child.dump_tree().split("\n")
            for ln, line in enumerate(lines):
                ret += "\n"
                if ln != 0 and cn == len(self.children) - 1:
                    ret += "\t"+line
                elif ln == 0 and cn == len(self.children)-1:
                    ret += "╚═\t"+line if not ascii_force else "--\t"+line
                elif ln == 0:
                    ret += "╠═\t"+line if not ascii_force else "+-\t"+line
                else:
                    ret += "║\t"+line if not ascii_force else "|\t"+line
            # ret += "\n".join([f"╠\t{line}" for line in child.dump_tree().split("\n")])
        return ret

    @property
    def context(self) -> ContextType:
        return self._context

    @context.setter
    def context(self, value: ContextType):
        for child in self.children:
            child.context = value
        self._context = value

    @property
    def being_asigned_to(self) -> bool:
        return self._being_asigned_to

    @being_asigned_to.setter
    def being_asigned_to(self, value: bool):
        self._being_asigned_to = value

    def translate(self) -> str:
        return "".join([child.translate() for child in self.children])


class Program(ASTNode):
    pass
