package ZoneEntry;

use strict;

use Errors;

BEGIN {
    @Conf::Ids = (@Conf::Ids, '$Header: /afs/sipb/project/zoned/src/RCS/ZoneEntry.pm,v 1.4 2014/02/05 20:57:19 ingolia Exp $ ');
};

return 1;

sub new_master {
    my $proto = shift;
    my $class = ref($proto) || $proto;

    my $zone = shift;
    my $srcfile = shift;
    my $maintainer = shift;

    my $self = {zone => $zone,
		master => 1,
		srcfile => $srcfile,
		maintainer => $maintainer};

    bless($self, $class);

    return $self;
}

sub new_slave {
    my $proto = shift;
    my $class = ref($proto) || $proto;

    my $zone = shift;
    my $masters = shift;
    my $maintainer = shift;

    my $self = {zone => $zone,
		master => '',
		masters => $masters,
		maintainer => $maintainer};

    bless($self, $class);

    return $self;
}

sub new_from_line {    
    my $proto = shift;
    my $class = ref($proto) || $proto;

    my $line = shift;

    my $zone;
    my $src;
    my $maintainer;

    if (($zone, $src, $maintainer) 
	= ($line =~ /^([[:word:]\.-]+)\s+([[:word:]\.\/,-]+)\s+(\S+)\s*$/)) {    
    } else {
	die("Malformed zone line\n\t$_\nDid not match the zone entry line regular expression\n");
    }
    
    my $self;
    
# Master zones begin with a /, a fully qualified path to the srcfile
# Slave zones begin with a digit, an ip address of a master

    if ($src =~ /^\//) {
	$self = {zone => $zone,
		 master => 1,
		 srcfile => $src,
		 maintainer => $maintainer};
    } elsif ($src =~ /^\d/) {
	my @masters = split(/,/, $src);

	foreach my $master (@masters) {
	    if ($master !~ /\d+\.\d+\.\d+\.\d+/) {
		die("Malformed zone source\n\t$src\nMasters must be given in dotted-quat notation");
	    }
	}

	$self = {zone => $zone,
		 master => 0,
		 masters => [@masters],
		 maintainer => $maintainer};
    } else {
	die("Malformed zone source\n\t$src\nMust begin with / for master or an IP address for slave");
    }

    bless($self, $class);

    return $self;
}

sub zone {
    my $self = shift;

    return $self->{'zone'};
}

sub zonefile {
    my $self = shift;

    return "db." . join('.', reverse(split(/\./, $self->zone())));
}

sub is_master {
    my $self = shift;

    return $self->{'master'};
}

sub srcfile {
    my $self = shift;

    if ($self->{'master'}) {
	return $self->{'srcfile'};
    } else {
	die("Request for srcfile on a slave zone\n");
    }
} 

sub masters {
    my $self = shift;

    if ($self->{'master'}) {
	die("Request for masters on a master zone\n");
    } else {
	return @{$self->{'masters'}};
    }
}

sub maintainer {
    my $self = shift;
    
    return $self->{'maintainer'};
}

sub tostring {
    my $self = shift;

    if ($self->{'master'}) {
	return ref($self) . "[master, zone='$self->{zone}', "
	    . "srcfile='$self->{srcfile}', maintainer='$self->{maintainer}']";
    } else {
	return ref($self) . "[slave,  zone='$self->{zone}', "
	    . "masters=" . join(',', @{$self->{masters}}) . ", "
		. "maintainer='$self->{maintainer}']";
    }
}

sub check_ri {
    my $self = shift;

    if (!defined($self->{'zone'}) || !defined($self->{'srcfile'})
	|| !defined($self->{'maintainer'})) {
	die("ZoneEntry rep invariant violated: $self\n");
    }
}

sub read_entries_file {
    my $self = shift;
    my $zonesfile = shift;

    if (!open(ZONEFILE, $zonesfile)) {
	die("Could not open file of zone entries $zonesfile: $!\n");
    }

    my @entries;

    while (<ZONEFILE>) {
	s/\#.*//; # Elide everything after a comment character
	if (/^\s*$/) {
	    next; # Skip empty lines
	}

	my $entry = ZoneEntry->new_from_line($_);

	if (defined($entry)) {
	    @entries = (@entries, $entry);
	} else {
	    die("Error parsing zone entry from $zonesfile\n\t$_\n");
	}
    }

    close(ZONEFILE);

    return @entries;
}

