package Dahdi::Config::Gen::Xpporder;
use strict;

use Dahdi::Config::Gen qw(is_true);
use Dahdi::Xpp;

sub new($$$) {
	my $pack = shift || die;
	my $gconfig = shift || die;
	my $genopts = shift || die;
	my $file = $ENV{XPPORDER_CONF} || "/etc/dahdi/xpp_order";
	my $self = {
			FILE	=> $file,
			GCONFIG	=> $gconfig,
			GENOPTS	=> $genopts,
		};
	bless $self, $pack;
	return $self;
}

#
# Returns list of xbuses sorted by the span numbers assigned
# to their XPD's. Also checks that each XBUS span numbers are sequential.
sub get_sorted_xbuses(@) {
	my @spans = @_;	# Verify our spans
	my @xbuses = Dahdi::Xpp::xbuses;
	my %xbus_of_span;
	my %xbus_beginning;
	my %seen_spans;
	my @sorted_xbuses;
	foreach my $xbus (@xbuses) {
		my $last_spanno;
		foreach my $xpd ($xbus->xpds) {
			my $spanno = $xpd->spanno;
			if(!$spanno) {
				printf STDERR "%s: Is not registered. Skipping.\n", $xpd->fqn;
				next;
			}
			$seen_spans{$spanno}++;
			if($xbus_of_span{$spanno}) {
				printf STDERR "%s: Span %d already seen on %s\n",
					$xpd->fqn, $spanno, $xbus_of_span{$spanno}->name;
				die;
			}
			$xbus_of_span{$spanno} = $xbus;
			# Check XPD's sequential numbering
			if(defined $last_spanno) {
				if($last_spanno + 1 != $spanno) {
					printf STDERR "%s: Bad span numbers (%d, %d)\n",
						$xpd->fqn, $last_spanno, $spanno;
					die;
				}
			} else {
				$xbus_beginning{$xbus} = $spanno;
			}
			$last_spanno = $spanno;
		}
	}
	foreach my $span (@spans) {
		my $spanno = $span->num;
		if(!defined($seen_spans{$spanno})) {
			warn "Span $spanno: Ignored: Does not belong to any XPD\n";
		}
	}
	@sorted_xbuses = sort { $xbus_beginning{$a} <=> $xbus_beginning{$b} } @xbuses;
	return @sorted_xbuses;
}

sub generate($$$) {
	my $self = shift || die;
	my $file = $self->{FILE};
	my $gconfig = $self->{GCONFIG};
	my $genopts = $self->{GENOPTS};
	my @spans = @_;		# Verify it's all our spans
	my @xbuses = get_sorted_xbuses(@spans);
	warn "Empty configuration -- no xbuses\n" unless @xbuses;
	rename "$file", "$file.bak"
		or $! == 2	# ENOENT (No dependency on Errno.pm)
		or die "Failed to backup old config: $!\n";
	#$gconfig->dump;
	print "Generating $file\n" if $genopts->{verbose};
	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
	my $old = select F;
	printf "# Autogenerated by $0 on %s\n", scalar(localtime);
	print  "# If you edit this file and execute $0 again,\n";
	print  "# your manual changes will be LOST.\n";
	print <<'HEAD';
#
# This is an optional configuration file for ordering
# Dahdi registration.
#
# It is read from /etc/dahdi/xpp_order. This location
# may be overridden via the environment variable XPPORDER_CONF
#
# Lines may contain:
#   - The Astribank label (verbatim)
#   - The Astribank connector string (prefixed with @)
# Ordering number of each listed Astribank is determined
# by its position in this file.
# Astribanks not listed in this file, get an ordering
# number of 99 (last).
#
# Astribanks with same ordering number are sorted by their
# connectors (to preserve legacy behavior).
#
# Examples:
#usb:1234
#@usb-0000:06:02.2-2
HEAD
	foreach my $xbus (@xbuses) {
		my $label = $xbus->label;
		my $connector = $xbus->connector;
		my $name = $xbus->name;
		printf "%s\t# %s #(%s)\n", $label, $connector, $name;
	}
	close F;
	select $old;
}

1;

__END__

=head1 NAME

Xpporder - Generate Astribank ordering information for dahdi_registration.

=head1 SYNOPSIS

 use Dahdi::Config::Gen::Xpporder;

 my $cfg = new Dahdi::Config::Gen::Xpporder(\%global_config, \%genopts);
 $cfg->generate;

=head1 DESCRIPTION

Generate the F</etc/dahdi/xpp_order>.
This is the configuration for dahdi_registration(1).
The order is determined according to current Dahdi registration
order.

Its location may be overriden via the environment variable F<XPPORDER_CONF>.
