#HOSTS_CHARSET='utf-8'
HOSTS_INCLUDE="etc/hosts"

# absolute path!
ZONES_INCLUDE="$SRV/var/zones"

NAMED_CHECKZONE=/usr/sbin/named-checkzone
NAMED_SERVICE=bind9

## Generate forward zone from hosts hosts using pvl.hosts-forward
#
#   update_hosts_forward $out $src
function update_hosts_forward {
    local out="$1"
    local src="$2"
    local msg="$out: Generating forward hosts zone: $src"
    local include_cache=$(include_cache_path $src)
    local srcs=($(include_cache $include_cache))

    if apply_check "$out" ${srcs[@]:-}; then
        log_skip "$msg"
    else
        log_apply "$msg"
    
        apply_cmd "$out" $OPT/bin/pvl.hosts-forward \
            --hosts-include=$HOSTS_INCLUDE \
            --hosts-include-trace=$include_cache \
             "$src"
    fi
}

## Generate reverse zone from hosts hosts using pvl.hosts-reverse
#
#   update_hosts_reverse $out $src
function update_hosts_reverse {
    local out="$1"
    local src="$2"
    local msg="$out: Generating reverse hosts zone: $src"
    local include_cache=$(include_cache_path $src)
    local srcs=($(include_cache $include_cache))

    if apply_check "$out" ${srcs[@]:-}; then
        log_skip "$msg"
    else
        log_apply "$msg"
    
        apply_cmd "$out" $OPT/bin/pvl.hosts-reverse \
            --hosts-include="$HOSTS_INCLUDE" \
            --hosts-include-trace=$include_cache \
             "$src"
    fi
}

## Update zone $INCLUDE file
#
#   update_zone_include etc/zone/includes/$zone var/zone/includes/$zone
#
function update_zone_include {
    local out="$1"
    local src="$2"
    local msg="$out: Copy zone include: $src"

    if apply_check "$out" "${@:2}"; then
        log_skip "$msg"
    else
        log_apply "$msg"

        apply_cmd "$out" cat \
            "$src"
    fi
}

## Check if the given zone needs to be updated; update serial if so
#
#   check_zone_serial var/serials/$zone $serial $zone_deps...
#
# Supports UPDATE_SERIAL=
function check_zone_serial {
    local out="$1"
    local serial="$2"
    local srcs=(${@:3})

    local old=$(test -e "$out" && cat "$out" || echo '')
    
    # test
    if [ "$UPDATE_SERIAL" = 1 ]; then
        log_force "$out: Force serial $old <- $serial"

    elif apply_check "$out" ${srcs[@]:-}; then
        return 0

    elif [ "$UPDATE_SERIAL" = 0 ]; then
        log_noop "$out: Noop serial: $old <- $serial"
        
        return 0

    else
        log_apply "$out: Update serial: $old <- $serial"
    fi

    echo "$serial" > $out
        
    return 1
}

## Generate zone file from source using pvl.dns-process:
#
#   update_zone var/zones/$zone etc/zones/$zone var/serials/$zone
#
# Updates the SOA serial, and adjusts the $INCLUDE paths
function update_zone {
    local update_serial=

    local OPTIND
    while getopts 's:' opt; do case $opt in
        s)  update_serial=$OPTARG ;;
    esac done
    shift $(($OPTIND - 1))

    local out="$1"
    local src="$2"
    local serial="$3"
    local zone_serial=

    local msg="$out: Generate zone: $src"
    local include_cache=$(include_cache_path $src)
    local srcs=($(include_cache $include_cache))
    
    if check_zone_serial "$serial" $update_serial ${srcs[@]:-}; then
        zone_serial=$(cat $serial)

        log_skip "$out: Skip zone: $src @ $zone_serial <- $update_serial"

    else
        zone_serial=$(cat $serial)

        log_apply "$out: Generate zone: $src @ $zone_serial"
    
        apply_cmd "$out" $OPT/bin/pvl.dns-process \
                --serial=$zone_serial \
                --include-path=$ZONES_INCLUDE \
                --include-trace=$include_cache \
                "$src"
    fi
}

## Test zone file for validity using named-checkzone:
#
#   check_zone      ..../$zone $origin
function test_zone {
    local zone=$1
    local origin=$2

    log_check "$zone: Checking zone @$origin..." 

    # checkzone is very specific about the order of arguments, -q must be first
    test_cmd $zone \
        $NAMED_CHECKZONE $origin $zone
}

## Load update zonefiles into bind:
#
#   reload_zones    
function reload_zones {
    if [ "$UPDATE_RELOAD" = 1 ]; then
        log_force "Reload zones"
        
    elif [ "$UPDATE_RELOAD" = 0 ]; then
        log_noop "Skip reload zones"
        
        return
    
    elif ! service_status $NAMED_SERVICE; then
        log_skip "named not running; did not restart"

        return
 
    else
        log_apply "Reload zones"
    fi

    service_reload $NAMED_SERVICE
}
