################################################################################
#
# Copyright (c) 2020–2021 Dominus Iniquitatis <zerosaiko@gmail.com>
#
# See LICENSE file for the licensing information
#
################################################################################
import json
import os
import renpy

from zipfile import ZipFile

_game_dir = os.path.join(renpy.config.basedir, "game")
_meta_dir = os.path.join(_game_dir, "comfy_meta")
_config_path = os.path.join(_meta_dir, "settings.json")

_default_settings = {
    "selected_theme_index": 0,
    "use_fonts": True,
    "use_layout": True,
    "use_hidpi": False,
    "installed_files": []
}

class ThemeManager:
    def __init__(self):
        self._log_file = open(os.path.join(_meta_dir, "logfile.txt"), "w")
        self.settings = {}
        self.settings.update(_default_settings)
        self._themes = []
        self._fetch_themes()
        self.load_settings()

    def disable(self):
        self._remove_current_theme()

    def get_current_theme(self):
        return self._themes[self.settings["selected_theme_index"]]

    def get_current_theme_name(self):
        return self.get_current_theme()["name"]

    def get_current_theme_preview(self):
        return self.get_current_theme()["preview"]

    def get_theme_count(self):
        return len(self._themes)

    def install(self):
        self._remove_current_theme()
        self._install_theme(self.get_current_theme())

    def load_settings(self):
        if not os.path.exists(_config_path):
            return

        with open(_config_path, "r") as file:
            self.settings.update(json.load(file))

    def save_settings(self):
        with open(_config_path, "w") as file:
            json.dump(self.settings, file, indent = 4, sort_keys = False)

    def _log(self, msg):
        self._log_file.write("%s\n" % str(msg))

    def _fetch_themes(self):
        for file_path in os.listdir(_meta_dir):
            file_name, file_ext = os.path.splitext(file_path)

            if file_ext == ".arc" and not file_name.endswith("_hidpi"):
                theme_info = self._get_theme_info(os.path.join(_meta_dir, file_path),
                                                  os.path.join(_meta_dir, "%s_hidpi.arc" % file_name))
                self._themes.append(theme_info)

        # FIXME: there should be a better way to put the Default theme above the others
        def comparator(x):
            name = x["name"]

            if name == "Default":
                return "  %s" % name
            elif name == "Classic":
                return " %s" % name

            return name

        self._themes.sort(key = comparator)

    def _get_theme_info(self, file_path, hidpi_path):
        result = {
            "path": file_path,
            "hidpi_path": hidpi_path
        }

        with ZipFile(file_path, "r") as theme_arc:
            with theme_arc.open("info.json", "r") as info_json:
                result.update(json.load(info_json))

            preview_path = theme_arc.extract("preview.png", _meta_dir)

            theme_preview_file_name = "%s_preview.png" % result["id"]
            theme_preview_path = os.path.join(_meta_dir, theme_preview_file_name)

            if os.path.exists(theme_preview_path):
                os.remove(theme_preview_path)

            os.rename(preview_path, theme_preview_path)

            result["preview"] = "comfy_meta/%s" % theme_preview_file_name

        return result

    def _install_theme(self, theme):
        ignored_files = [
            "info.json",
            "preview.png"
        ]

        if not self.settings["use_fonts"]:
            ignored_files.append("fonts.rpy")

        if not self.settings["use_layout"]:
            ignored_files.append("layout.rpy")

        self.settings["installed_files"] = []

        theme_path = theme["path"] if not self.settings["use_hidpi"] else theme["hidpi_path"]

        with ZipFile(theme_path, "r") as theme_arc:
            for file_path in theme_arc.namelist():
                if os.path.basename(file_path) in ignored_files:
                    self._log("Skipping %s..." % file_path)
                    continue

                self._log("Installing %s..." % file_path)
                theme_arc.extract(file_path, _game_dir)

                self.settings["installed_files"].append(file_path)

        self._log("Theme installed.")

    def _remove_current_theme(self):
        for file_path in reversed(self.settings["installed_files"]):
            full_path = os.path.join(_game_dir, file_path)

            if os.path.exists(full_path) and not os.path.isdir(full_path):
                file_name, file_ext = os.path.splitext(full_path)

                self._log("Removing %s..." % full_path)
                os.remove(full_path)

                if file_ext == ".rpy":
                    self._log("Removing %s.rpyc..." % file_name)
                    os.remove("%s.rpyc" % file_name)

        self.settings["installed_files"] = []

        self._log("Theme removed.")