# -*- coding: utf-8 -*-
from setuphelpers import *

r""" 
https://kb.nomachine.com/AR02N00877

The server.cfg and/or node.cfg files are placed in :

/usr/NX/etc/on Linux

C:\Program files\NoMachine\etc\server.cfg for 64bit packages on 64bit systems
and C:\Program files (x86)\NoMachine\etc\server.cfg for 32bit packages on Windows 64bit systems

/Applications/NoMachine.app/Contents/Frameworks/etc/server.cfg on macOS.

"""


def get_nomachine_dir():
    if get_os_name() == "Windows":
        app_dir = makepath(programfiles, "NoMachine")
    elif get_os_name() == "Linux":
        app_dir = "/usr/NX"
    elif get_os_name() == "Darwin":
        app_dir = "/Applications/NoMachine.app/Contents/Frameworks"
    else:
        error("os not detected")
    return app_dir


server_cfg_path = makepath(get_nomachine_dir(), "etc", "server.cfg")
node_cfg_path = makepath(get_nomachine_dir(), "etc", "node.cfg")

library_nomachine = "/Library/Application Support/NoMachine"
nxuninstall_script = makepath(library_nomachine, "nxuninstall.sh")


def install():
    bin_name = glob.glob("nomachine_*.dmg")[0]

    for service in ['localnxserver', 'nxserver']:
        run_notfatal(f"launchctl stop com.nomachine.{service}")

    remove_script_interactivity()
    try:
        install_dmg(
            bin_name,
            key="/Applications/NoMachine.app",
            min_version=control.get_software_version()
        )
    except Exception as e:
        if not 'hdiutil: detach failed' in str(e):
            raise
        

    uninstallkey.clear()

    remove_script_interactivity()

    # Configuring server.cfg default preferences
    config_dict = {
        "#UpdateFrequency": "UpdateFrequency 0",
        "UpdateFrequency": "UpdateFrequency 0",
        "#StartNXDaemon": "StartNXDaemon 0",
        "StartNXDaemon": "StartNXDaemon 0",
        "#PhysicalDesktopSharing": "PhysicalDesktopSharing 0",
        "PhysicalDesktopSharing": "PhysicalDesktopSharing 0",
        "#PhysicalDesktopSharing": "PhysicalDesktopSharing 0",
        "#EnableNetworkBroadcast": "EnableNetworkBroadcast 0",
        "#VirtualDesktopAccess": "VirtualDesktopAccess none",
        "VirtualDesktopAccess": "VirtualDesktopAccess none",
        "#PhysicalDesktopAccess": "PhysicalDesktopAccess none",
        "PhysicalDesktopAccess": "PhysicalDesktopAccess none",
        "#PhysicalDesktopAccessNoAcceptance": "PhysicalDesktopAccessNoAcceptance none",
        "PhysicalDesktopAccessNoAcceptance": "PhysicalDesktopAccessNoAcceptance none",
        "#LoginScreenAccess": "LoginScreenAccess 0",
        "LoginScreenAccess": "LoginScreenAccess 0",
        "#PhysicalDesktopMode": "LoginScreenAccess 0",
        "LoginScreenAccess": "LoginScreenAccess 0",
    }
    edit_config_raw_file(server_cfg_path, config_dict)

    # Configuring node.cfg default preferences
    config_dict = {
        "#EnableDiskSharing": "EnableDiskSharing none",
        "EnableDiskSharing": "EnableDiskSharing none",
        "#EnablePrinterSharing": "EnablePrinterSharing none",
        "EnablePrinterSharing": "EnablePrinterSharing none",
        "#EnableUSBSharing": "EnableUSBSharing none",
        "EnableUSBSharing": "EnableUSBSharing none",
        "#EnableNetworkSharing": "EnableNetworkSharing none",
        "EnableNetworkSharing": "EnableNetworkSharing none",
        "#EnableSmartcardSharing": "EnableSmartcardSharing 0",
        "EnableSmartcardSharing": "EnableSmartcardSharing 0",
        "#AudioInterface": "AudioInterface disabled",
        "AudioInterface": "AudioInterface disabled",
        "#DisplayMonitorIcon": "DisplayMonitorIcon 0",
        "DisplayMonitorIcon": "DisplayMonitorIcon 0",
    }
    edit_config_raw_file(node_cfg_path, config_dict)


# https://kb.nomachine.com/AR12K00767
def uninstall():
    killalltasks(ensure_list(control.impacted_process))

    remove_script_interactivity()

    uninstall_app("NoMachine")

    # We run the uninstallation script if it still exist
    if isfile(nxuninstall_script):
        run_notfatal(f"'{nxuninstall_script}'")
        remove_tree(library_nomachine, ignore_errors=True)


def remove_script_interactivity():
    if isfile(nxuninstall_script):
        run(f"sed -i '' '/^ *osascript /d' '{nxuninstall_script}'")

def edit_config_raw_file(conf_path, config_dict, base_file=None, encoding=None):
    r"""
    Edits a configuration file at the given path.
    This function allows you to edit INI files with incorrect format, flat files, dirty JSON, etc.

    Args:
        conf_path (str): The path to the configuration file.
        config_dict (dict): A dictionary containing key-value pairs to be updated or added in the configuration file.
            The key is the string at the beginning of the line you are trying to edit.
            The value is the new replacing line.
            (Note: take care of spaces and tabs (\t), but line return (\n) will be added automatically.)
        base_file (str or None, optional): The base file content to be used if the configuration file doesn't exist.
            It can be either a string representing the base content or a file path. Defaults to None.
        encoding (str, optional): The encoding of the configuration file. If not specified, the function attempts to detect it. Defaults to None.

    Returns:
        (dict or list): The dictionary with the previous line as the key and the new line as the value for edited lines. The list of written lines.

    Example:
    >>> edit_config_raw_file(user_conf_path, config_dict, encoding="UTF-8-SIG")
    {'Language=en-US\n': 'Language=fr-FR\n', 'Destinations=Picker\n': 'Destinations=Editor\n',
    'CaptureMousepointer=True\n': 'CaptureMousepointer=False\n'}
    >>> edit_config_raw_file(server_cfg_path, config_dict))
    ['UpdateFrequency 0\n']

    """
    result_dict = {}
    new_lines = []

    if not encoding and os.path.isfile(conf_path):
        encoding = detect_file_encoding(conf_path)
    else:
        encoding = "UTF-8"

    if not os.path.isfile(conf_path):
        if base_file is None:
            print(f'"{conf_path}" file does not exist, and you did not provide a base_file. Writing values of config_dict line by line.')
            new_lines = set()
            for key, value in config_dict.items():
                new_line = value + "\n"
                new_lines.add(new_line)
            new_lines = list(new_lines)
        else:
            if isfile(base_file):
                # encoding = detect_file_encoding(base_file)
                with open(conf_path, "r", encoding=encoding) as f:
                    new_lines = f.readlines()
            else:
                new_lines = base_file.splitlines()
    else:
        with open(conf_path, "r", encoding=encoding) as f:
            for line in f:
                line_edited = False
                old_line = line
                line = line.rstrip("\n")
                for key, value in config_dict.items():
                    if line.startswith(key):
                        line = value
                        line_edited = True
                        break
                new_line = line + "\n"
                new_lines.append(new_line)
            if line_edited:
                result_dict[old_line] = new_line

    with open(conf_path, "w", encoding=encoding) as f:
        f.writelines(new_lines)

    if result_dict:
        return result_dict
    else:
        return new_lines


def detect_file_encoding(file_path):
    """Detect the encoding of a file."""
    import chardet

    with open(file_path, "rb") as file:
        raw_data = file.read()
        result = chardet.detect(raw_data)
        return result["encoding"]
