# 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 botocore.compat import OrderedDict

from awscli.customizations.exceptions import ParamValidationError
from awscli.customizations.flatten import SEP, FlattenArguments

LOG = logging.getLogger(__name__)

DEFAULT_VALUE_TYPE_MAP = {
    'Int': int,
    'Double': float,
    'IntArray': int,
    'DoubleArray': float,
}


def index_hydrate(params, container, cli_type, key, value):
    """
    Hydrate an index-field option value to construct something like::

        {
            'index_field': {
                'DoubleOptions': {
                    'DefaultValue': 0.0
                }
            }
        }
    """
    if 'IndexField' not in params:
        params['IndexField'] = {}

    if 'IndexFieldType' not in params['IndexField']:
        raise ParamValidationError('You must pass the --type option.')

    # Find the type and transform it for the type options field name
    # E.g: int-array => IntArray
    _type = params['IndexField']['IndexFieldType']
    _type = ''.join([i.capitalize() for i in _type.split('-')])

    # ``index_field`` of type ``latlon`` is mapped to ``Latlon``.
    # However, it is defined as ``LatLon`` in the model so it needs to
    # be changed.
    if _type == 'Latlon':
        _type = 'LatLon'

    # Transform string value to the correct type?
    if key.split(SEP)[-1] == 'DefaultValue':
        value = DEFAULT_VALUE_TYPE_MAP.get(_type, lambda x: x)(value)

    # Set the proper options field
    if _type + 'Options' not in params['IndexField']:
        params['IndexField'][_type + 'Options'] = {}

    params['IndexField'][_type + 'Options'][key.split(SEP)[-1]] = value


FLATTEN_CONFIG = {
    "define-expression": {
        "expression": {
            "keep": False,
            "flatten": OrderedDict(
                [
                    # Order is crucial here!  We're
                    # flattening ExpressionValue to be "expression",
                    # but this is the name ("expression") of the our parent
                    # key, the top level nested param.
                    ("ExpressionName", {"name": "name"}),
                    ("ExpressionValue", {"name": "expression"}),
                ]
            ),
        }
    },
    "define-index-field": {
        "index-field": {
            "keep": False,
            # We use an ordered dict because `type` needs to be parsed before
            # any of the <X>Options values.
            "flatten": OrderedDict(
                [
                    ("IndexFieldName", {"name": "name"}),
                    ("IndexFieldType", {"name": "type"}),
                    (
                        "IntOptions.DefaultValue",
                        {
                            "name": "default-value",
                            "type": "string",
                            "hydrate": index_hydrate,
                        },
                    ),
                    (
                        "IntOptions.FacetEnabled",
                        {"name": "facet-enabled", "hydrate": index_hydrate},
                    ),
                    (
                        "IntOptions.SearchEnabled",
                        {"name": "search-enabled", "hydrate": index_hydrate},
                    ),
                    (
                        "IntOptions.ReturnEnabled",
                        {"name": "return-enabled", "hydrate": index_hydrate},
                    ),
                    (
                        "IntOptions.SortEnabled",
                        {"name": "sort-enabled", "hydrate": index_hydrate},
                    ),
                    (
                        "IntOptions.SourceField",
                        {
                            "name": "source-field",
                            "type": "string",
                            "hydrate": index_hydrate,
                        },
                    ),
                    (
                        "TextOptions.HighlightEnabled",
                        {
                            "name": "highlight-enabled",
                            "hydrate": index_hydrate,
                        },
                    ),
                    (
                        "TextOptions.AnalysisScheme",
                        {"name": "analysis-scheme", "hydrate": index_hydrate},
                    ),
                ]
            ),
        }
    },
}


def initialize(cli):
    """
    The entry point for CloudSearch customizations.
    """
    flattened = FlattenArguments('cloudsearch', FLATTEN_CONFIG)
    flattened.register(cli)
