#!/usr/bin/perl
use warnings;
use strict;
use IO::File;

die "$0: old-zone-info new-zone-info\n" unless @ARGV == 2;

sub extract_serial ($);
sub suggest_serial ($);

my $err = 0;
my ($oldzone, $newzone) = @ARGV;

my @difflines = `/usr/bin/diff -bu $oldzone $newzone`;
exit 0 if @difflines == 0;  # no differences
chomp @difflines;
shift @difflines; shift @difflines; # --- and +++

my $oldserial = extract_serial $oldzone;
my $newserial = extract_serial $newzone;

if ($oldserial > $newserial) {
	++$err;
	print "SOA serial old > new ($oldserial > $newserial)\n";
	print " (Force override if deliberately cycling)\n";
}

my @changes;
foreach (@difflines) {
	next unless /^[-+]/;
	next if /^[+-][#;]/;
	push @changes, $_;
}

if (@changes and $newserial le $oldserial) {
	print "There are substantive changes, yet new serial not higher\n";
	print "Serial: $newserial\n";
	print " $_\n" foreach @changes;
	print "Try: " . suggest_serial($oldserial) . "\n";
	++$err;
}
exit $err;

sub extract_serial ($)
{
	my $fn = shift;
	my $fh = new IO::File $fn, "r"
		or die "Failed to open '${fn}': $!\n";
	my @zlines = grep { /[^;]*SOA/ .. /[^;]*\)/ } $fh->getlines;
	$fh->close;

	chomp @zlines;
	map {s/;.*//} @zlines;
	my $soa = join(' ', @zlines);
	$soa =~ s/\s+/ /g;
	if ( $soa =~ m/\(\s+(\d+)\s+/ ) {
		return $1;
	} else {
		return undef;
	}
}

sub suggest_serial ($)
{
	use POSIX 'strftime';
	my $old = shift;
	my $base = strftime '%Y%m%d', gmtime;
	if ($old =~ s/^\Q$base\E//) {
		++$old;
		die "\n99 changes in one day!\n" if $old == 99;
		return $base . sprintf '%02d', $old;
	} else {
		return $base . '01';
	}

}
