package Statusmon::Rsync;

use Statusmon::Statusmon;
use Monitor::bb;

@Statusmon::Rsync::ISA = qw(Statusmon::Statusmon);

use strict;


sub new
{

    my ($this) = @_;
    my  $class = ref($this) || $this;
    my  $self = {};

    bless($self, $class);

    # I want to receive "statuschange" events
    $self->register( "statuschange" );
    $self->register( "metagrouping" );
    $self->register( "config" );
    $self->sched_frequency( 1 );
    $self->{"rsync"} = [];
    $self->{"watches"} = {};
    $self->{"full_int"} = 8;
    $self->{"grouping_int"} = 15;

    return($self);
}


sub start {
    my( $self ) = @_;

    print STDERR "Rsync start()\n" if( $BigSister::common::dl > 3 );
    my $config = $self->get_feature_provider( "displayconfig" );
    if( $config ) { $self->read_config( $config->get_current_config() ) };
}
    

sub find_watches {
    my( $self ) = @_;
    my $watches = $self->{"watches"} = {};
    my $sync;

    print STDERR "Rsync: find_watches()\n" if( $BigSister::common::dl > 7 );
    my $grouper = $self->get_feature_provider( "grouping" );
    foreach $sync( @{$self->{"rsync"}} ) {
        my $thiswatches = $sync->{"watches"} = {};
	my @groups = @{$sync->{"config"}->{"groups"}};
	my $i;
	for( $i=0; $i <= $#groups; $i++ ) {
	    my $group = $groups[$i];
	    print STDERR "  $group\n" if( $BigSister::common::dl > 8 );
	    next if( $thiswatches->{$group} );
	    $thiswatches->{$group} = 1;
	    my $watchlist;
	    if( defined $watches->{$group} ) {
	        $watchlist = $watches->{$group};
	    }
	    else {
	        $watches->{$group} = $watchlist = [];
	    }
	    push( @$watchlist, $sync );
	    if( $grouper ) {
	        my $subs = $grouper->get_members( $group );
		if( $subs ) {
		    push( @groups, @$subs );
		}
	    }
	}
    }
}



sub read_config {
    my( $self, $newconfig, $oldconfig ) = @_;

    print STDERR "Rsync read_config()\n" if( $BigSister::common::dl > 4 );
    $self->{"dirty"} = 1;
    my $syncs = $self->{"rsync"} = [];

    if( (! defined $newconfig->{"rsync"}) || ! @{$newconfig->{"rsync"}} ) {
        print STDERR "Rsync: not configured\n" if( $BigSister::common::dl > 4 );
	return;
    }

    my $sync;
    foreach $sync (@{$newconfig->{"rsync"}}) {
        my %sync = (
	    "config" => $sync,
	    "vips" => ()
	    );
	print STDERR "Rsync adding host $sync->{host}, port $sync->{port}, groups ".(join(",",@{$sync->{groups}})).", prefix $sync->{prefix}\n" if( $BigSister::common::dl > 4 );
	push( @$syncs, \%sync );
    }
    $self->find_watches();
}



sub join_group {
    my( $self, $cmd ) = @_;

    my $group = $cmd->{"group"};
    if( defined $self->{"watches"}->{$group} ) {
        $self->{"groupdirty"} = 1;
    }
}



sub set {
    my( $self, $cmd ) = @_;

    my $host = $cmd->{"host"};
    return unless( defined $self->{"watches"}->{$host} );
    my $watchlist = $self->{"watches"}->{$host};
    my $sync;
    foreach $sync (@$watchlist) {
        push( @{$sync->{"vips"}}, 
	  "status ".($sync->{"config"}->{"prefix"}).$host.".".(
	  $cmd->{"check"})." ".($cmd->{"status"})." (".(time
	  ).") ".(scalar localtime)." ".($cmd->{"text"}) );
    }
}


sub event {
    my( $self, $cmd ) = @_;
    my $text;

    print STDERR "Statusmon::grouping got an event\n" if( $BigSister::common::dl > 6 );
    $self->{"current_event"} = $cmd;
    if( $cmd->{"cmd"} eq "groupmembers" ) {
	$self->join_group( $cmd );
    }
#    elsif( $cmd->{"cmd"} eq "grouptitle" ) {
#	$self->displayname( $cmd->{"group"}, $cmd->{"name"} );
#    }
    elsif( $cmd->{"cmd"} eq "displayconfig" ) {
	$self->read_config( $cmd->{"config"}, $cmd->{"previous_config"} );
    }
    elsif( $cmd->{"cmd"} eq "statuschange" ) {
	$self->set( $cmd );
    }
}



sub fullupdate {
    my( $self, $host ) = @_;
    my $sync;

    my $grouper = $self->get_feature_provider( "grouping" );
    return unless( $grouper );
    foreach $sync (@{$self->{"rsync"}}) {
        my $cfg = $sync->{"config"};
	next if( (defined $host) && ($host ne $cfg->{"host"}) );
	my $list = $sync->{"vips"} = [];
	my @watches = keys %{$sync->{"watches"}};
	my $prefix = $cfg->{"prefix"};
	my $i;
	for( $i=0; $i<=$#watches; $i++ ) {
	    my $host = $watches[$i];
	    my @checks = $self->get_checks( $host );
	    next unless( @checks );
	    my $check;
	    foreach $check (@checks) {
		my $status = $self->get_current_status( $host.".".$check );
		last unless( defined $status );
		push( @$list, "status $prefix$host.$check ".($self->get_statustext($status)
			)." (".time.") ".(scalar localtime)." ".(
			$self->get_current_text( $host.".".$check )) );
	    }
	}
    }
    $self->incremental( $host );
}


sub incremental {
    my( $self, $host ) = @_;
    my $sync;

    foreach $sync (@{$self->{"rsync"}}) {
        my $cfg = $sync->{"config"};
	next if( (defined $host) && ($host ne $cfg->{"host"}) );
        my $bbd = Monitor::bb->new( $cfg->{"host"}, 10, $cfg->{"port"} );
	my @reps = @{$sync->{"vips"}};
	my $i;
	for( $i=0; $i<=$#reps; $i++ ) {
	    $reps[$i] =~ s/\n/\|\>/g;
	    $bbd->sysreport( $reps[$i] );
	}
	$bbd->_end_report();
    }
}


sub groupupdate {
    my( $self, $host ) = @_;
    my $sync;

    my $grouper = $self->get_feature_provider( "grouping" );
    return unless( $grouper );
    foreach $sync (@{$self->{"rsync"}}) {
        my $cfg = $sync->{"config"};
	next if( (defined $host) && ($host ne $cfg->{"host"}) );
	my $list = $sync->{"vips"} = [];

	my $group;
	my $prefix = $cfg->{"prefix"};
	foreach $group (keys %{$sync->{"watches"}}) {
	    my $name = $grouper->get_title( $group );
	    push( @$list, "displayname $prefix".$group." ".$name );
	    my $groups = $grouper->get_groups( $group );
	    # was sending an empty group list if ($groups && !@$groups);
	    # bbd didn't like this much
	    next unless( $groups && @$groups );
	    push( @$list, "join $prefix".$group." $prefix".(
	        join( " $prefix", @$groups ))  );
	}
    }
    $self->incremental( $host );
}



sub run {
    my( $self ) = @_;

    print STDERR "Rsync run()\n" if( $BigSister::common::dl > 4 );
    if( $self->{"groupdirty"} ) {
        $self->find_watches();
	$self->{"groupdirty"} = 0;
    }

    if( $self->{"dirty"} ) {
        $self->{"full_last"} = 0;
	$self->{"grouping_last"} = 0;
	$self->{"dirty"} = 0;
    }

    print STDERR "number of remote syncs: ".(@{$self->{"rsync"}})."\n" if( $BigSister::common::dl > 5 );
    return unless( $#{$self->{"rsync"}} >= 0 );

    my $now = time;
    if( $now - $self->{"full_last"} >= $self->{"full_int"} * 60 ) {
	print STDERR "Rsync fullupdate()\n" if( $BigSister::common::dl > 4 );
	my $pid = $self->background();
        if( ($pid == 0) || ($pid == -1) ) {
	    $self->fullupdate();
	    exit(0) if( ! $pid );
	}
	$self->{"full_last"} = $now;
    }
    else {
	print STDERR "Rsync incremental()\n" if( $BigSister::common::dl > 4 );
	my $pid = $self->background();
        if( ($pid == 0) || ($pid == -1) ) {
	    $self->incremental();
	    exit(0) if( ! $pid );
	}
    }

    my $sync;
    foreach $sync (@{$self->{"rsync"}}) {
        $sync->{"vips"} = [];
    }

    if( $now - $self->{"grouping_last"} >= $self->{"grouping_int"} * 60 ) {
	print STDERR "Rsync groupupdate()\n" if( $BigSister::common::dl > 4 );
	my $pid = $self->background();
        if( ($pid == 0) || ($pid == -1) ) {
	    $self->groupupdate();
	    exit(0) if( ! $pid );
	}
	$self->{"grouping_last"} = $now;
    }
}


1;
