#!/usr/bin/perl -w
#
# $Id: Simple.pm,v 1.4 2002/03/29 13:13:10 fpmip Exp $
#
# Simple class for correlation
#
# Author : Tycho Fruru <tycho@fruru.com>
#
# Copyright (C) 2001 Tycho Fruru <tycho@fruru.com>
# Copyright (C) 2001 Conostix S.A. Luxembourg - Tycho Fruru <tycho@conostix.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
package IPFC::Correlate::Simple;

use strict;
use warnings;

use IPFC::Event;
use IPFC::EventGroup;
use Data::Dumper;

sub new($) {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	my $backend_interface = shift;
	
	if (not $backend_interface->isa("IPFC::Backend::Interface")) {
		die "IPFC::Correlate::Simple called without IPFC::Backend::Interface parameter";
	}

	my $self;
	
	$self->{'maximum-correlation-time'} = 600;
	$self->{'maximum-events'} = 100;
	$self->{'events'} = IPFC::EventGroup->new;
	
	bless($self,$class);
	return $self;
}

sub set_maximum_correlation_time($) {
	my $self = shift;
	my $maximum_correlation_time = shift;
	
	$self->{'maximum-correlation-time'} = $maximum_correlation_time;
	$self->cleanup;
	return $maximum_correlation_time;
}

sub get_maximum_correlation_time() {
	my $self = shift;
	return $self->{'maximum-correlation-time'};
}

sub set_maximum_events($) {
	my $self = shift;
	my $maximum_events = shift;
	$self->{'maximum-events'} = $maximum_events;
	$self->cleanup;
	return $maximum_events;
}

sub get_maximum_events() {
	my $self = shift;
	return $self->{'maximum-events'};
}

sub correlate($) {
# tries to find correlations between all events in the cache, then adds the event to the cache
	my $self = shift;
	my $event = shift;
	
	my $correlation ;
	
	if (! $event->isa("IPFC::Event")) {
		die "Called IPFC::Correlate::Simple::correlate without IPFC::Event parameter !";
	}
	
	my $correlation_event = $event->clone;
	
	$self->add_correlation_info($correlation_event);
	#adds correlation info (mostly "fictive" attributes) to the $correlation_event
	
	foreach my $key (keys %{$correlation_event}) {
		foreach my $value (@{$correlation_event->{$key}}) {
			if (defined($value) && defined($self->{'event-index'}->{$key}->{$value})) {
				$correlation->{$key}->{'value'} = $value;
				$correlation->{$key}->{'event_id'} = $self->{'event-index'}->{$key}->{$value};
			#print ".";
				#print "Correlation between events exists : ".
				#       "@{$self->{'event-index'}->{$key}->{$value}}\n";
				#print "For key $key with value $value\n";
	
			}
		}
	}
	
	my $event_id = $correlation_event->{"event_id"}->[0];
	
	foreach my $key (keys %$correlation_event) {
		foreach my $value (@{$correlation_event->{$key}}) {
			#push @{$self->{'event-index'}->{$key}->{$value}} , $event_id;
			if (defined($value)) {
				$self->{'event-index'}->{$key}->{$value}->{$event_id} = 1;
			}
		}
	}
	
	$self->{'event-index-time'}->{$event_id} = time; # timestamping (good for deleting old events)
	
#	print Dumper($self);
	
	$self->cleanup;
	
	#die;
	
#	print Dumper($correlation);
#	sleep 1;
	
	return $correlation;
}

sub add_correlation_info($) {
	my $self = shift;
	my $event = shift;
	
	if (! $event->isa("IPFC::Event")) {
		die "Called IPFC::Correlate::Simple::add_correlation_info without IPFC::Event parameter !";
	}
	
	return 1;
}

sub cleanup() {
	my $self = shift;
	
	my $timeout        = $self->get_maximum_correlation_time;
	my $maximum_events = $self->get_maximum_events;	
	my $events         = $self->{'event-index'};
	
	my $event_ids = $events->{'event_id'};
		
#	print Dumper($events);

	my $oldest_event = $self->{'oldest-event'} || 0;
	my $current_time = time;
	
	if ($oldest_event > ($current_time - ($self->{'maximum-correlation-time'} + 120))) {
		return 1;
	}
	
	print "cleaning the old bats\n";
#return 1;

# not a very good criterion, but ...
	
#	my @event_ids = keys %$event_ids;
		
	
#	my @sorted_events = sort { $self->{'event-index-time'}->{$a} <=> $self->{'event-index-time'}->{$b} }
#				   keys %{$self->{'event-index-time'}};
				   
	my @old_events;
	
	my $new_oldest_event = $current_time;
	
	while (my ($event_id) = each (%{$event_ids})) {
		if ( $self->{'event-index-time'}->{$event_id} < ($current_time - $self->{'maximum-correlation-time'}) ) {
			#print "Event $event_id more than 15 seconds old, deleting it !";
			push @old_events,$event_id;
			delete $self->{'event-index-time'}->{$event_id};
		} elsif ( $self->{'event-index-time'}->{$event_id} < $new_oldest_event ) {
			$new_oldest_event = $self->{'event-index-time'}->{$event_id};
		}
	}
	
	$self->{'oldest-event'} = $new_oldest_event;
	
#	print "Older than 70 seconds \n";
#	print join(":",@old_events)."\n";
	
	print "numbers : $#old_events old events\n";

#	$count = $count - ($#old_events + 1);
	
#	print "There are $count events remaining in correlation function\n";
	
#print "Oldest : $oldest_event_id\n";
	
#	print "Oldest event id = $oldest_event_id\n";

#print Dumper($events);
#print "This is before\n";
#sleep 5;


#	while (my ($key) = each %$events) {
#	  while (my ($value) = each %{$events->{$key}}) {
#	    my $i = 0;
#	    while (defined(my $oldest_event_id = $old_events[$i++])) {
#		if (defined($events->{$key}->{$value}->{$oldest_event_id})) {
#			delete $events->{$key}->{$value}->{$oldest_event_id};
#		}
#	    }
#	  }
#	}

	my $new_events;
	
	my %old;
	
	foreach my $e (@old_events) {
		$old{$e} = 1;
	}
		
	
	while (my ($key) = each %$events) {
	  while (my ($value) = each %{$events->{$key}}) {
	    while (my ($e) = each %{$events->{$key}->{$value}}) {
	    	if (! $old{$e}) {
			$new_events->{$key}->{$value}->{$e} = 1;
		}
	    }
	  }
	}

	$self->{'event-index'} = $new_events;

#	while (my ($key) = each %$events) {
#	  while (my ($value) = each %{$events->{$key}}) {
#	 	my @e = keys %{$events->{$key}->{$value}};
#		print "$key $value : $#e entries\n";
#		if ($#e == -1) {
#			print "There are no more keys left for $key $value ..\n";
#			print "\n\n\n";
#			undef $events->{$key}->{$value};
#			delete $events->{$key}->{$value};
#			print Dumper($events->{$key}->{$value});
#			print Dumper($events->{$key});
#		}
#	  }
#	}

	print "Cleaning finished ...\n";
	my @num = keys %{$self->{'event-index-time'}};
	print "$#num keys remaining\n";
	
#	print Dumper($self->{'event-index'});

	
	
	
#	print Dumper($events);
#	sleep 1;

	return 1;
	
}



return 1;
