import configparser
from typing import Tuple, List, Set
import io

from UM.Util import parseBool
from UM.VersionUpgrade import VersionUpgrade

_removed_settings = {
    "spaghetti_infill_enabled",
    "spaghetti_infill_stepped",
    "spaghetti_max_infill_angle",
    "spaghetti_max_height",
    "spaghetti_inset",
    "spaghetti_flow",
    "spaghetti_infill_extra_volume",
    "support_tree_enable"
}  # type: Set[str]

class VersionUpgrade30to31(VersionUpgrade):
    def getCfgVersion(self, serialised: str) -> int:
        parser = configparser.ConfigParser(interpolation=None)
        parser.read_string(serialised)
        format_version = int(parser.get("general", "version"))  # Explicitly give an exception when this fails. That means that the file format is not recognized.
        setting_version = int(parser.get("metadata", "setting_version", fallback="0"))
        return format_version * 1000000 + setting_version

    ##  Upgrades Preferences to have the new version number.
    #
    #   This renames the renamed settings in the list of visible settings.
    def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
        parser = configparser.ConfigParser(interpolation=None)
        parser.read_string(serialized)

        # Update version number.
        parser["metadata"]["setting_version"] = "15"

        if "general" in parser and "visible_settings" in parser["general"]:
            settings = set(parser["general"]["visible_settings"].split(";"))

            # add support_structure to the visible settings list if necessary
            if "support_tree_enable" in parser["general"]["visible_settings"]:
                settings.add("support_structure")

            # Remove deleted settings from the visible settings list.
            settings.difference_update(_removed_settings)

            # serialize
            parser["general"]["visible_settings"] = ";".join(settings)

        result = io.StringIO()
        parser.write(result)
        return [filename], [result.getvalue()]

    ##  Upgrades instance containers to have the new version
    #   number.
    #
    #   This renames the renamed settings in the containers.
    def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
        parser = configparser.ConfigParser(interpolation=None, comment_prefixes=())
        parser.read_string(serialized)

        # Update version number.
        parser["metadata"]["setting_version"] = "15"

        if "values" in parser:
            # Set support_structure if necessary
            if "support_tree_enable" in parser["values"]:
                if parseBool(parser["values"]["support_tree_enable"]):
                    parser["values"]["support_structure"] = "tree"
                    parser["values"]["support_enable"] = "True"

        result = io.StringIO()
        parser.write(result)
        return [filename], [result.getvalue()]

    ##  Upgrades stacks to have the new version number.
    def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
        parser = configparser.ConfigParser(interpolation=None)
        parser.read_string(serialized)

        # Update version number.
        if "metadata" not in parser:
            parser["metadata"] = {}
        parser["metadata"]["setting_version"] = "15"

        result = io.StringIO()
        parser.write(result)
        return [filename], [result.getvalue()]
