# Copyright 2014
# The Cloudscaling Group, 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.

"""
APIRequest class
"""

from lxml import etree
from oslo_config import cfg
from oslo_log import log as logging
import six

from ec2api.api import cloud
from ec2api.api import ec2utils
from ec2api import exception
from ec2api.i18n import _

CONF = cfg.CONF
LOG = logging.getLogger(__name__)


def _underscore_to_camelcase(st):
    return ''.join([x[:1].upper() + x[1:] for x in st.split('_')])


def _database_to_isoformat(datetimeobj):
    """Return a xs:dateTime parsable string from datatime."""
    return datetimeobj.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + 'Z'


class APIRequest(object):

    def __init__(self, action, version, args):
        self.action = action
        self.version = version
        self.args = args
        if CONF.full_vpc_support:
            self.controller = cloud.VpcCloudController()
        else:
            self.controller = cloud.CloudController()

    def invoke(self, context):
        try:
            method = getattr(self.controller,
                             ec2utils.camelcase_to_underscore(self.action))
        except AttributeError:
            LOG.exception(_('Unsupported API request: action = %(action)s'),
                          {'action': self.action})
            raise exception.InvalidRequest()

        args = ec2utils.dict_from_dotted_str(self.args.items())

        def convert_dicts_to_lists(args):
            if not isinstance(args, dict):
                return args
            for key in args.keys():
                # NOTE(vish): Turn numeric dict keys into lists
                # NOTE(Alex): Turn "value"-only dict keys into values
                if isinstance(args[key], dict):
                    if args[key] == {}:
                        continue
                    first_subkey = next(six.iterkeys(args[key]))
                    if first_subkey.isdigit():
                        s = args[key]
                        args[key] = [convert_dicts_to_lists(s[k])
                                     for k in sorted(s)]
                    elif (first_subkey == 'value' and
                            len(args[key]) == 1):
                        args[key] = args[key]['value']
            return args

        args = convert_dicts_to_lists(args)
        result = method(context, **args)
        return self._render_response(result, context.request_id)

    def _render_response(self, response_data, request_id):
        response_el = ec2utils.dict_to_xml(
            {'return': 'true'} if response_data is True else response_data,
            self.action + 'Response')
        response_el.attrib['xmlns'] = ('http://ec2.amazonaws.com/doc/%s/'
                                       % self.version)
        request_id_el = etree.Element('requestId')
        request_id_el.text = request_id
        response_el.insert(0, request_id_el)

        response = etree.tostring(response_el, pretty_print=True)

        # Don't write private key to log
        if self.action != "CreateKeyPair":
            LOG.debug(response)
        else:
            LOG.debug("CreateKeyPair: Return Private Key")

        return response
