#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.

import inspect
import os
from configparser import ConfigParser

from fenrirscreenreader.core import applicationManager
from fenrirscreenreader.core import attributeManager
from fenrirscreenreader.core import barrierManager
from fenrirscreenreader.core import commandManager
from fenrirscreenreader.core import cursorManager
from fenrirscreenreader.core import debug
from fenrirscreenreader.core import debugManager
from fenrirscreenreader.core import diffReviewManager
from fenrirscreenreader.core import environment
from fenrirscreenreader.core import eventManager
from fenrirscreenreader.core import helpManager
from fenrirscreenreader.core import inputManager
from fenrirscreenreader.core import memoryManager
from fenrirscreenreader.core import outputManager
from fenrirscreenreader.core import processManager
from fenrirscreenreader.core import punctuationManager
from fenrirscreenreader.core import quickMenuManager
from fenrirscreenreader.core import readAllManager
from fenrirscreenreader.core import remoteManager
from fenrirscreenreader.core import sayAllManager
from fenrirscreenreader.core import screenManager
from fenrirscreenreader.core import tableManager
from fenrirscreenreader.core import textManager
from fenrirscreenreader.core import vmenuManager
from fenrirscreenreader.core.settingsData import settings_data
from fenrirscreenreader.utils import module_utils

currentdir = os.path.dirname(
    os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
fenrir_path = os.path.dirname(currentdir)


class SettingsManager:
    system_settings_root = "/etc/fenrirscreenreader/"
    system_settings_file = "/etc/fenrirscreenreader/settings/settings.conf"
    user_settings_file = (
        "~/.local/share/stormux/fenrirscreenreader/settings/settings.conf"
    )
    user_resource_root = "~/.local/stormux/fenrir/"
    system_sound_roots = [
        "/usr/share/sounds/fenrir/",
        "/usr/share/sounds/fenrirscreenreader/",
    ]

    def __init__(self):
        self.settings = settings_data
        self.settingArgDict = {}
        self.bindingsBackup = None
        self.settings_file = ""
        self.save_settings_path = ""

    def initialize(self, environment):
        self.env = environment

    def shutdown(self):
        pass

    def get_binding_backup(self):
        return self.bindingsBackup.copy()

    def load_sound_icons(self, soundIconPath, environment=None):
        # Use passed environment or fall back to self.env
        env = environment if environment is not None else self.env
        try:
            with open(soundIconPath + "/soundicons.conf", "r") as siConfig:
                while True:
                    line = siConfig.readline()
                    if not line:
                        break
                    line = line.replace("\n", "")
                    if line.replace(" ", "") == "":
                        continue
                    if line.replace(" ", "").startswith("#"):
                        continue
                    if line.count("=") != 1:
                        continue
                    values = line.split("=")
                    sound_icon = values[0].upper()
                    values[1] = values[1].replace("'", "")
                    values[1] = values[1].replace('"', "")
                    sound_icon_file = ""
                    if os.path.exists(values[1]):
                        sound_icon_file = values[1]
                    else:
                        if not soundIconPath.endswith("/"):
                            soundIconPath += "/"
                        if os.path.exists(soundIconPath + values[1]):
                            sound_icon_file = soundIconPath + values[1]
                    env["soundIcons"][sound_icon] = sound_icon_file
                    env["runtime"]["DebugManager"].write_debug_out(
                        "SoundIcon: " + sound_icon + "." + sound_icon_file,
                        debug.DebugLevel.INFO,
                        on_any_level=True,
                    )
        except (IOError, OSError) as e:
            env["runtime"]["DebugManager"].write_debug_out(
                "load_sound_icons: failed to load sound icons from "
                + soundIconPath
                + ". Error: "
                + str(e),
                debug.DebugLevel.ERROR,
            )

    def get_settings_file(self):
        return self.settings_file

    def set_settings_file(self, settings_file):
        if os.path.exists(settings_file) and not os.access(
            settings_file, os.R_OK
        ):
            return
        self.settings_file = settings_file

    def get_user_settings_file(self):
        return os.path.expanduser(self.user_settings_file)

    def get_system_settings_file(self):
        return self.system_settings_file

    def is_user_settings_mode(self):
        return os.geteuid() != 0

    def get_default_save_settings_file(self):
        if self.is_user_settings_mode():
            return self.get_user_settings_file()
        return self.get_system_settings_file()

    def get_bundled_settings_root(self):
        return os.path.abspath(os.path.join(fenrir_path, "../../config/")) + "/"

    def get_user_resource_root(self):
        return os.path.expanduser(self.user_resource_root)

    def get_user_script_path(self):
        return self.get_user_resource_root()

    def get_user_sound_root(self):
        return os.path.join(self.get_user_resource_root(), "sounds/")

    def get_resource_settings_root(self):
        if os.path.exists(self.system_settings_root):
            return self.system_settings_root
        bundled_settings_root = self.get_bundled_settings_root()
        if os.path.exists(bundled_settings_root):
            return bundled_settings_root
        return ""

    def get_sound_theme_roots(self):
        candidate_roots = [
            self.get_user_sound_root(),
            *self.system_sound_roots,
            os.path.join(self.get_bundled_settings_root(), "sound/"),
        ]
        sound_roots = []
        seen_roots = set()
        for root in candidate_roots:
            normalized_root = os.path.abspath(os.path.expanduser(root))
            if normalized_root in seen_roots:
                continue
            sound_roots.append(normalized_root + "/")
            seen_roots.add(normalized_root)
        return sound_roots

    def resolve_sound_theme_path(self, theme):
        if not theme:
            return ""
        theme = os.path.expanduser(theme)
        if os.path.exists(os.path.join(theme, "soundicons.conf")):
            return theme
        for sound_root in self.get_sound_theme_roots():
            theme_path = os.path.join(sound_root, theme)
            if os.path.exists(os.path.join(theme_path, "soundicons.conf")):
                return theme_path
        return ""

    def load_keyboard_layout(self, environment):
        settings_root = self.get_resource_settings_root()
        keyboard_layout = self.get_setting("keyboard", "keyboard_layout")
        if os.path.exists(keyboard_layout):
            environment["runtime"]["InputManager"].load_shortcuts(
                keyboard_layout
            )
            return

        layout_path = os.path.join(settings_root, "keyboard", keyboard_layout)
        if os.path.exists(layout_path):
            self.set_setting("keyboard", "keyboard_layout", layout_path)
            environment["runtime"]["InputManager"].load_shortcuts(layout_path)
            return

        layout_path = os.path.join(
            settings_root, "keyboard", keyboard_layout + ".conf"
        )
        if os.path.exists(layout_path):
            self.set_setting("keyboard", "keyboard_layout", layout_path)
            environment["runtime"]["InputManager"].load_shortcuts(layout_path)

    def resolve_settings_file(self, requested_settings_file=None):
        if requested_settings_file and os.path.exists(requested_settings_file):
            return requested_settings_file

        if self.is_user_settings_mode() and os.path.exists(
            self.get_user_settings_file()
        ):
            return self.get_user_settings_file()

        if os.path.exists(self.get_system_settings_file()):
            return self.get_system_settings_file()

        bundled_settings_file = os.path.join(
            self.get_bundled_settings_root(), "settings/settings.conf"
        )
        if os.path.exists(bundled_settings_file):
            return bundled_settings_file

        return ""

    def load_settings(self, setting_config_path):
        if not os.path.exists(setting_config_path):
            return False
        if not os.access(setting_config_path, os.R_OK):
            return False
        self.env["settings"] = ConfigParser()
        try:
            self.env["settings"].read(setting_config_path)
        except Exception as e:
            self.env["runtime"]["DebugManager"].write_debug_out(
                "settings_manager load_settings: Error reading config file: "
                + str(e),
                debug.DebugLevel.ERROR,
            )
            return False
        self.set_settings_file(setting_config_path)
        return True

    def save_settings(self, setting_config_path=None):
        if setting_config_path is None:
            if self.save_settings_path:
                setting_config_path = self.save_settings_path
            else:
                setting_config_path = self.get_default_save_settings_file()

        # Ensure directory exists for user-local settings
        if setting_config_path and setting_config_path.startswith(
            os.path.expanduser("~/.local/")
        ):
            config_dir = os.path.dirname(setting_config_path)
            if not os.path.exists(config_dir):
                try:
                    os.makedirs(config_dir, mode=0o755, exist_ok=True)
                except Exception as e:
                    self.env["runtime"]["DebugManager"].write_debug_out(
                        "save_settings: failed to create directory "
                        + config_dir
                        + ": "
                        + str(e),
                        debug.DebugLevel.ERROR,
                    )
        # set opt dict here
        # save file
        try:
            # print('file: ',setting_config_path)
            for section, settings in self.settingArgDict.items():
                for setting, value in settings.items():
                    # print(section, setting, value)
                    self.env["settings"].set(section, setting, value)
            # print('full',self.env['settings'])

            config_file = open(setting_config_path, "w")
            self.env["settings"].write(config_file)
            config_file.close()
            os.chmod(setting_config_path, 0o644)
        except Exception as e:
            self.env["runtime"]["DebugManager"].write_debug_out(
                "save_settings: save settingsfile:"
                + setting_config_path
                + "failed. Error:"
                + str(e),
                debug.DebugLevel.ERROR,
            )

    def set_setting(self, section, setting, value):
        self.set_option_arg_dict(section, setting, value)
        # self.env['settings'].set(section, setting, value)

    def get_setting(self, section, setting):
        value = ""
        try:
            value = self.settingArgDict[section][setting]
            return value
        except Exception as e:
            pass
        try:
            value = self.env["settings"].get(section, setting)
        except Exception as e:
            value = str(self.settings[section][setting])
        return value

    def get_setting_as_int(self, section, setting):
        value = 0
        try:
            value = int(self.settingArgDict[section][setting])
            return value
        except Exception as e:
            pass
        try:
            value = self.env["settings"].getint(section, setting)
        except Exception as e:
            value = self.settings[section][setting]
        return value

    def get_setting_as_float(self, section, setting):
        value = 0.0
        try:
            value = float(self.settingArgDict[section][setting])
            return value
        except Exception as e:
            pass
        try:
            value = self.env["settings"].getfloat(section, setting)
        except Exception as e:
            value = self.settings[section][setting]
        return value

    def get_setting_as_bool(self, section, setting):
        value = False
        try:
            value = self.settingArgDict[section][setting].upper() in [
                "1",
                "YES",
                "JA",
                "TRUE",
            ]
            return value
        except Exception as e:
            pass
        try:
            value = self.env["settings"].getboolean(section, setting)
        except Exception as e:
            value = self.settings[section][setting]
        return value

    def load_driver(self, driverName, driverType):
        # Map runtime keys to actual directory names
        driver_dir_map = {
            "InputDriver": "inputDriver",
            "ScreenDriver": "screenDriver",
            "SpeechDriver": "speechDriver",
            "SoundDriver": "soundDriver",
            "RemoteDriver": "remoteDriver",
        }
        driver_dir = driver_dir_map.get(driverType, driverType)

        try:
            if self.env["runtime"][driverType] is not None:
                self.env["runtime"][driverType].shutdown()
        except Exception as e:
            self.env["runtime"]["DebugManager"].write_debug_out(
                "settings_manager load_driver: Error shutting down driver: "
                + str(e),
                debug.DebugLevel.ERROR,
            )
        try:
            driver_mod = module_utils.import_module(
                driverName,
                fenrir_path + "/" + driver_dir + "/" + driverName + ".py",
            )
            self.env["runtime"][driverType] = driver_mod.driver()
            self.env["runtime"][driverType].initialize(self.env)
            self.env["runtime"]["DebugManager"].write_debug_out(
                "Loading Driver " + driverType + " (" + driverName + ") OK",
                debug.DebugLevel.INFO,
                on_any_level=True,
            )
        except Exception as e:
            self.env["runtime"]["DebugManager"].write_debug_out(
                "Loading Driver "
                + driverType
                + " ("
                + driverName
                + ") FAILED:"
                + str(e),
                debug.DebugLevel.ERROR,
            )
            try:
                driver_mod = module_utils.import_module(
                    driverName,
                    fenrir_path + "/" + driver_dir + "/dummyDriver.py",
                )
                self.env["runtime"][driverType] = driver_mod.driver()
                self.env["runtime"][driverType].initialize(self.env)
            except Exception as e:
                self.env["runtime"]["DebugManager"].write_debug_out(
                    "(fallback) Loading Driver "
                    + driverType
                    + " (dummyDriver) FAILED:"
                    + str(e),
                    debug.DebugLevel.ERROR,
                )

    def shutdown_driver(self, driverType):
        try:
            self.env["runtime"][driverType].shutdown()
        except Exception as e:
            pass
        del self.env["runtime"][driverType]

    def set_fenrir_keys(self, keys):
        keys = keys.upper()
        key_list = keys.split(",")
        for key in key_list:
            if key not in self.env["input"]["fenrir_key"]:
                self.env["input"]["fenrir_key"].append(key)

    def set_script_keys(self, keys):
        keys = keys.upper()
        key_list = keys.split(",")
        for key in key_list:
            if key not in self.env["input"]["script_key"]:
                self.env["input"]["script_key"].append(key)

    def reset_setting_arg_dict(self):
        self.settingArgDict = {}
        self.env["runtime"]["OutputManager"].reset_SpeechDriver()

    def set_option_arg_dict(self, section, setting, value):
        # section = section.lower()
        # setting = setting.lower()
        try:
            e = self.settingArgDict[section]
        except KeyError:
            self.settingArgDict[section] = {}
        try:
            t = self.settings[section][setting]
        except Exception as e:
            print(section, setting, "not found")
            return
        try:
            v = value  # Initialize v with the original value
            if isinstance(self.settings[section][setting], str):
                v = str(value)
            elif isinstance(self.settings[section][setting], bool):
                if value not in ["True", "False"]:
                    raise ValueError(
                        "could not convert string to bool: " + value
                    )
                v = value == "True"
            elif isinstance(self.settings[section][setting], int):
                v = int(value)
            elif isinstance(self.settings[section][setting], float):
                v = float(value)

            # Content validation for critical settings
            self._validate_setting_value(section, setting, v)

            self.settingArgDict[section][setting] = str(value)
        except Exception as e:
            print(
                "settings_manager:set_option_arg_dict:Datatype missmatch: "
                + section
                + "#"
                + setting
                + "="
                + str(value)
                + " Error:"
                + str(e)
            )
            # self.env['runtime']['DebugManager'].write_debug_out('settings_manager:set_option_arg_dict:Datatype
            # missmatch: '+ section + '#' + setting + '=' +  value + ' Error:'
            # +  str(e), debug.DebugLevel.ERROR)
            return

    def _validate_setting_value(self, section, setting, value):
        """Validate setting values for critical screen reader functionality.
        Only validates settings that could cause crashes or accessibility issues.
        Invalid values raise ValueError which is caught by the calling method.
        """

        # Speech settings validation - critical for accessibility
        if section == "speech":
            if setting == "rate":
                if not (0.0 <= value <= 3.0):
                    raise ValueError(
                        f"Speech rate must be between 0.0 and 3.0, got {value}"
                    )
            elif setting == "pitch":
                if not (0.0 <= value <= 2.0):
                    raise ValueError(
                        f"Speech pitch must be between 0.0 and 2.0, got {value}"
                    )
            elif setting == "volume":
                if not (0.0 <= value <= 1.5):
                    raise ValueError(
                        f"Speech volume must be between 0.0 and 1.5, got {value}"
                    )
            elif setting == "driver":
                valid_drivers = [
                    "speechdDriver",
                    "genericDriver",
                    "dummyDriver",
                ]
                if value not in valid_drivers:
                    raise ValueError(
                        f"Invalid speech driver: {value}. Valid options: {valid_drivers}"
                    )

        # Sound settings validation
        elif section == "sound":
            if setting == "volume":
                if not (0.0 <= value <= 1.5):
                    raise ValueError(
                        f"Sound volume must be between 0.0 and 1.5, got {value}"
                    )
            elif setting == "driver":
                valid_drivers = [
                    "genericDriver",
                    "gstreamerDriver",
                    "dummyDriver",
                ]
                if value not in valid_drivers:
                    raise ValueError(
                        f"Invalid sound driver: {value}. Valid options: {valid_drivers}"
                    )

        # Screen settings validation
        elif section == "screen":
            if setting == "driver":
                valid_drivers = ["vcsaDriver", "ptyDriver", "dummyDriver"]
                if value not in valid_drivers:
                    raise ValueError(
                        f"Invalid screen driver: {value}. Valid options: {valid_drivers}"
                    )

        # Input settings validation
        elif section == "keyboard":
            if setting == "driver":
                valid_drivers = [
                    "evdevDriver",
                    "x11Driver",
                    "dummyDriver",
                ]
                if value not in valid_drivers:
                    raise ValueError(
                        f"Invalid input driver: {value}. Valid options: {valid_drivers}"
                    )

        # General settings validation
        elif section == "general":
            if setting == "debug_level":
                if not (0 <= value <= 3):
                    raise ValueError(
                        f"Debug level must be between 0 and 3, got {value}"
                    )

    def parse_setting_args(self, settingArgs):
        if settingArgs is None:
            return
        for optionElem in settingArgs.split(";"):
            setting_val_list = []
            section_option_list = []
            section = ""
            option = ""
            value = ""
            setting_val_list = optionElem.split("=", 1)
            if len(setting_val_list) != 2:
                continue
            if "#" in setting_val_list[0]:
                section_option_list = setting_val_list[0].split("#", 1)
            elif "." in setting_val_list[0]:
                section_option_list = setting_val_list[0].split(".", 1)
            elif "," in setting_val_list[0]:
                section_option_list = setting_val_list[0].split(",", 1)
            elif "!" in setting_val_list[0]:
                section_option_list = setting_val_list[0].split("!", 1)
            else:
                continue
            if len(section_option_list) != 2:
                continue

            section = str(section_option_list[0])
            option = str(section_option_list[1])
            value = str(setting_val_list[1])
            self.set_option_arg_dict(section, option, value)

    def init_fenrir_config(
        self, cliArgs, fenrir_manager=None, environment=environment.environment
    ):
        self.cliArgs = cliArgs

        settings_root = self.get_resource_settings_root()
        if not settings_root:
            return None

        self.save_settings_path = self.get_default_save_settings_file()
        settings_file = self.resolve_settings_file(cliArgs.setting)
        if not settings_file:
            return None

        environment["runtime"]["SettingsManager"] = self
        environment["runtime"]["SettingsManager"].initialize(environment)

        valid_config = environment["runtime"]["SettingsManager"].load_settings(
            settings_file
        )
        if not valid_config:
            return None
        if cliArgs.options != "":
            self.parse_setting_args(cliArgs.options)
        if cliArgs.debug:
            self.set_setting("general", "debug_level", 3)
        if cliArgs.print:
            self.set_setting("general", "debug_level", 3)
            self.set_setting("general", "debug_mode", "PRINT")
        if cliArgs.x11:
            self.set_setting("screen", "driver", "ptyDriver")
            self.set_setting("keyboard", "driver", "x11Driver")
        if cliArgs.x11_window_id:
            self.set_setting(
                "keyboard", "x11_window_id", cliArgs.x11_window_id
            )

        self.set_fenrir_keys(self.get_setting("general", "fenrir_keys"))
        self.set_script_keys(self.get_setting("general", "script_keys"))

        environment["runtime"]["DebugManager"] = debugManager.DebugManager(
            self.env["runtime"]["SettingsManager"].get_setting(
                "general", "debug_file"
            )
        )
        environment["runtime"]["DebugManager"].initialize(environment)

        if cliArgs.force_all_screens:
            environment["runtime"]["force_all_screens"] = True

        if cliArgs.ignore_screen:
            current_ignore_screen = self.get_setting("screen", "ignore_screen")
            if current_ignore_screen:
                ignore_screens = (
                    current_ignore_screen.split(",") + cliArgs.ignore_screen
                )
            else:
                ignore_screens = cliArgs.ignore_screen
            self.set_setting(
                "screen", "ignore_screen", ",".join(ignore_screens)
            )

        sound_theme_path = self.resolve_sound_theme_path(
            self.get_setting("sound", "theme")
        )
        if sound_theme_path:
            self.set_setting("sound", "theme", sound_theme_path)
            environment["runtime"]["SettingsManager"].load_sound_icons(
                self.get_setting("sound", "theme"), environment
            )

        environment["runtime"][
            "PunctuationManager"
        ] = punctuationManager.PunctuationManager()
        environment["runtime"]["PunctuationManager"].initialize(environment)

        environment["runtime"]["TextManager"] = textManager.TextManager()
        environment["runtime"]["TextManager"].initialize(environment)

        if not os.path.exists(
            self.get_setting("general", "punctuation_profile")
        ):
            if os.path.exists(
                settings_root
                + "punctuation/"
                + self.get_setting("general", "punctuation_profile")
            ):
                self.set_setting(
                    "general",
                    "punctuation_profile",
                    settings_root
                    + "punctuation/"
                    + self.get_setting("general", "punctuation_profile"),
                )
                environment["runtime"]["PunctuationManager"].load_dicts(
                    self.get_setting("general", "punctuation_profile")
                )
            if os.path.exists(
                settings_root
                + "punctuation/"
                + self.get_setting("general", "punctuation_profile")
                + ".conf"
            ):
                self.set_setting(
                    "general",
                    "punctuation_profile",
                    settings_root
                    + "punctuation/"
                    + self.get_setting("general", "punctuation_profile")
                    + ".conf",
                )
                environment["runtime"]["PunctuationManager"].load_dicts(
                    self.get_setting("general", "punctuation_profile")
                )
        else:
            environment["runtime"]["PunctuationManager"].load_dicts(
                self.get_setting("general", "punctuation_profile")
            )

        if fenrir_manager:
            environment["runtime"]["FenrirManager"] = fenrir_manager

        environment["runtime"]["MemoryManager"] = memoryManager.MemoryManager()
        environment["runtime"]["MemoryManager"].initialize(environment)

        environment["runtime"][
            "AttributeManager"
        ] = attributeManager.AttributeManager()
        environment["runtime"]["AttributeManager"].initialize(environment)

        environment["runtime"]["EventManager"] = eventManager.EventManager()
        environment["runtime"]["EventManager"].initialize(environment)

        environment["runtime"][
            "ProcessManager"
        ] = processManager.ProcessManager()
        environment["runtime"]["ProcessManager"].initialize(environment)

        environment["runtime"]["OutputManager"] = outputManager.OutputManager()
        environment["runtime"]["OutputManager"].initialize(environment)

        environment["runtime"]["InputManager"] = inputManager.InputManager()
        environment["runtime"]["InputManager"].initialize(environment)
        self.load_keyboard_layout(environment)

        environment["runtime"]["ScreenManager"] = screenManager.ScreenManager()
        environment["runtime"]["ScreenManager"].initialize(environment)

        environment["runtime"][
            "CommandManager"
        ] = commandManager.CommandManager()
        environment["runtime"]["CommandManager"].initialize(environment)

        environment["runtime"]["HelpManager"] = helpManager.HelpManager()
        environment["runtime"]["HelpManager"].initialize(environment)

        environment["runtime"]["RemoteManager"] = remoteManager.RemoteManager()
        environment["runtime"]["RemoteManager"].initialize(environment)

        environment["runtime"][
            "DiffReviewManager"
        ] = diffReviewManager.DiffReviewManager()
        environment["runtime"]["DiffReviewManager"].initialize(environment)

        environment["runtime"]["CursorManager"] = cursorManager.CursorManager()
        environment["runtime"]["CursorManager"].initialize(environment)
        environment["runtime"][
            "ApplicationManager"
        ] = applicationManager.ApplicationManager()
        environment["runtime"]["ApplicationManager"].initialize(environment)
        environment["runtime"]["TextManager"] = textManager.TextManager()
        environment["runtime"]["TextManager"].initialize(environment)
        environment["runtime"]["TableManager"] = tableManager.TableManager()
        environment["runtime"]["TableManager"].initialize(environment)
        environment["runtime"][
            "BarrierManager"
        ] = barrierManager.BarrierManager()
        environment["runtime"]["BarrierManager"].initialize(environment)
        environment["runtime"]["SayAllManager"] = sayAllManager.SayAllManager()
        environment["runtime"]["SayAllManager"].initialize(environment)
        environment["runtime"]["VmenuManager"] = vmenuManager.VmenuManager()
        environment["runtime"]["VmenuManager"].initialize(environment)
        environment["runtime"][
            "QuickMenuManager"
        ] = quickMenuManager.QuickMenuManager()
        environment["runtime"]["QuickMenuManager"].initialize(environment)
        
        environment["runtime"][
            "ReadAllManager"
        ] = readAllManager.ReadAllManager()
        environment["runtime"]["ReadAllManager"].initialize(environment)

        # only possible after having input and screen managers with clean
        # buffer
        environment["runtime"]["InputManager"].write_event_buffer()
        environment["runtime"]["InputManager"].handle_device_grab(force=True)

        environment["runtime"]["DebugManager"].write_debug_out(
            r"/-------environment-------/",
            debug.DebugLevel.INFO,
            on_any_level=True,
        )
        environment["runtime"]["DebugManager"].write_debug_out(
            str(environment), debug.DebugLevel.INFO, on_any_level=True
        )
        environment["runtime"]["DebugManager"].write_debug_out(
            r"/-------settings.conf-------/",
            debug.DebugLevel.INFO,
            on_any_level=True,
        )
        environment["runtime"]["DebugManager"].write_debug_out(
            str(environment["settings"]._sections),
            debug.DebugLevel.INFO,
            on_any_level=True,
        )
        environment["runtime"]["DebugManager"].write_debug_out(
            r"/-------self.settingArgDict-------/",
            debug.DebugLevel.INFO,
            on_any_level=True,
        )
        environment["runtime"]["DebugManager"].write_debug_out(
            str(self.settingArgDict), debug.DebugLevel.INFO, on_any_level=True
        )
        self.bindingsBackup = environment["bindings"].copy()

        return environment
