#!/usr/bin/python3
#
# This file is part of OpenMediaVault.
#
# @license   http://www.gnu.org/licenses/gpl.html GPL Version 3
# @author    Volker Theile <volker.theile@openmediavault.org>
# @copyright Copyright (c) 2009-2017 Volker Theile
#
# OpenMediaVault is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# OpenMediaVault 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with OpenMediaVault. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
from typing import List

import click
import natsort
import openmediavault.procutils
import openmediavault.settings

import openmediavault


def grep_env_vars() -> List[str]:
    result = set()
    # Grep the environment variables used in Salt states.
    output = openmediavault.procutils.check_output(
        ['grep', '--no-filename', '--recursive', 'default:OMV_',
            openmediavault.getenv('OMV_SALT_DIR', '/srv/salt/omv')]
    )
    for line in output.splitlines():
        m = re.match(r".+'default:(OMV_[\S_]+)'.+", line.decode())
        if not m:
            continue
        result.add(m.group(1))
    # Grep environment variables used in various shell scripts.
    paths = [
        '/etc/cron.daily',
        '/etc/cron.weekly',
        '/etc/cron.monthly',
        '/usr/sbin/omv-btrfs-scrub',
        '/usr/sbin/omv-mkraid',
        '/usr/sbin/omv-sysinfo'
    ]
    output = openmediavault.procutils.check_output(
        ['grep', '--no-filename', '--recursive', 'OMV_.*=${OMV_', *paths]
    )
    for line in output.splitlines():
        m = re.match(r"^(OMV_[\S_]+)=.+$", line.decode())
        if not m:
            continue
        result.add(m.group(1))
    return natsort.humansorted(result)


class Context:
    verbose: bool


pass_context = click.make_pass_decorator(Context, ensure=True)


@click.group()
@click.option('-v', '--verbose', is_flag=True, help='Shows verbose output.')
@pass_context
def cli(ctx, verbose: bool):
    ctx.verbose = verbose
    return 0


@cli.command(name='list', help='List all available environment variables.')
@pass_context
def list_cmd(ctx):  # noqa
    for env_var in grep_env_vars():
        print(env_var)
    sys.exit(0)


@cli.command(name='get', help='Get configured environment variables.')
@click.argument('names', nargs=-1)
@click.option(
    '--value-only',
    is_flag=True,
    help='Print only the value of the environment variable.'
)
@pass_context
def get_cmd(ctx, names: List[str], value_only: bool):  # noqa
    # Get all environment variables starting with 'OMV_'.
    env_vars = dict(filter(lambda item: item[0].startswith('OMV_'),
                           openmediavault.settings.Environment.as_dict().items()))
    # Check if we should display only given variables.
    if len(names) > 0:
        env_vars = dict(filter(lambda item: item[0] in names,
                               env_vars.items()))
        if len(env_vars) == 0:
            sys.exit(1)
    for key, value in natsort.humansorted(env_vars.items()):
        print(value if value_only else '{}={}'.format(key, value))
    sys.exit(0)


@cli.command(name='set', help='Set an environment variable.')
@click.argument('key', required=True)
@click.argument('value', required=True)
@pass_context
def set_cmd(ctx, key: str, value: str):  # noqa
    if not key.startswith('OMV_'):
        sys.stderr.write('Key must be prefixed with OMV_\n')
        sys.exit(1)
    environment = openmediavault.settings.Environment
    environment.load()
    environment.set(key, value)
    environment.save()
    sys.exit(0)


@cli.command(name='unset', help='Unset an environment variable.')
@click.argument('key', required=True)
@pass_context
def unset_cmd(ctx, key: str):  # noqa
    if not key.startswith('OMV_'):
        sys.stderr.write('Key must be prefixed with OMV_\n')
        sys.exit(1)
    environment = openmediavault.settings.Environment
    environment.load()
    environment.unset(key)
    environment.save()
    sys.exit(0)


def main():
    cli()


if __name__ == '__main__':
    sys.exit(main())
