import logging
import xml.etree.ElementTree as ElementTree
from ASTTypes.ASTNodeSubtypes import *
from ASTTypes.ASTNode import Program, ContextType
from logging import debug
import XMLParse.ParserGlobals as Globals
from .ExpressionParser import Tokenizer
from ASTTypes.CompoundStatementTypes import *


def parse_pdom_file(filepath: str) -> ASTNode:
    debug(f"Parsing PDOM: {filepath}")
    tree = ElementTree.parse(filepath)
    root = tree.getroot()
    # Workaround for <program> element
    root = analyze_document(root[0])
    ret = Program("Program", value=None, children=root.children)
    ret.context = ContextType.VOID
    return ret


def analyze_document(document: ElementTree.Element) -> StatementList:
    return analyze_statement_list(document)


def analyze_statement_list(statement_list: ElementTree.Element) -> StatementList:
    ret = StatementList()
    for child in statement_list:
        ret.append_child(analyze_statement(child))
    return ret


def analyze_statement(statement: ElementTree.Element) -> Statement:
    match statement.attrib["Statement-type"]:
        case "Include":
            token_stream = ""
            for child in statement:
                if child.tag == "Token":
                    token_stream += child.text + " "
            logging.info(f"Skipping include statement '{token_stream}'!")
        case "Statement" | "Variable":
            return Statement.from_Expression(analyze_expression(statement))
        case "Compound":
            return analyze_compound_statement(statement)
        case "Sub":
            return analyze_sub_statement(statement)
        case "Break":
            return analyze_break_statement(statement)
        case some_type:
            raise SyntaxError(f"Unknown Statement type {some_type}")


def analyze_sub_statement(statement: ElementTree.Element) -> Statement:
    match list(statement):
        case [ElementTree.Element(text="sub", tag="Token"),
              ElementTree.Element(tag="Token", attrib={"Token-type": "Word", **throwaway}, text=sub_name),
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Block", **throwaway2}) as block]:
            block_parsed = analyze_statement_list(block)
            return SubStatement(sub_name, block_parsed)


def analyze_compound_statement(statement: ElementTree.Element) -> Statement:
    match list(statement):
        #  Plain IF statement (No else or elif)
        case [ElementTree.Element(text="if", tag="Token"),
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Condition", **throwaway}) as condition,
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Block", **throwaway2}) as block]:
            condition_parsed = analyze_expression(condition[0])  # Condition structure encloses Statement structure
            block_parsed = analyze_statement_list(block)
            return IfStatement(condition=condition_parsed, block=block_parsed)
        case [ElementTree.Element(text="if", tag="Token"),
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Condition", **throwaway}) as condition,
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Block", **throwaway2}) as block,
              *rest]:
            condition_parsed = analyze_expression(condition[0])  # Condition structure encloses Statement structure
            block_parsed = analyze_statement_list(block)
            if_statement = IfStatement(condition=condition_parsed, block=block_parsed)
            return analyze_elif_else_ladder(rest, if_statement)
        case [ElementTree.Element(text="while"),
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Condition", **throwaway}) as condition,
              ElementTree.Element(tag="Structure", attrib={"Struct-type": "Block", **throwaway2}) as block]:
            condition_parsed = analyze_expression(condition[0])
            block_parsed = analyze_statement_list(block)
            return WhileStatement(condition_parsed, block_parsed)
    raise SyntaxError("Unrecognised compound statement")


def analyze_elif_else_ladder(elements: list[ElementTree.Element], if_statement: IfStatement) -> Statement:
    current_if_statement = if_statement
    while elements:
        match elements:
            case [ElementTree.Element(tag="Token", text="else"),
                  ElementTree.Element(tag="Structure", attrib={"Struct-type": "Block", **throwaway}) as block]:
                parsed_block = analyze_statement_list(block)
                current_if_statement.append_else(parsed_block)
                elements = []
            case [ElementTree.Element(tag="Token", text="elsif"),
                  ElementTree.Element(tag="Structure", attrib={"Struct-type": "Condition", **throwaway2}) as condition,
                  ElementTree.Element(tag="Structure", attrib={"Struct-type": "Block", **throwaway}) as block,
                  *rest]:
                condition_parsed = analyze_expression(condition[0])
                block_parsed = analyze_statement_list(block)
                inner_if_statement = IfStatement(condition_parsed, block_parsed)
                current_if_statement.append_else(StatementList([inner_if_statement]))
                current_if_statement = inner_if_statement
                elements = rest
            case _:
                raise SyntaxError("Bad Elsif-Else ladder")
    return if_statement


def analyze_expression(expression: ElementTree.Element) -> Expression:
    tokens = list(expression)
    new_tokenizer = Tokenizer(tokens)
    tokenizer_save = Globals.TOKENIZER.set(new_tokenizer)
    ret: Expression = Globals.PARSER(0)
    Globals.TOKENIZER.reset(tokenizer_save)
    return Expression([ret])


def analyze_break_statement(statemet: ElementTree.Element) -> Statement:
    match list(statemet):
        case [ElementTree.Element(text="return"),
              *expression]:
            expression_element = ElementTree.Element("Expression")
            for element in expression:
                expression_element.append(element)
            expression_parsed = analyze_expression(expression_element)
            return ReturnStatement(expression_parsed)
    raise SyntaxError("Unknown Break statement")
