#!/usr/bin/python3
#
# This file is part of FreedomBox.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
"""
Configuration helper for BitTorrent web client.
"""

import argparse
import json
import os
import shutil
import subprocess
import time

import augeas
from plinth import action_utils

try:
    from deluge import config
except ImportError:
    # deluge is not installed or is python2 version
    config = None

DELUGED_DEFAULT_FILE = '/etc/default/deluged'
DELUGE_CONF_DIR = '/var/lib/deluged/.config/deluge/'

DELUGE_WEB_SYSTEMD_SERVICE_PATH = '/etc/systemd/system/deluge-web.service'
DELUGE_WEB_SYSTEMD_SERVICE = '''
#
# This file is managed and overwritten by Plinth.  If you wish to edit
# it, disable Deluge in Plinth, remove this file and manage it manually.
#
[Unit]
Description=Deluge Web Interface
Documentation=man:deluge-web(1)
After=network.target

[Service]
ExecStart=bash -c "/usr/bin/deluge-web --base=deluge $(/usr/bin/deluge-web --version | grep deluge-web | cut -f2 -d' ' | grep -q '^1.' && echo '' || echo '--do-not-daemonize')"
Restart=on-failure
User=debian-deluged
Group=debian-deluged
LockPersonality=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictRealtime=yes
StateDirectory=deluged
SystemCallArchitectures=native

[Install]
WantedBy=multi-user.target
'''  # noqa: E501


def parse_arguments():
    """Return parsed command line arguments as dictionary."""
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')

    subparsers.add_parser('setup', help='Setup deluge')

    subparsers.add_parser('get-configuration',
                          help='Return the current configuration')

    subparser = subparsers.add_parser('set-configuration',
                                      help='Set the configuration parameter')
    subparser.add_argument('parameter',
                           help='Name of the configuration parameter')
    subparser.add_argument('value',
                           help='Value of the configuration parameter')

    subparsers.required = True
    return parser.parse_args()


def _set_configuration(filename, parameter, value):
    """Set the configuration parameter."""
    deluged_is_running = action_utils.service_is_running('deluged')
    if deluged_is_running:
        action_utils.service_stop('deluged')
    deluge_web_is_running = action_utils.service_is_running('deluge-web')
    if deluge_web_is_running:
        action_utils.service_stop('deluge-web')

    filepath = os.path.join(DELUGE_CONF_DIR, filename)
    if config is None:
        script = 'from deluge import config;\
            conf = config.Config(filename="{0}");\
            conf["{1}"] = "{2}";\
            conf.save()'.format(filepath, parameter, value)
        subprocess.check_call(['python2', '-c', script])
    else:
        conf = config.Config(filename=filepath)
        conf[parameter] = value
        conf.save()
    shutil.chown(filepath, 'debian-deluged', 'debian-deluged')

    if deluged_is_running:
        action_utils.service_start('deluged')
    if deluge_web_is_running:
        action_utils.service_start('deluge-web')


def _get_host_id():
    """Get default host id."""
    if config is None:
        hosts_conf_file = os.path.join(DELUGE_CONF_DIR, 'hostlist.conf.1.2')
        script = 'from deluge import config;\
            conf = config.Config(filename="{0}");\
            print(conf["hosts"][0][0])'.format(hosts_conf_file)
        output = subprocess.check_output(['python2', '-c', script]).decode()
        return output.strip()
    else:
        hosts_conf_file = os.path.join(DELUGE_CONF_DIR, 'hostlist.conf')
        conf = config.Config(filename=hosts_conf_file)
        return conf["hosts"][0][0]


def _set_deluged_daemon_options():
    """Set deluged daemon options."""
    aug = augeas.Augeas(
        flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD)
    aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
    aug.set('/augeas/load/Shellvars/incl[last() + 1]', DELUGED_DEFAULT_FILE)
    aug.load()
    aug.set('/files' + DELUGED_DEFAULT_FILE + '/ENABLE_DELUGED', '1')
    # overwrite daemon args, use default config directory (same as deluge-web)
    aug.set('/files' + DELUGED_DEFAULT_FILE + '/DAEMON_ARGS',
            '"-d -l /var/log/deluged/daemon.log -L info"')
    aug.save()


def subcommand_get_configuration(_):
    """Return the current deluged configuration in JSON format."""
    deluged_conf_file = os.path.join(DELUGE_CONF_DIR, 'core.conf')
    if config is None:
        script = 'from deluge import config;\
            conf = config.Config(filename="{0}");\
            print(conf["download_location"])'.format(deluged_conf_file)
        output = subprocess.check_output(['python2', '-c', script]).decode()
        download_location = output.strip()
    else:
        conf = config.Config(filename=deluged_conf_file)
        download_location = conf["download_location"]

    print(json.dumps({'download_location': download_location}))


def subcommand_set_configuration(arguments):
    """Set the deluged configuration."""
    if arguments.parameter != 'download_location':
        return
    _set_configuration('core.conf', arguments.parameter, arguments.value)


def subcommand_setup(_):
    """Perform initial setup for deluge."""

    with open(DELUGE_WEB_SYSTEMD_SERVICE_PATH, 'w') as file_handle:
        file_handle.write(DELUGE_WEB_SYSTEMD_SERVICE)

    _set_deluged_daemon_options()

    subprocess.check_call(['systemctl', 'daemon-reload'])
    # restarting deluge-web service stops also possible deluged process
    # that was started from the web interface
    action_utils.service_restart('deluge-web')
    action_utils.service_restart('deluged')
    # wait processes to start
    time.sleep(10)

    # configure deluge-web to autoconnect to the default deluged daemon, also
    # restarts deluged and deluge-web services again to create config files
    host_id = _get_host_id()
    _set_configuration('web.conf', 'default_daemon', host_id)


def main():
    """Parse arguments and perform all duties."""
    arguments = parse_arguments()

    subcommand = arguments.subcommand.replace('-', '_')
    subcommand_method = globals()['subcommand_' + subcommand]
    subcommand_method(arguments)


if __name__ == '__main__':
    main()
