# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
#    Author: Alin Balutoiu <abalutoiu@cloudbasesolutions.com>
#
#    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 oslo_config import cfg
from oslo_log import log as logging
from os_win import utilsfactory
from os_win import constants
from os_win import exceptions as os_win_exc

from designate.backend.agent_backend import base
from designate import exceptions

LOG = logging.getLogger(__name__)


class MSDNSBackend(base.AgentBackend):

    __plugin_name__ = 'msdns'
    __backend_status__ = 'experimental'

    def __init__(self, agent_service):
        """Configure the backend"""
        super(MSDNSBackend, self).__init__(agent_service)

        self._dnsutils = utilsfactory.get_dnsutils()

        masters = cfg.CONF['service:agent'].masters
        if not masters:
            raise exceptions.Backend("Missing agent AXFR masters")
        # Only ip addresses are needed
        self._masters = [ns.split(":")[0] for ns in masters]

        LOG.info("AXFR masters: %r", self._masters)

    def start(self):
        """Start the backend"""
        LOG.info("Started msdns backend")

    def find_zone_serial(self, zone_name):
        """Return the zone's serial"""
        zone_name = zone_name.rstrip(".")
        LOG.debug("Finding zone: %s", zone_name)
        try:
            return self._dnsutils.get_zone_serial(zone_name)
        except os_win_exc.DNSZoneNotFound:
            # Return None if the zone was not found
            return None

    def create_zone(self, zone):
        """Create a new DNS Zone"""
        zone_name = zone.origin.to_text(omit_final_dot=True)
        if isinstance(zone_name, bytes):
            zone_name = zone_name.decode('utf-8')
        LOG.debug("Creating zone: %s", zone_name)
        try:
            self._dnsutils.zone_create(
                zone_name=zone_name,
                zone_type=constants.DNS_ZONE_TYPE_SECONDARY,
                ds_integrated=False,
                ip_addrs=self._masters)
        except os_win_exc.DNSZoneAlreadyExists:
            # Zone already exists, check its properties to see if the
            # existing zone is identical to the requested one
            zone_properties = self._dnsutils.get_zone_properties(zone_name)

            identical_zone_exists = (
                zone_properties['zone_type'] == (
                    constants.DNS_ZONE_TYPE_SECONDARY) and
                zone_properties['ds_integrated'] is False and
                set(zone_properties['master_servers']) == set(self._masters))

            if not identical_zone_exists:
                raise

    def update_zone(self, zone):
        """Instruct MSDNS to request an AXFR from MiniDNS.
        """
        zone_name = zone.origin.to_text(omit_final_dot=True)
        if isinstance(zone_name, bytes):
            zone_name = zone_name.decode('utf-8')
        LOG.debug("Updating zone: %s", zone_name)
        self._dnsutils.zone_update(zone_name)

    def delete_zone(self, zone_name):
        """Delete a DNS Zone
        Do not raise exception if the zone does not exist.
        """
        LOG.debug('Deleting zone: %s' % zone_name)
        zone_name = zone_name.rstrip(".")
        self._dnsutils.zone_delete(zone_name)
