package probes::base;

=head1 NAME

probes::base - Base Class for implementing SmokePing Probes

=head1 OVERVIEW
 
For the time being, please use the probes::FPing for
inspiration when implementing your own probes.

=head1 AUTHOR

Tobias Oetiker <tobi@oetiker.ch>

=cut

use vars qw($VERSION);
use Carp;
use lib qw(..);
use Smokeping;

$VERSION = 1.0;

use strict;

sub new($$)
{
    my $this   = shift;
    my $class   = ref($this) || $this;
    my $self = { properties => shift, cfg => shift, 
    targets => {}, rtts => {}, addrlookup => {}};
    bless $self, $class;
    return $self;
}

sub add($$)
{
    my $self = shift;
    my $tree = shift;
    
    $self->{targets}{$tree} = shift;
}

sub ping($)
{
    croak "this must be overridden by the subclass";
}

sub round ($) {
    return sprintf "%.0f", $_[0];
}

sub ProbeDesc ($) {
    return "Probe which does not overrivd the ProbeDesc methode";
}    

sub rrdupdate_string($$)
{   my $self = shift;
    my $tree = shift;
#    print "$tree -> ", join ",", @{$self->{rtts}{$tree}};print "\n";    
    # skip invalid addresses
    my $pings = $self->{cfg}{Database}{pings}; 
    return "U:${pings}:".(join ":", map {"U"} 1..($pings+1)) 
        unless defined $self->{rtts}{$tree} and @{$self->{rtts}{$tree}} > 0;
    my $entries = scalar @{$self->{rtts}{$tree}};
    my @times = @{$self->{rtts}{$tree}};
    my $loss = $pings - $entries;
    my $median = $times[int($entries/2)] || 'U';
    # shift the data into the middle of the times array
    my $lowerloss = int($loss/2);
    my $upperloss = $loss - $lowerloss;
    @times = ((map {'U'} 1..$lowerloss),@times, (map {'U'} 1..$upperloss));
    my $age;
    if ( -f $self->{targets}{$tree}.".adr" ) {
      $age =  time - (stat($self->{targets}{$tree}.".adr"))[9];
    } else {
      $age = 'U';
    }
    if ( $entries == 0 ){
      $age = 'U';
      $loss = 'U';
      if ( -f $self->{targets}{$tree}.".adr"
	   and not -f $self->{targets}{$tree}.".snmp" ){
	unlink $self->{targets}{$tree}.".adr";
      }
    } ;
    return "${age}:${loss}:${median}:".(join ":", @times);
}

sub addresses($)
{
    my $self = shift;
    my $addresses = [];
    $self->{addrlookup} = {};
    foreach my $tree (keys %{$self->{targets}}){
        my $target = $self->{targets}{$tree};
        if ($target =~ m|/|) {
	   if ( open D, "<$target.adr" ) {
	       my $ip;
	       chomp($ip = <D>);
	       close D;
	       
	       if ( open D, "<$target.snmp" ) {
		   my $snmp = <D>;
		   chomp($snmp);
		   if ($snmp ne Smokeping::snmpget_ident $ip) {
		       # something fishy snmp properties do not match, skip this address
		       next;
		   }
                   close D;
	       }
	       $target = $ip;
	   } else {
	       # can't read address file skip
	       next;
	   }
	}
        $self->{addrlookup}{$target} = () 
                unless defined $self->{addrlookup}{$target};
        push @{$self->{addrlookup}{$target}}, $tree;
	push @{$addresses}, $target;
    };    
    return $addresses;
}

sub debug {
        my $self = shift;
        my $newval = shift;
        $self->{debug} = $newval if defined $newval;
        return $self->{debug};
}

sub do_debug {
        my $self = shift;
        return unless $self->debug;
        $self->do_log(@_);
}

sub do_fatal {
        my $self = shift;
        $self->do_log("Fatal:", @_);
        croak(@_);
}

sub do_log {
        my $self = shift;
        my $name = ref $self;
        $name =~ s/^probes:://;
        Smokeping::do_log("$name:", @_);
}

sub report {
	my $self = shift;
	my $count = keys %{$self->{targets}};
	$self->do_log("probing $count targets");
}

1;
