# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
"""
BuddyNS DNS Driver
"""

import sys

try:
    import simplejson as json
except ImportError:
    import json

from libcloud.dns.types import Provider, ZoneDoesNotExistError,\
    ZoneAlreadyExistsError
from libcloud.dns.base import DNSDriver, Zone
from libcloud.common.buddyns import BuddyNSConnection, BuddyNSResponse,\
    BuddyNSException

__all__ = [
    'BuddyNSDNSDriver'
]


class BuddyNSDNSResponse(BuddyNSResponse):
    pass


class BuddyNSDNSConnection(BuddyNSConnection):
    responseCls = BuddyNSDNSResponse


class BuddyNSDNSDriver(DNSDriver):
    name = 'BuddyNS DNS'
    website = 'https://www.buddyns.com'
    type = Provider.BUDDYNS
    connectionCls = BuddyNSDNSConnection

    def list_zones(self):
        action = '/api/v2/zone/'
        response = self.connection.request(action=action, method='GET')
        zones = self._to_zones(items=response.parse_body())

        return zones

    def get_zone(self, zone_id):
        """
        :param zone_id: Zone domain name (e.g. example.com)
        :return: :class:`Zone`
        """
        action = '/api/v2/zone/%s' % zone_id
        try:
            response = self.connection.request(action=action, method='GET')
        except BuddyNSException:
            e = sys.exc_info()[1]
            if e.message == 'Not found':
                raise ZoneDoesNotExistError(value=e.message, driver=self,
                                            zone_id=zone_id)
            else:
                raise e
        zone = self._to_zone(response.parse_body())

        return zone

    def create_zone(self, domain, type='master', ttl=None, extra=None):
        """
        :param domain: Zone domain name (e.g. example.com)
        :type domain: ``str``

        :param type: Zone type (This is not really used. See API docs for extra
          parameters)
        :type type: ``str``

        :param ttl: TTL for new records (This is used through the extra param)
        :type ttl: ``int``

        :param extra: Extra attributes that are specific to the driver
        such as ttl.
        :type extra: ``dict``

        :rtype: :class:`Zone`
        Do not forget to pass the master in extra,
        extra = {'master':'65.55.37.62'} for example.
        """
        action = '/api/v2/zone/'
        data = {'name': domain}
        if extra is not None:
            data.update(extra)
        post_data = json.dumps(data)
        try:
            response = self.connection.request(action=action, method='POST',
                                               data=post_data)
        except BuddyNSException:
            e = sys.exc_info()[1]
            if e.message == 'Invalid zone submitted for addition.':
                raise ZoneAlreadyExistsError(value=e.message, driver=self,
                                             zone_id=domain)
            else:
                raise e

        zone = self._to_zone(response.parse_body())

        return zone

    def delete_zone(self, zone):
        """
        :param zone: Zone to be deleted.
        :type zone: :class:`Zone`

        :return: Boolean
        """
        action = '/api/v2/zone/%s' % zone.domain
        try:
            self.connection.request(action=action, method='DELETE')
        except BuddyNSException:
            e = sys.exc_info()[1]
            if e.message == 'Not found':
                raise ZoneDoesNotExistError(value=e.message, driver=self,
                                            zone_id=zone.id)
            else:
                raise e

        return True

    def _to_zone(self, item):
        common_keys = ['name', ]
        extra = {}
        for key in item:
            if key not in common_keys:
                extra[key] = item.get(key)
        zone = Zone(domain=item['name'], id=item['name'], type=None,
                    extra=extra, ttl=None, driver=self)

        return zone

    def _to_zones(self, items):
        zones = []
        for item in items:
            zones.append(self._to_zone(item))

        return zones
