#    Copyright 2013 - 2016 Mirantis, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from __future__ import print_function

import argparse
import os
import sys
import yaml

from reclass_tools import walk_models


def execute(params):

    results = walk_models.get_all_reclass_params(
        params.paths,
        verbose=params.verbose)

    print(yaml.dump(results))


def dump_params(args=None):
    if args is None:
        args = sys.argv[1:]

    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawTextHelpFormatter,
        description="")
    parser.add_argument('--verbose', dest='verbose', action='store_const', const=True,
                        help='Show verbosed output.', default=False)
    parser.add_argument('paths', help='Paths to search for *.yml files.', nargs='+')

    if len(args) == 0:
        args = ['-h']

    params = parser.parse_args(args)
    results = walk_models.get_all_reclass_params(
        params.paths,
        verbose=params.verbose)

    print(yaml.dump(results))


def show_key(args=None):
    remove_key(args=args, pretend=True)


def remove_key(args=None, pretend=False):
    if args is None:
        args = sys.argv[1:]

    key_parser = argparse.ArgumentParser(add_help=False)
    if pretend:
        key_parser_help = (
            'Key name to find in reclass model files, for example:'
            ' reclass-show-key parameters.linux.network.interface'
            ' /path/to/model/')
    else:
        key_parser_help = (
            'Key name to remove from reclass model files, for example:'
            ' reclass-remove-key parameters.linux.network.interface'
            ' /path/to/model/')
    key_parser.add_argument('key_name', help=key_parser_help)

    parser = argparse.ArgumentParser(parents=[key_parser],
        formatter_class=argparse.RawTextHelpFormatter,
        description="")
    parser.add_argument('--verbose', dest='verbose', action='store_const', const=True,
                        help='Show verbosed output.', default=False)
    parser.add_argument('paths', help='Paths to search for *.yml files.', nargs='+')

    if len(args) == 0:
        args = ['-h']

    params = parser.parse_args(args)
    results = walk_models.remove_reclass_parameter(
        params.paths,
        params.key_name,
        verbose=params.verbose,
        pretend=pretend)


def inventory_list(args=None):
    try:
        from reclass_tools import reclass_models
    except ImportError:
        print("Please run this tool on the salt-master node with installed 'reclass'")
        return

    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
                                     description="")
    parser.add_argument('--domain', '-d', dest='domain',
                        help=('Show only the nodes which names are ended with the specified domain, for example:'
                              ' reclass-inventory-list -d example.local'))


    params = parser.parse_args(args)

    inventory = reclass_models.inventory_list(domain=params.domain)

    print('\n'.join(sorted(inventory.keys())))

def vcp_list(args=None):
    try:
        from reclass_tools import reclass_models
    except ImportError:
        print("Please run this tool on the salt-master node with installed 'reclass'")
        return

    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
                                     description="")
    parser.add_argument('--domain', '-d', dest='domain',
                        help=('Show only the nodes which names are ended with the specified domain, for example:'
                              ' reclass-inventory-list -d example.local'))

    params = parser.parse_args(args)

    vcp_node_names = reclass_models.vcp_list(domain=params.domain)
    #print('\n'.join(sorted(vcp_node_names)))
    print('\n'.join(sorted(('{0}.{1}'.format(name, domain) for name, domain in vcp_node_names))))


def create_inventory_context(args=None):
    try:
        from reclass_tools import create_inventory
    except ImportError:
        print("Please run this tool on the salt-master node with installed 'reclass'")
        return

    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
                                     description="Dumps nodes and specified node parameters from reclass, for example: create_inventory_context -d example.local parameters.linux.network.interface parameters.linux.storage")
    parser.add_argument('--domain', '-d', dest='domain',
                        help=('Show only the nodes which names are ended with the specified domain, for example:'
                              ' reclass-inventory-list -d example.local'))
    parser.add_argument('keys', help=(
        'Reclass key names to dump with nodes'), nargs='*')

    params = parser.parse_args(args)

    current_underlay_context = create_inventory.create_inventory_context(domain=params.domain, keys=params.keys)

    print(yaml.dump(current_underlay_context, default_flow_style=False))


def render_dir(args=None):
    try:
        from reclass_tools import create_inventory
    except ImportError:
        print("Please run this tool on the salt-master node with installed 'reclass'")
        return

    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
                                     description="Render a coockiecutter-based template directory using several different context files")
    parser.add_argument('--template-dir', '-t', dest='template_dir',
                        help=('Coockiecutter-based template directory'))
    parser.add_argument('--output-dir', '-o', dest='output_dir',
                        help=('Path to the directory where the rendered template will be placed'))
    parser.add_argument('--context', '-c', dest='contexts',
                        help=('Path to the directory where the rendered template will be placed'),
                        nargs='+')

    params = parser.parse_args(args)

    create_inventory.render_dir(template_dir=params.template_dir, output_dir=params.output_dir, contexts=params.contexts)


