#!/usr/bin/env python3
import shutil
# The Scorbunny Configuration tool for SayoriOS
# Made by NDRAEY.


import time
import os
from dataclasses import dataclass
import yaml


# -- config --

OPTIMIZATION_LEVELS = ["0", "1", "2", "3", "s"]
BUILD_MODES = ["debug",  "release"]

# Tuple<Description, FieldInConfigDataclass, Variant<AcceptedValues, Type>>
MAPPING = (
    ("Optimization level", "optimization_level", OPTIMIZATION_LEVELS),
    ("Build mode",  "build_mode", BUILD_MODES),
    ("Enable -Werror",  "enable_werror", bool),
    ("Use SSE instructions",  "use_sse", bool),
)


@dataclass
class Config:
    optimization_level: str = "0"
    build_mode: str = "debug"
    enable_werror: bool = False
    use_sse: bool = True


# -- logging --

def log(message, *args, **kwargs):
    print(f"I [{time.strftime('%H:%M:%S')}]: {message}",  *args, **kwargs)

def error(message, *args, **kwargs):
    print(f"\x1b[31;1mE [{time.strftime('%H:%M:%S')}]: {message}",  *args, **kwargs, end="\x1b[0m\n")

def warn(message, *args, **kwargs):
    print(f"\x1b[33;1mW [{time.strftime('%H:%M:%S')}]: {message}",  *args, **kwargs, end="\x1b[0m\n")

def okay(message, *args, **kwargs):
    print(f"\x1b[32;1mK [{time.strftime('%H:%M:%S')}]: {message}",  *args, **kwargs, end="\x1b[0m\n")


log("HELLO")

try:
    from dialog import Dialog
except ImportError:
    error("dialog is not installed!")
    try:
        input("Press Enter to install or Ctrl+C to exit")
    except:
        exit(1)
    log("installing dialog...")

    import pip
    pip.main(['install', 'pythondialog', '--break-system-packages'])

    from dialog import Dialog


def create_dir_if_not_exists(path: str):
    if not os.path.exists(path):
        os.makedirs(path)


def dialog_select_configuration(dialog: Dialog) -> (str, str):
    choices = [
        ("New", "Create new configuration"),
        ("", "")
    ]

    for i in os.listdir("builds"):
        choices.append((i, f"Configuration"))

    a = dialog.menu("Select configuration", choices=choices)

    return a


def dialog_new_configuration(dialog: Dialog):
    a = ("ok", "New")
    while a[1] == 'New':
        a = dialog.inputbox("Enter configuration name:")

    return a


def load_configuration(config_name: str) -> Config:
    with open(f"builds/{config_name}/config.yaml", "r") as f:
        d = yaml.load(f, Loader=yaml.FullLoader)
        return Config(**d)


def save_configuration(name: str, config: Config):
    with open(f"builds/{name}/config.yaml", "w") as f:
        f.write("# DO NOT EDIT THIS FILE MANUALLY!\n")
        f.write("# This file is automatically generated by the Scorbunny configuration tool.\n\n")

        yaml.dump(config.__dict__, f)

        f.truncate()

    config2mk(name, config)


def dialog_configure_parameter(dialog: Dialog, config_name: str, config_parameter: str):
    conf = load_configuration(config_name)   # load configuration

    parameter = [i for i in MAPPING if i[0] == config_parameter][0]

    choices = []
    choices_texts = parameter[2]

    if parameter[2] is bool:
        choices_texts = (True, False)
    
    for i in choices_texts:
        choices.append((str(i), "", conf.__dict__[parameter[1]] == i))

    choice = dialog.radiolist(f"{config_name} - {parameter[0]}", choices=choices)

    if choice[0] == 'ok':
        # Convert string selecttion into a type provided in a mapped field 
        if parameter[2] is bool:
            conf.__dict__[parameter[1]] = eval(choice[1])
        else:
            conf.__dict__[parameter[1]] = type(conf.__dict__[parameter[1]])(choice[1])

        save_configuration(config_name, conf)

    return choice


def dialog_configure(dialog: Dialog, config_name: str):
    conf = load_configuration(config_name)   # load configuration

    choices = []

    for i in MAPPING:
        choices.append((i[0], f"{conf.__dict__[i[1]]}"))

    choice = dialog.menu(f"Configuring `{config_name}`", choices=choices)

    return choice

def config2mk(name: str, config: Config):
    text = ""

    for k, v in config.__dict__.items():
        text += k.upper() + f"?={v}\n"

    with open(f"builds/{name}/config.mk", "w") as f:
        f.write("# DO NOT EDIT THIS FILE MANUALLY!\n")
        f.write("# This file is automatically generated by the Scorbunny configuration tool.\n\n")

        f.write(text)
        f.truncate()


def main():
    log("Creating `builds/` directory...")
    create_dir_if_not_exists("builds")

    dialog = Dialog()
    dialog.set_background_title("The Scorbunny configuration tool v0.1")

    while True:
        a = dialog_select_configuration(dialog)

        if a[0] == 'cancel':
            exit(0)

        if a[1] == '':
            continue

        if a[1] == 'New':
            res = dialog_new_configuration(dialog)

            if res[0] == 'cancel':
                continue

            os.mkdir(f"builds/{res[1]}")  # create new configuration directory

            save_configuration(res[1], Config())

            # Copy files
            shutil.copy("common.mk", f"builds/{res[1]}/common.mk")
            # shutil.copy("config.mk", f"builds/{res[1]}/config.mk")
            shutil.copytree("ramdisk", f"builds/{res[1]}/ramdisk", dirs_exist_ok=True)
            shutil.copytree("iso", f"builds/{res[1]}/iso", dirs_exist_ok=True)

            okay(f"Configuration {res[1]} created!")
        else:
            while True:
                cfg = dialog_configure(dialog, a[1])

                if cfg[0] == 'ok':
                    dialog_configure_parameter(dialog, a[1], cfg[1])
                else:
                    break


if __name__ == "__main__":
    main()
