.. versionadded:: Fluorine

    Ensure a DNS zone exists.

    :param name:
        Name of the DNS zone (without a terminating dot).

    :param resource_group:
        The resource group assigned to the DNS zone.

    :param etag:
        The etag of the zone. `Etags <https://docs.microsoft.com/en-us/azure/dns/dns-zones-records#etags>`_ are used
        to handle concurrent changes to the same resource safely.

    :param if_match:
        The etag of the DNS zone. Omit this value to always overwrite the current zone. Specify the last-seen etag
        value to prevent accidentally overwritting any concurrent changes.

    :param if_none_match:
        Set to '*' to allow a new DNS zone to be created, but to prevent updating an existing zone. Other values will
        be ignored.

    :param registration_virtual_networks:
        A list of references to virtual networks that register hostnames in this DNS zone. This is only when zone_type
        is Private. (requires `azure-mgmt-dns <https://pypi.python.org/pypi/azure-mgmt-dns>`_ >= 2.0.0rc1)

    :param resolution_virtual_networks:
        A list of references to virtual networks that resolve records in this DNS zone. This is only when zone_type is
        Private. (requires `azure-mgmt-dns <https://pypi.python.org/pypi/azure-mgmt-dns>`_ >= 2.0.0rc1)

    :param tags:
        A dictionary of strings can be passed as tag metadata to the DNS zone object.

    :param zone_type:
        The type of this DNS zone (Public or Private). Possible values include: 'Public', 'Private'. Default value: 'Public'
         (requires `azure-mgmt-dns <https://pypi.python.org/pypi/azure-mgmt-dns>`_ >= 2.0.0rc1)

    :param connection_auth:
        A dict with subscription and authentication parameters to be used in connecting to the
        Azure Resource Manager API.

    Example usage:

    .. code-block:: yaml

        Ensure DNS zone exists:
            azurearm_dns.zone_present:
                - name: contoso.com
                - resource_group: my_rg
                - zone_type: Private
                - registration_virtual_networks:
                  - /subscriptions/{{ sub }}/resourceGroups/my_rg/providers/Microsoft.Network/virtualNetworks/test_vnet
                - tags:
                    how_awesome: very
                    contact_name: Elmer Fudd Gantry
                - connection_auth: {{ profile }}

def zone_present(name, resource_group, etag=None, if_match=None, if_none_match=None,
                 registration_virtual_networks=None, resolution_virtual_networks=None,
                 tags=None, zone_type='Public', connection_auth=None, **kwargs):
    '''
    .. versionadded:: Fluorine

    Ensure a DNS zone exists.

    :param name:
        Name of the DNS zone (without a terminating dot).

    :param resource_group:
        The resource group assigned to the DNS zone.

    :param etag:
        The etag of the zone. `Etags <https://docs.microsoft.com/en-us/azure/dns/dns-zones-records#etags>`_ are used
        to handle concurrent changes to the same resource safely.

    :param if_match:
        The etag of the DNS zone. Omit this value to always overwrite the current zone. Specify the last-seen etag
        value to prevent accidentally overwritting any concurrent changes.

    :param if_none_match:
        Set to '*' to allow a new DNS zone to be created, but to prevent updating an existing zone. Other values will
        be ignored.

    :param registration_virtual_networks:
        A list of references to virtual networks that register hostnames in this DNS zone. This is only when zone_type
        is Private. (requires `azure-mgmt-dns <https://pypi.python.org/pypi/azure-mgmt-dns>`_ >= 2.0.0rc1)

    :param resolution_virtual_networks:
        A list of references to virtual networks that resolve records in this DNS zone. This is only when zone_type is
        Private. (requires `azure-mgmt-dns <https://pypi.python.org/pypi/azure-mgmt-dns>`_ >= 2.0.0rc1)

    :param tags:
        A dictionary of strings can be passed as tag metadata to the DNS zone object.

    :param zone_type:
        The type of this DNS zone (Public or Private). Possible values include: 'Public', 'Private'. Default value: 'Public'
         (requires `azure-mgmt-dns <https://pypi.python.org/pypi/azure-mgmt-dns>`_ >= 2.0.0rc1)

    :param connection_auth:
        A dict with subscription and authentication parameters to be used in connecting to the
        Azure Resource Manager API.

    Example usage:

    .. code-block:: yaml

        Ensure DNS zone exists:
            azurearm_dns.zone_present:
                - name: contoso.com
                - resource_group: my_rg
                - zone_type: Private
                - registration_virtual_networks:
                  - /subscriptions/{{ sub }}/resourceGroups/my_rg/providers/Microsoft.Network/virtualNetworks/test_vnet
                - tags:
                    how_awesome: very
                    contact_name: Elmer Fudd Gantry
                - connection_auth: {{ profile }}

    '''
    ret = {
        'name': name,
        'result': False,
        'comment': '',
        'changes': {}
    }

    if not isinstance(connection_auth, dict):
        ret['comment'] = 'Connection information must be specified via connection_auth dictionary!'
        return ret

    zone = __salt__['azurearm_dns.zone_get'](name, resource_group, azurearm_log_level='info', **connection_auth)

    if 'error' not in zone:
        tag_changes = __utils__['dictdiffer.deep_diff'](zone.get('tags', {}), tags or {})
        if tag_changes:
            ret['changes']['tags'] = tag_changes

        # The zone_type parameter is only accessible in azure-mgmt-dns >=2.0.0rc1
        if zone.get('zone_type'):
            if zone.get('zone_type').lower() != zone_type.lower():
                ret['changes']['zone_type'] = {
                    'old': zone['zone_type'],
                    'new': zone_type
                }

            if zone_type.lower() == 'private':
                # The registration_virtual_networks parameter is only accessible in azure-mgmt-dns >=2.0.0rc1
                if registration_virtual_networks and not isinstance(registration_virtual_networks, list):
                    ret['comment'] = 'registration_virtual_networks must be supplied as a list of VNET ID paths!'
                    return ret
                reg_vnets = zone.get('registration_virtual_networks', [])
                remote_reg_vnets = sorted([vnet['id'].lower() for vnet in reg_vnets if 'id' in vnet])
                local_reg_vnets = sorted([vnet.lower() for vnet in registration_virtual_networks or []])
                if local_reg_vnets != remote_reg_vnets:
                    ret['changes']['registration_virtual_networks'] = {
                        'old': remote_reg_vnets,
                        'new': local_reg_vnets
                    }

                # The resolution_virtual_networks parameter is only accessible in azure-mgmt-dns >=2.0.0rc1
                if resolution_virtual_networks and not isinstance(resolution_virtual_networks, list):
                    ret['comment'] = 'resolution_virtual_networks must be supplied as a list of VNET ID paths!'
                    return ret
                res_vnets = zone.get('resolution_virtual_networks', [])
                remote_res_vnets = sorted([vnet['id'].lower() for vnet in res_vnets if 'id' in vnet])
                local_res_vnets = sorted([vnet.lower() for vnet in resolution_virtual_networks or []])
                if local_res_vnets != remote_res_vnets:
                    ret['changes']['resolution_virtual_networks'] = {
                        'old': remote_res_vnets,
                        'new': local_res_vnets
                    }

        if not ret['changes']:
            ret['result'] = True
            ret['comment'] = 'DNS zone {0} is already present.'.format(name)
            return ret

        if __opts__['test']:
            ret['result'] = None
            ret['comment'] = 'DNS zone {0} would be updated.'.format(name)
            return ret

    else:
        ret['changes'] = {
            'old': {},
            'new': {
                'name': name,
                'resource_group': resource_group,
                'etag': etag,
                'registration_virtual_networks': registration_virtual_networks,
                'resolution_virtual_networks': resolution_virtual_networks,
                'tags': tags,
                'zone_type': zone_type,
            }
        }

    if __opts__['test']:
        ret['comment'] = 'DNS zone {0} would be created.'.format(name)
        ret['result'] = None
        return ret

    zone_kwargs = kwargs.copy()
    zone_kwargs.update(connection_auth)

    zone = __salt__['azurearm_dns.zone_create_or_update'](
        name=name,
        resource_group=resource_group,
        etag=etag,
        if_match=if_match,
        if_none_match=if_none_match,
        registration_virtual_networks=registration_virtual_networks,
        resolution_virtual_networks=resolution_virtual_networks,
        tags=tags,
        zone_type=zone_type,
        **zone_kwargs
    )

    if 'error' not in zone:
        ret['result'] = True
        ret['comment'] = 'DNS zone {0} has been created.'.format(name)
        return ret

    ret['comment'] = 'Failed to create DNS zone {0}! ({1})'.format(name, zone.get('error'))
    return ret