#
# Licensed under the GNU General Public License Version 3
#
# This program 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
# (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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright 2013 Aron Parsons <aronparsons@gmail.com>
#

# NOTE: the 'self' variable is an instance of SpacewalkShell

# wildcard import
# pylint: disable=W0401,W0614

# unused argument
# pylint: disable=W0613

# invalid function name
# pylint: disable=C0103

import os
import re
import shlex
try:
    from xmlrpc import client as xmlrpclib
except ImportError:
    import xmlrpclib
from spacecmd.utils import *


def help_group_addsystems(self):
    print('group_addsystems: Add systems to a group')
    print('usage: group_addsystems GROUP <SYSTEMS>')
    print('       group_addsystems GROUP <ssm>')
    print('')
    print(self.HELP_SYSTEM_OPTS)


def complete_group_addsystems(self, text, line, beg, end):
    parts = shlex.split(line)
    if line[-1] == ' ':
        parts.append('')

    if len(parts) == 2:
        return tab_completer(self.do_group_list('', True), text)
    elif len(parts) > 2:
        return self.tab_complete_systems(parts[-1])


def do_group_addsystems(self, args):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if not args:
        self.help_group_addsystems()
        return 1

    group_name = args.pop(0)

    # use the systems listed in the SSM
    if re.match('ssm', args[0], re.I):
        systems = self.ssm.keys()
    else:
        systems = self.expand_systems(args)

    system_ids = []
    for system in sorted(systems):
        system_id = self.get_system_id(system)
        if not system_id:
            continue
        system_ids.append(system_id)

    if system_ids:
        self.client.systemgroup.addOrRemoveSystems(self.session, group_name,
                                                   system_ids, True)
        return 0
    else:
        return 1

####################


def help_group_removesystems(self):
    print('group_removesystems: Remove systems from a group')
    print('usage: group_removesystems GROUP <SYSTEMS>')
    print('')
    print(self.HELP_SYSTEM_OPTS)


def complete_group_removesystems(self, text, line, beg, end):
    parts = shlex.split(line)
    if line[-1] == ' ':
        parts.append('')

    if len(parts) == 2:
        return tab_completer(self.do_group_list('', True), text)
    elif len(parts) > 2:
        return self.tab_complete_systems(parts[-1])


def do_group_removesystems(self, args):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if not args:
        self.help_group_removesystems()
        return 1

    group_name = args.pop(0)

    # use the systems listed in the SSM
    if re.match('ssm', args[0], re.I):
        systems = self.ssm.keys()
    else:
        systems = self.expand_systems(args)

    system_ids = []
    for system in sorted(systems):
        system_id = self.get_system_id(system)
        if not system_id:
            continue
        system_ids.append(system_id)

    if system_ids:
        print('Systems')
        print('-------')
        print('\n'.join(sorted(systems)))

        if not self.user_confirm('Remove these systems [y/N]:'):
            return

        self.client.systemgroup.addOrRemoveSystems(self.session,
                                                   group_name,
                                                   system_ids,
                                                   False)
        return 0
    else:
        print("No systems found")
        return 1

####################


def help_group_create(self):
    print('group_create: Create a system group')
    print('usage: group_create [NAME] [DESCRIPTION]')


def do_group_create(self, args):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if args:
        name = args[0]
    else:
        name = prompt_user('Name:')

    if len(args) > 1:
        description = ' '.join(args[1:])
    else:
        description = prompt_user('Description:')

    self.client.systemgroup.create(self.session, name, description)

    return 0

####################


def help_group_delete(self):
    print('group_delete: Delete a system group')
    print('usage: group_delete NAME ...')


def complete_group_delete(self, text, line, beg, end):
    return tab_completer(self.do_group_list('', True), text)


def do_group_delete(self, args):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if not args:
        self.help_group_delete()
        return 1

    groups = args

    self.do_group_details('', True)
    if not self.user_confirm('Delete these groups [y/N]:'):
        return 1

    for group in groups:
        self.client.systemgroup.delete(self.session, group)

    return 0

####################


def help_group_backup(self):
    print('group_backup: backup a system group')
    print('''usage: group_backup <NAME> [OUTDIR])
                    group_backup ALL

"OUTDIR" defaults to $HOME/spacecmd-backup/group/YYYY-MM-DD/NAME
"ALL" is a keyword and collects all groups
''')


def complete_group_backup(self, text, line, beg, end):
    List = self.do_group_list('', True)
    List.append('ALL')
    return tab_completer(List, text)


def do_group_backup(self, args):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if not args:
        self.help_group_backup()
        return 1

    groups = args
    if len(args) and args[0] == 'ALL':
        groups = self.do_group_list('', True)

    # use an output base from the user if it was passed
    if len(args) > 1:
        outputpath_base = datetime.now().strftime(os.path.expanduser(args[1]))
    else:
        outputpath_base = os.path.expanduser('~/spacecmd-backup/group')

        # make the final output path be <base>/date
        outputpath_base = os.path.join(outputpath_base,
                                       datetime.now().strftime("%Y-%m-%d"))

    try:
        if not os.path.isdir(outputpath_base):
            os.makedirs(outputpath_base)
    except OSError:
        logging.error('Could not create output directory: %s', outputpath_base)
        return 1

    for group in groups:
        print("Backup Group: %s" % group)
        details = self.client.systemgroup.getDetails(self.session, group)
        outputpath = outputpath_base + "/" + group
        print("Output File: %s" % outputpath)
        fh = open(outputpath, 'w')
        fh.write(details['description'])
        fh.close()

    return 0

####################


def help_group_restore(self):
    print('group_restore: restore a system group')
    print('''
usage: group_restore INPUTDIR [NAME] ...
       group_restore INPUTDIR ALL
       group_restore INPUTDIR
       group_restore .

Specifying only INPUTDIR will default to ALL groups.
Setting dot (.) instead of full INPUTDIR will imply current directory.
    ''')


def complete_group_restore(self, text, line, beg, end):
    parts = shlex.split(line)

    if len(parts) > 1:
        groups = self.do_group_list('', True)
        groups.append('ALL')
        return tab_completer(groups, text)


def do_group_restore(self, args):
    args, options = parse_command_arguments(args, get_argument_parser())

    files = {}
    current = {}

    if args:
        inputdir = os.getcwd() if args[0] == "." else args[0]
        groups = args[1:] or ["ALL"]
    else:
        self.help_group_restore()
        return 1

    inputdir = os.path.abspath(inputdir)
    logging.debug("Input Directory: %s" % (inputdir))

    # make a list of file items in the input dir
    if os.path.isdir(inputdir):
        d_content = os.listdir(inputdir)
        for d_item in d_content:
            if os.path.isfile(inputdir + "/" + d_item):
                logging.debug("Found file %s" % inputdir + "/" + d_item)
                files[d_item] = inputdir + "/" + d_item
    else:
        logging.error("Restore dir %s does not exits or is not a directory" % inputdir)
        return 1

    if not files:
        logging.error("Restore dir %s has no restore items" % inputdir)
        return 1

    missing_groups = 0
    if groups and next(iter(groups)) != 'ALL':
        for group in groups:
            if group not in files:
                logging.error("Group %s was not found in backup" % (group))
                missing_groups += 1
    if missing_groups:
        logging.error("Found %s missing groups, terminating", missing_groups)
        return 1

    for groupname in self.do_group_list('', True):
        details = self.client.systemgroup.getDetails(self.session, groupname)
        current[groupname] = details['description']
        current[groupname] = current[groupname].rstrip('\n')

    for groupname in files:
        fh = open(files[groupname], 'r')
        details = fh.read()
        fh.close()
        details = details.rstrip('\n')

        if groupname in current and current[groupname] == details:
            logging.error("Group %s already restored" % groupname)
            continue

        elif groupname in current:
            logging.debug("Already have %s but the description has changed" % groupname)

            if is_interactive(options):
                print("Changing description from:")
                print("\n\"%s\"\nto\n\"%s\"\n" % (current[groupname], details))
                userinput = prompt_user('Continue [y/N]:')

                if re.match('y', userinput, re.I):
                    logging.info("Updating description for group: %s" % groupname)
                    self.client.systemgroup.update(self.session, groupname, details)
            else:
                logging.info("Updating description for group: %s" % groupname)
                self.client.systemgroup.update(self.session, groupname, details)
        else:
            logging.info("Creating new group %s" % groupname)
            self.client.systemgroup.create(self.session, groupname, details)

    return 0

####################


def help_group_list(self):
    print('group_list: List available system groups')
    print('usage: group_list')


def do_group_list(self, args, doreturn=False):
    groups = self.client.systemgroup.listAllGroups(self.session)
    groups = [g.get('name') for g in groups]

    if doreturn:
        return groups
    else:
        if groups:
            print('\n'.join(sorted(groups)))

####################


def help_group_listsystems(self):
    print('group_listsystems: List the members of a group')
    print('usage: group_listsystems GROUP')


def complete_group_listsystems(self, text, line, beg, end):
    return tab_completer(self.do_group_list('', True), text)


def do_group_listsystems(self, args, doreturn=False):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if len(args) != 1:
        self.help_group_listsystems()
        return

    group = args[0]

    try:
        systems = self.client.systemgroup.listSystems(self.session, group)
        systems = [s.get('profile_name') for s in systems]
    except xmlrpclib.Fault:
        logging.warning('%s is not a valid group' % group)
        return []

    if doreturn:
        return systems
    else:
        if systems:
            print('\n'.join(sorted(systems)))

####################


def help_group_details(self):
    print('group_details: Show the details of a system group')
    print('usage: group_details GROUP ...')


def complete_group_details(self, text, line, beg, end):
    return tab_completer(self.do_group_list('', True), text)


def do_group_details(self, args, short=False):
    arg_parser = get_argument_parser()

    (args, _options) = parse_command_arguments(args, arg_parser)

    if not args:
        self.help_group_details()
        return 1

    add_separator = False

    for group in args:
        try:
            details = self.client.systemgroup.getDetails(self.session, group)
            systems = [stm.get('profile_name') for stm in self.client.systemgroup.listSystems(self.session, group)]
        except xmlrpclib.Fault:
            logging.warning('The group "%s" is invalid' % group)
            return 1

        if add_separator:
            print(self.SEPARATOR)
        add_separator = True

        print('ID:                %i' % details.get('id'))
        print('Name:              %s' % details.get('name'))
        print('Description:       %s' % details.get('description'))
        print('Number of Systems: %i' % details.get('system_count'))

        if not short:
            print('')
            print('Members')
            print('-------')
            print('\n'.join(sorted(systems)))

    return 0
