package Zaptel::Span;
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2007, Xorcom
# This program is free software; you can redistribute and/or
# modify it under the same terms as Perl itself.
#
# $Id: Span.pm 5177 2007-12-24 20:31:24Z tzafrir $
#
use strict;
use Zaptel::Utils;
use Zaptel::Chans;

my $proc_base = "/proc/zaptel";

sub chans($) {
	my $span = shift;
	return @{$span->{CHANS}};
}

sub by_number($) {
	my $span_number = shift;
	die "Missing span number" unless defined $span_number;
	my @spans = Zaptel::spans();

	my ($span) = grep { $_->num == $span_number } @spans;
	return $span;
}

my @bri_strings = (
		'BRI_(NT|TE)',
		'(?:quad|octo)BRI PCI ISDN Card.* \[(NT|TE)\]\ ',
		'octoBRI \[(NT|TE)\] ',
		'HFC-S PCI A ISDN.* \[(NT|TE)\] '
		);

my @pri_strings = (
		'(E1|T1|J1)_(NT|TE)'
		);

our $ZAPBRI_NET = 'bri_net';
our $ZAPBRI_CPE = 'bri_cpe';

our $ZAPPRI_NET = 'pri_net';
our $ZAPPRI_CPE = 'pri_cpe';

sub new($$) {
	my $pack = shift or die "Wasn't called as a class method\n";
	my $num = shift or die "Missing a span number parameter\n";
	my $self = { NUM => $num };
	bless $self, $pack;
	$self->{TYPE} = "UNKNOWN";
	open(F, "$proc_base/$num") or die "Failed to open '$proc_base/$num\n";
	my $head = <F>;
	chomp $head;
	$self->{IS_DIGITAL} = 0;
	$self->{IS_BRI} = 0;
	$self->{IS_PRI} = 0;
	foreach my $cardtype (@bri_strings) {
		if($head =~ m/$cardtype/) {
			$self->{IS_DIGITAL} = 1;
			$self->{IS_BRI} = 1;
			$self->{TERMTYPE} = $1;
			$self->{TYPE} = "BRI_$1";
			$self->{DCHAN_IDX} = 2;
			$self->{BCHAN_LIST} = [ 0, 1 ];
			last;
		}
	}
	foreach my $cardtype (@pri_strings) {
		if($head =~ m/$cardtype/) {
			$self->{IS_DIGITAL} = 1;
			$self->{IS_PRI} = 1;
			$self->{PROTO} = "$1";
			$self->{TERMTYPE} = $2;
			$self->{TYPE} = "$1_$2";
			if($self->{PROTO} eq 'E1') {
				$self->{DCHAN_IDX} = 15;
				$self->{BCHAN_LIST} = [ 0 .. 14, 16 .. 30 ];
			} elsif($self->{PROTO} eq 'T1') {
				$self->{DCHAN_IDX} = 23;
				$self->{BCHAN_LIST} = [ 0 .. 22 ];
			} else {
				die "'$self->{PROTO}' unsupported yet";
			}
			last;
		}
	}
	die "$0: Unkown TERMTYPE [NT/TE]\n"
		if $self->is_digital  and !defined $self->{TERMTYPE};
	($self->{NAME}, $self->{DESCRIPTION}) = (split(/\s+/, $head, 4))[2, 3];
	$self->{IS_ZAPTEL_SYNC_MASTER} =
		($self->{DESCRIPTION} =~ /\(MASTER\)/) ? 1 : 0;
	$self->{CHANS} = [];
	while(<F>) {
		chomp;
		s/^\s*//;
		s/\s*$//;
		next unless /\S/;
		my $c = Zaptel::Chans->new($self, $_);
		push(@{$self->{CHANS}}, $c);
	}
	close F;

	$self->{YELLOW} = undef;
	$self->{CRC4} = undef;
	if($self->is_bri()) {
		$self->{CODING} = 'ami';
		$self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
		$self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
		# Infer some info from channel name:
		my $first_chan = ($self->chans())[0] || die "$0: No channels in span #$num\n";
		my $chan_fqn = $first_chan->fqn();
		if($chan_fqn =~ m(ZTHFC.*/|ztqoz.*/|XPP_BRI_.*/)) {		# BRI
			$self->{FRAMING} = 'ccs';
			$self->{SWITCHTYPE} = 'euroisdn';
			$self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPBRI_NET : $ZAPBRI_CPE ;
		} elsif($chan_fqn =~ m(ztgsm.*/)) {				# Junghanns's GSM cards. 
			$self->{FRAMING} = 'ccs';
			$self->{SIGNALLING} = 'gsm';
		}
	}
	if($self->is_pri()) {
		$self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
		$self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
		if($self->{PROTO} eq 'E1') {
			$self->{CODING} = 'hdb3';
			$self->{FRAMING} = 'ccs';
			$self->{SWITCHTYPE} = 'euroisdn';
			$self->{CRC4} = 'crc4';
		} elsif($self->{PROTO} eq 'T1') {
			$self->{CODING} = 'b8zs';
			$self->{FRAMING} = 'esf';
			$self->{SWITCHTYPE} = 'national';
		} else {
			die "'$self->{PROTO}' unsupported yet";
		}
		$self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPPRI_NET : $ZAPPRI_CPE ;
	}
	return $self;
}

sub bchans($) {
	my $self = shift || die;

	return @{$self->{BCHANS}};
}

1;
