import pexpect
import threading
import re
from typing import Tuple, Dict

vivado = None
t_vivado_init = None


def start():
    global vivado
    global t_vivado_init
    vivado = pexpect.spawnu(
        "vivado -mode tcl -nolog -nojournal",
        encoding="utf-8",
        codec_errors="ignore",
    )

    t_vivado_init = threading.Thread(target=vivado.expect, args=("Vivado%",))
    t_vivado_init.start()
    return vivado


def execute_command(command: str) -> str:
    if not vivado.isalive():
        raise Exception(
            "Could not start Vivado, is it installed?"
            + " Is it in your PATH?\n"
            + " Try running 'vivado -mode tcl' yourself and"
            + " debug why it does not start"
        )
    global t_vivado_init
    if t_vivado_init is not None:
        print("Waiting for Vivado to start ...")
        t_vivado_init.join()
        vivado.sendline("set_param tcl.collectionResultDisplayLimit Inf")
        vivado.expect("Vivado%", timeout=None)
        t_vivado_init = None

    vivado.sendline(command)
    vivado.expect("Vivado%", timeout=None)
    return str(vivado.before)


def source(tcl_script: str) -> Tuple[str, bool]:
    vivado_out = execute_command("source " + tcl_script)
    return vivado_out, not re.findall("ERROR:", vivado_out)


def get_parts() -> Dict[str, str]:
    parts = [
        x.strip()
        for x in re.sub(
            "get_parts\r\n", "", execute_command("get_parts")
        ).split(" ")[1:]
    ]
    family = [
        x.strip()
        for x in re.sub(
            "[get_parts]\r\n",
            "",
            execute_command("get_property FAMILY [get_parts]"),
        ).split(" ")[3:]
    ]
    family[0] = family[0][len("[get_parts]\r\n") :]
    return dict(zip(parts, family))


def get_help(command: str) -> str:
    return execute_command("help " + command)
