# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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.

import logging
from awscli.customizations.commands import BasicCommand
from awscli.customizations.emr import config
from awscli.customizations.emr import configutils
from awscli.customizations.emr import emrutils
from awscli.customizations.emr import exceptions

LOG = logging.getLogger(__name__)


class Command(BasicCommand):
    region = None

    UNSUPPORTED_COMMANDS_FOR_RELEASE_BASED_CLUSTERS = set([
        'install-applications',
        'restore-from-hbase-backup',
        'schedule-hbase-backup',
        'create-hbase-backup',
        'disable-hbase-backups',
    ])

    def supports_arg(self, name):
        return any((x['name'] == name for x in self.ARG_TABLE))

    def _run_main(self, parsed_args, parsed_globals):

        self._apply_configs(parsed_args,
                            configutils.get_configs(self._session))
        self.region = emrutils.get_region(self._session, parsed_globals)
        self._validate_unsupported_commands_for_release_based_clusters(
            parsed_args, parsed_globals)
        return self._run_main_command(parsed_args, parsed_globals)

    def _apply_configs(self, parsed_args, parsed_configs):
        applicable_configurations = \
            self._get_applicable_configurations(parsed_args, parsed_configs)

        configs_added = {}
        for configuration in applicable_configurations:
            configuration.add(self, parsed_args,
                              parsed_configs[configuration.name])
            configs_added[configuration.name] = \
                parsed_configs[configuration.name]

        if configs_added:
            LOG.debug("Updated arguments with configs: %s" % configs_added)
        else:
            LOG.debug("No configs applied")
        LOG.debug("Running command with args: %s" % parsed_args)

    def _get_applicable_configurations(self, parsed_args, parsed_configs):
        # We need to find the applicable configurations by applying
        # following filters:
        # 1. Configurations that are applicable to this command
        # 3. Configurations that are present in parsed_configs
        # 2. Configurations that are not present in parsed_args

        configurations = \
            config.get_applicable_configurations(self)

        configurations = [x for x in configurations
                          if x.name in parsed_configs and
                          not x.is_present(parsed_args)]

        configurations = self._filter_configurations_in_special_cases(
            configurations, parsed_args, parsed_configs)

        return configurations

    def _filter_configurations_in_special_cases(self, configurations,
                                                parsed_args, parsed_configs):
        # Subclasses can override this method to filter the applicable
        # configurations further based upon some custom logic
        # Default behavior is to return the configurations list as is
        return configurations

    def _run_main_command(self, parsed_args, parsed_globals):
        # Subclasses should implement this method.
        # parsed_globals are the parsed global args (things like region,
        # profile, output, etc.)
        # parsed_args are any arguments you've defined in your ARG_TABLE
        # that are parsed.
        # parsed_args are updated to include any emr specific configuration
        # from the config file if the corresponding argument is not
        # explicitly specified on the CLI
        raise NotImplementedError("_run_main_command")

    def _validate_unsupported_commands_for_release_based_clusters(
            self, parsed_args, parsed_globals):
        command = self.NAME

        if (command in self.UNSUPPORTED_COMMANDS_FOR_RELEASE_BASED_CLUSTERS and
                hasattr(parsed_args, 'cluster_id')):
            release_label = emrutils.get_release_label(
                parsed_args.cluster_id, self._session, self.region,
                parsed_globals.endpoint_url, parsed_globals.verify_ssl)
            if release_label:
                raise exceptions.UnsupportedCommandWithReleaseError(
                    command=command,
                    release_label=release_label)


def override_args_required_option(argument_table, args, session, **kwargs):
    # This function overrides the 'required' property of an argument
    # if a value corresponding to that argument is present in the config
    # file
    # We don't want to override when user is viewing the help so that we
    # can show the required options correctly in the help
    need_to_override = False if len(args) == 1 and args[0] == 'help' \
        else True

    if need_to_override:
        parsed_configs = configutils.get_configs(session)
        for arg_name in argument_table.keys():
            if arg_name.replace('-', '_') in parsed_configs:
                argument_table[arg_name].required = False
