#! /usr/bin/perl -w
################################################################################
# Copyright 2005-2009 MERETHIS
# Centreon is developped by : Julien Mathis and Romain Le Merlus under
# GPL Licence 2.0.
# 
# 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.
# 
# 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.
# 
# You should have received a copy of the GNU General Public License along with 
# this program; if not, see <http://www.gnu.org/licenses>.
# 
# Linking this program statically or dynamically with other modules is making a 
# combined work based on this program. Thus, the terms and conditions of the GNU 
# General Public License cover the whole combination.
# 
# As a special exception, the copyright holders of this program give MERETHIS 
# permission to link this program with independent modules to produce an executable, 
# regardless of the license terms of these independent modules, and to copy and 
# distribute the resulting executable under terms of MERETHIS choice, provided that 
# MERETHIS also meet, for each linked independent module, the terms  and conditions 
# of the license of that module. An independent module is a module which is not 
# derived from this program. If you modify this program, you may extend this 
# exception to your version of the program, but you are not obliged to do so. If you
# do not wish to do so, delete this exception statement from your version.
# 
# For more information : contact@centreon.com
# 
# SVN : $URL
# SVN : $Id :
#
####################################################################################
#
# Script init
#

use strict;
use warnings;
use DBI;
use POSIX ":sys_wait_h";

use lib "/usr/lib/perl5/vendor_perl/5.10.1/i386-linux-thread-multi";
use RRDs;
use File::Copy;

my $installedPath = "/usr/share/centreon/";

my $LOG = "/var/log/centreon/centstorage.log";
my $PID = "/var/run/centreon/centstorage.pid";

# Init Globals
use vars qw($debug $LOG %status $generalcounter);
use vars qw($mysql_user $mysql_passwd $mysql_host $mysql_database_oreon $mysql_database_ods $mysql_database_ndo);
use vars qw($con_oreon $con_ods);

$debug = 0;
my $stop = 0;

# Init value
my ($file, $line, @line_tab, @data_service, $hostname, $service_desc, $metric_id, $configuration);

# Init status tab
%status = ('OK' => '0', 'WARNING' => '1', 'CRITICAL' => '2', 'UNKNOWN' => '3', 'PENDING' => '4');

# Include Configuration Data
require "/etc/centreon/conf.pm";

sub catch_zap {
	$stop = 0;
	writeLogFile("Receiving order to stop...\n");
}

sub writeLogFile($){
	open (LOG, ">> ".$LOG) || print "can't write $LOG: $!";
	print LOG time()." - ".$_[0];
	close LOG or warn $!;
}

# checking if pid file exists.
if (-x $PID){
	writeLogFile("ods already runnig. can't launch again....\n");
	exit(2);
}

# Set signals
$SIG{INT}  = \&catch_zap;

require $installedPath."lib/misc.pm";
require $installedPath."lib/purge.pm";
require $installedPath."lib/getHostData.pm";
require $installedPath."lib/getServiceData.pm";
require $installedPath."lib/identifyService.pm";
require $installedPath."lib/verifyHostServiceIdName.pm";
require $installedPath."lib/identifyMetric.pm";
require $installedPath."lib/updateFunctions.pm";

sub CheckMySQLConnexion(){
	while ((!defined($con_oreon) || !$con_oreon->ping) && (!defined($con_ods) || !$con_ods->ping)){
		if (!defined($con_oreon) || !$con_oreon->ping) {
			$con_oreon = DBI->connect("DBI:mysql:database=".$mysql_database_oreon.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
			if (!defined($con_oreon)) {
				writeLogFile("Error when connecting to database : " . $DBI::errstr . "\n");
				sleep(2);
			}
		} else {
			sleep(2);
			undef($con_oreon);
			$con_oreon = DBI->connect("DBI:mysql:database=".$mysql_database_oreon.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
		}
		if (!defined($con_ods) || !$con_ods->ping) {
			$con_ods = DBI->connect("DBI:mysql:database=".$mysql_database_ods.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
			if (!defined($con_ods)) {
				writeLogFile("Error when connecting to database : " . $DBI::errstr . "\n");
				sleep(2);
			}
		} else {
			sleep(2);
			undef($con_ods);
			$con_ods = DBI->connect("DBI:mysql:database=".$mysql_database_ods.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});	
		}
	}
}

sub CreateConnexionForCentstorage(){
	my $strgcnx;
	while (!defined($strgcnx) || !$strgcnx->ping){
		if (!defined($strgcnx)) {
			$strgcnx = DBI->connect("DBI:mysql:database=".$mysql_database_ods.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
			if (!defined($strgcnx)) {
				writeLogFile("Error when connecting to database : ".$DBI::errstr."\n");
				sleep(5);
			}
		}
	}
	return $strgcnx;
}

sub CreateConnexionForOreon(){
	my $oreoncnx;
	while (!defined($oreoncnx) || !$oreoncnx->ping){
		if (!defined($oreoncnx)) {
			$oreoncnx = DBI->connect("DBI:mysql:database=".$mysql_database_oreon.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
			if (!defined($oreoncnx)) {
				writeLogFile("Error when connecting to database : ".$DBI::errstr."\n");
				sleep(5);
			}
		}
	}
	return $oreoncnx;
}

sub CreateConnexionForNDO(){
	my $ndocnx;
	while (!defined($ndocnx) || !$ndocnx->ping){
		if (!defined($ndocnx)) {
			$ndocnx = DBI->connect("DBI:mysql:database=".$mysql_database_ndo.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
			if (!defined($ndocnx)) {
				writeLogFile("Error when connecting to database : ".$DBI::errstr."\n");
				sleep(5);
			}
		}
	}
	return $ndocnx;
}

########################################
# return perfdata file path
########################################

sub getPerfDataFile(){
	my ($filename, $sth2, $data, $con_ods);
	$con_ods = DBI->connect("DBI:mysql:database=".$mysql_database_ods.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
	$sth2 = $con_ods->prepare("SELECT perfdata_file FROM config");
	if (!$sth2->execute){
		writeLogFile("Error when getting perfdata file : " . $sth2->errstr . "\n");
	}
	$data = $sth2->fetchrow_hashref();
	undef($sth2);
	$filename = $data->{'perfdata_file'};
	undef($data);
	undef($con_ods);
	return $filename;
}

########################################
# Move perfdata file to tmp file 
########################################

sub movePerfDataFile($){
	my $PERFDATA = $_[0];
	if (move($PERFDATA, $PERFDATA."_read")){
		`echo "# New File #" >> $PERFDATA`;
		return(1);
	}
}

########################################
# Get ODS config data  
########################################

sub getConfig(){
	my ($sth2, $data, $con_ods);
	$con_ods = DBI->connect("DBI:mysql:database=".$mysql_database_ods.";host=".$mysql_host, $mysql_user, $mysql_passwd, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});
	$sth2 = $con_ods->prepare("SELECT auto_drop,drop_file,perfdata_file FROM config");
	writeLogFile("Error when getting drop and perfdata properties : ".$sth2->errstr."\n")if (!$sth2->execute);
	$data = $sth2->fetchrow_hashref();	
	undef($sth2);
	undef($con_ods);
	return($data);
}

sub GetPerfData(){
	# Init Var
	my ($line_tab, $sth2, $data, $flag_drop, $sleeptime);
	use vars qw($con_oreon $con_ods);
	
	CheckMySQLConnexion();				
	my $PFDT = getPerfDataFile();
	
	if (-r $PFDT || -r $PFDT.".bckp"){
		# Move perfdata File befor reading		
		# Penser a lire le fichier de backup !
		CheckMySQLConnexion();
		if (movePerfDataFile($PFDT) && open(PFDT, "< $PFDT"."_read")){
			$data = getConfig();
			$PFDT = $data->{'perfdata_file'};
			$flag_drop = 1;
			if ($data->{'auto_drop'} == 1 && defined($data->{'drop_file'})){
				if (!open(DROP, ">> ".$data->{'drop_file'})){
					$flag_drop = 0;
					writeLogFile("can't write in ".$data->{'drop_file'}." : $!");
				}
			} else {
				$flag_drop = 0;
			}
			undef($data);
			while (<PFDT>){
				if (!m/^\#.*/){
					print DROP $_  if ($flag_drop == 1);
			    	@line_tab = split('\t');
			    	$line_tab[2] =~ s/\\/\#BS\#/g;
			    	$line_tab[2] =~ s/\//\#S\#/g;
			    	if (defined($line_tab[5]) && ($line_tab[5] ne '' && $line_tab[5] ne "\n")){
						CheckMySQLConnexion();
						checkAndUpdate(@line_tab);
					}
					undef($line_tab);
				}
			}
			close(PFDT);
			# Remove Read File
			writeLogFile("Error When removing service-perfdata file : $!") if (!unlink($PFDT."_read"));
				
			# Drop Data
			close(DROP) if ($flag_drop == 1);
			undef($line_tab);
			undef($flag_drop);
		} else {
			writeLogFile("Error When writing data in tmp read file : $!");
		}
		my $i,
		$sleeptime = getSleepTime();
		for ($i = 0; $i <= $sleeptime && $stop; $i++){
			sleep(1);	
		}
		undef($sleeptime);
		undef($i);
	}
	$con_oreon->disconnect();
    $con_ods->disconnect();
} 

########################################
# Check if nagios restart and if we 
# must to check configuration and 
# launch purge process  
# -> Thread
########################################

sub CheckRestart(){
	my ($last_restart_stt, $last_restart, $sth2, $data, $y);
	use vars qw($con_oreon $con_ods);
	
	$last_restart = getLastRestart();
	$last_restart_stt = getLastRestartInMemory();
	if (!$last_restart_stt || $last_restart ne $last_restart_stt){
		check_HostServiceID();
		if (getPurgeConfig()){
			CheckMySQLDrain();
			DeleteOldRrdDB();
		}
		saveLastRestartInMemory($last_restart);
	}
}

########################################
# Purge MySQL data
########################################

sub purgeMysqlData(){
	my $con_ods= CreateConnexionForCentstorage();
	my $sth2 = $con_ods->prepare("SELECT * FROM config");	
	writeLogFile("Error when getting len_storage_mysql properties : ".$sth2->errstr."\n")if (!$sth2->execute());
	my $data = $sth2->fetchrow_hashref();
	if (defined($data->{'len_storage_mysql'}) && $data->{'len_storage_mysql'} ne 0){
		my $delete_limit = time() - 60 * 60 * 24 * $data->{'len_storage_mysql'};
		$sth2 = $con_ods->prepare("DELETE FROM data_bin WHERE ctime < '".$delete_limit."'");
		writeLogFile("Error when purging Mysql data  : ".$sth2->errstr."\n")if (!$sth2->execute());
	}
	$sth2->finish();
	undef($sth2);
	$con_ods->disconnect();
}

sub checkAndUpdate($){
	my $data_service;
	my $valueRecorded;
	if ($_[5]){
		if ($_[1] =~ /[a-zA-Z]*_Module/){
			@data_service = identify_hidden_service($_[1], $_[2]); # return index_id and storage
			if (defined($data_service[0]) && $data_service[0] ne 0) {
				$valueRecorded = identify_hidden_metric($_[5], $data_service[0], $_[4], $_[0], $data_service[1], $valueRecorded, $data_service[2]); # perfdata index status time type counter rebuild
			}
		} else {
			@data_service = identify_service($_[1], $_[2]); # return index_id and storage
			# Update status 
			updateServiceState($line_tab[1], $line_tab[2], $line_tab[0], $data_service[0]);
			if (defined($data_service[0]) && $data_service[0] ne 0) {
				$valueRecorded = identify_metric($_[5], $data_service[0], $_[4], $_[0], $data_service[1], $valueRecorded, $data_service[2]); # perfdata index status time type counter rebuild
			}
		}
	}
	undef(@data_service);
}

sub getModulesInterval($$){
        my $service_description = $_[0];
        $con_oreon = $_[1];
        my $interval;
        $service_description =~ /([a-zA-Z0-9]*)_([0-9]*)/;
        if ($1 eq "meta"){
            my $sth_interval = $con_oreon->prepare("SELECT normal_check_interval FROM meta_service WHERE meta_id = '".$2."'");

            if (!$sth_interval->execute) {
                writeLogFile("Error when getting metrics interval for Meta : " . $sth_interval->errstr . "\n");
            }
            my $meta_conf = $sth_interval->fetchrow_hashref();
            if (defined($meta_conf->{'normal_check_interval'}) && $meta_conf->{'normal_check_interval'}){
                $interval = $meta_conf->{'normal_check_interval'} * getIntervalLenght();
            } else {
                $interval = 2 * getIntervalLenght();
            }
            undef($meta_conf);
            undef($sth_interval);
        } elsif ($1 eq "qos") {
            my $sth_interval = $con_oreon->prepare("SELECT normal_check_interval FROM mod_QOS WHERE osl_id = '".$2."'");
            if (!$sth_interval->execute) {
                writeLogFile("Error when getting metrics interval for QOS : " . $sth_interval->errstr . "\n");
            }
            my $osl_conf = $sth_interval->fetchrow_hashref();
            if (defined($osl_conf->{'normal_check_interval'}) && $osl_conf->{'normal_check_interval'}){
                $interval = $osl_conf->{'normal_check_interval'} * getIntervalLenght();
            } else {
                $interval = 2 * getIntervalLenght();
            }
            undef($osl_conf);
            undef($sth_interval);
        } else {
            $interval = 90;
        }
        return $interval;
}

sub updateServiceState($$$$){ # Host name, sercvice desc, ctime, index
	my $interval = 4000;
	my $nb_value;
	my $interval_length;

	my $index = $_[3];

	my $RRDdatabase_status_path = getRRDdatabase_status_path();	
	my @tab = (0=>"100", 1=>"75", 2=>"0", 3=>"0");	
	
	my $odscnx = CreateConnexionForCentstorage();
	my $centcnx= CreateConnexionForOreon();
	
	my $service_description = removeSpecialCharInMetric($_[2]);
	
	my $sth = $centcnx->prepare("SELECT `db_name`, `db_prefix`, `db_user`, `db_pass`, `db_host` FROM `cfg_ndo2db` LIMIT 1;");
	writeLogFile("Error when getting informations about ndo connexions : ".$sth->errstr."\n") if (!$sth->execute);
	my $conf = $sth->fetchrow_hashref();
	
	# Set NDO Prefix  
	my $ndo_prefix = $conf->{"db_prefix"};
	
	$_[1] =~ s/#S#/\//g;
	$_[1] =~ s/#BS#/\\/g;
	
	# Connect To NDO DB
	my $ndocnx = DBI->connect("DBI:mysql:database=".$conf->{"db_name"}.";host=".$conf->{"db_host"}, $conf->{"db_user"}, $conf->{"db_pass"}, {'RaiseError' => 0, 'PrintError' => 0, 'AutoCommit' => 1});		
	my $reqH = "(SELECT `host_object_id` FROM `nagios_hosts` WHERE `display_name` = '".$_[0]."' LIMIT 1)";
	my $reqS = "(SELECT `service_object_id` FROM `nagios_services` WHERE `display_name` = '".$_[1]."' AND `host_object_id` = ($reqH) LIMIT 1)";
	my $req = "SELECT `last_hard_state` FROM `nagios_servicestatus` WHERE `service_object_id` = $reqS";
	
	my $sth2 = $ndocnx->prepare($req);
	writeLogFile("Error when getting service id who must be rebuild : ".$sth2->errstr."\n") if (!$sth2->execute);
	my $hard_state = $sth2->fetchrow_hashref();
	
	# Get Hard State
	my $status = $hard_state->{"last_hard_state"};
	$sth2->finish();
	$ndocnx->disconnect();
		
	if (defined($status)){
		if ($status eq 0){
			$status = 100;
		} elsif ($status eq 1){
			$status = 75;
		} elsif ($status eq 2){
			$status = 0;
		} elsif ($status eq 3){
			undef($status);
		}
	}
	
	if (!-d $RRDdatabase_status_path){
		writeLogFile("Directory ".$RRDdatabase_status_path." does not exists. Trying to create it....\n");
		if (!mkdir($RRDdatabase_status_path, "775")) {
			writeLogFile("Can't create ".$RRDdatabase_status_path." : permission denied\n");	
		} else {
			writeLogFile($RRDdatabase_status_path." Created\n");
		}
	}
	
	# call function to check if DB exist and else create it
	if (defined($index) && defined($status) && $_[2]){
		if (-e $RRDdatabase_status_path."/".$index.".rrd"){
			updateRRDDatabase($RRDdatabase_status_path, $index, "status", $_[2], $status);
		} else {
			my $begin = time() - 200000;
			$interval = getServiceCheckIntervalWithSVCid($index);
			$interval = 3 if (!defined($interval));
			$interval = getIntervalLenght() * $interval;
			my $interval_hb = $interval * 2;
			$nb_value = getLenStorageDB() / $interval;

			createRRDDatabase($RRDdatabase_status_path, $index, $begin, $interval, "status", $nb_value);
			tuneRRDDatabase($RRDdatabase_status_path, $index, "status", $interval_hb);
			updateRRDDatabase($RRDdatabase_status_path,$index, "status", $_[2], $status);

			undef($begin);
		}
	}
}

sub replaceMetricSpecialChar($){
	my $metric_name = $_[0];
	$metric_name =~ s/\//slash\_/g;
	$metric_name =~ s/\\/bslash\_/g;
	$metric_name =~ s/\#S\#/slash\_/g;
	$metric_name =~ s/\#BS\#/bslash\_/g;
	return $metric_name;
}

sub createRRDDatabase($$$$$$){
	my ($ERR, $RRDdatabase_path, $metric_id, $begin, $metric_name, $interval, $my_len_storage_rrd);
	($RRDdatabase_path, $metric_id, $begin, $interval, $metric_name, $my_len_storage_rrd) = @_;
	$metric_name = replaceMetricSpecialChar($metric_name);
	RRDs::create($RRDdatabase_path.$metric_id.".rrd", "-b ".$begin, "-s ".$interval, "DS:".substr($metric_name, 0, 19).":GAUGE:".$interval.":U:U", "RRA:AVERAGE:0.5:1:".$my_len_storage_rrd, "RRA:AVERAGE:0.5:12:".$my_len_storage_rrd);
	$ERR = RRDs::error;
	if ($ERR) {
		writeLogFile("ERROR while creating ".$RRDdatabase_path.$metric_id.".rrd : $ERR\n");
	}
	undef($ERR);
}

sub tuneRRDDatabase($$$$){
	my ($ERR, $RRDdatabase_path, $metric_id ,$metric_name, $interval_hb);
	($RRDdatabase_path, $metric_id ,$metric_name, $interval_hb) = @_;
	$metric_name = replaceMetricSpecialChar($metric_name);
	RRDs::tune($RRDdatabase_path.$metric_id.".rrd", "-h", substr($metric_name, 0, 19).":".$interval_hb);
	$ERR = RRDs::error;
	if ($ERR){
		writeLogFile("ERROR while tunning operation on ".$RRDdatabase_path.$metric_id.".rrd : $ERR\n");
	}
	undef($ERR);
}

sub removeOldRRDDatabase($$$$){
	my ($RRDdatabase_path, $metric_id, $interval, $my_len_storage_rrd);
	($RRDdatabase_path, $metric_id, $interval, $my_len_storage_rrd) = @_;
	system("rm -Rf  ".$RRDdatabase_path.$metric_id.".rrd");
	writeLogFile("Rebuild database : ".$RRDdatabase_path.$metric_id.".rrd (interval : $interval - Len : $my_len_storage_rrd)\n");		
}

sub updateRRDDatabase($$$$$){
	my ($RRDdatabase_path, $metric_id, $metric_name, $ctime, $value) = @_;
	my $ERR;
	
	$value =~ s/\,/\./g;
	$metric_name = replaceMetricSpecialChar($metric_name);
	RRDs::update ($RRDdatabase_path.$metric_id.".rrd" , "--template", substr($metric_name, 0, 19), $ctime.":".sprintf("%e", $value));
	$ERR = RRDs::error;
	if ($ERR){
		writeLogFile("ERROR while updating ".$RRDdatabase_path.$metric_id.".rrd at ".$ctime." -> ".$value." : $ERR\n");
	}
	undef($ERR);
}

sub CheckRebuild(){
	use vars qw($con_oreon $con_ods);
	my ($RRDdatabase_path, $RRDdatabase_status_path, $len_storage_rrd, $svc_mst_be_rbld);
	my ($data, $ERR, $flag, $metric, $cpt);
	
	# ---------------------------------------------
	# enable db connexion
	my $con_ods = CreateConnexionForCentstorage();
	my $con_oreon = CreateConnexionForOreon();
	
	# ---------------------------------------------
	# Rebuild database
	$RRDdatabase_path = getRRDdatabase_path();
	$RRDdatabase_status_path = getRRDdatabase_status_path();
	$len_storage_rrd = getLenStorageDB();
	
	my $sth2 = $con_ods->prepare("SELECT id, service_id, host_name, service_description FROM index_data WHERE `must_be_rebuild` = '1'");
	writeLogFile("Error when getting service id who must be rebuild : ".$sth2->errstr."\n") if (!$sth2->execute);
	while ($svc_mst_be_rbld = $sth2->fetchrow_hashref()){
	
		my $sth = $con_ods->prepare("UPDATE index_data SET `must_be_rebuild` = '2' WHERE id = '".$svc_mst_be_rbld->{'id'}."'");
		writeLogFile("Error when getting perfdata file : " . $sth->errstr . "\n") if (!$sth->execute);
		undef($sth);
		
		writeLogFile("Rebuild Graphs for Services : ".$svc_mst_be_rbld->{'id'}."\n");
		
		# -----------------------------------------------------
		# Get check interval for this service
		my $interval;
		my $sth_interval;
		if ($svc_mst_be_rbld->{'host_name'} =~ /([a-zA-Z0-9]*)_Module/){
			$interval = getModulesInterval($svc_mst_be_rbld->{'service_description'}, $con_oreon);
		} else {
			$interval = getServiceCheckIntervalFromService($svc_mst_be_rbld->{'id'}) * getIntervalLenght();
		}
		$interval = 330 if (!defined($interval));
		
		my $interval_hb = $interval * 2;
		my $sth3 = $con_ods->prepare("SELECT metric_id, metric_name FROM metrics WHERE index_id = '".$svc_mst_be_rbld->{'id'}."'");
		if (!$sth3->execute) {writeLogFile("Error when getting metrics id who must be rebuild : " . $sth3->errstr . "\n");}
		
		writeLogFile("ERROR : can t rebuild... interval = 0 (time unit : ".getIntervalLenght().")\n") if ($interval == 0);
		my $sth4;
		if ($interval != 0){
			while ($metric = $sth3->fetchrow_hashref()){
				# Replace Special chars
				$metric->{'metric_name'} = replaceMetricSpecialChar($metric->{'metric_name'});
				writeLogFile("Get Data for rebuilding $RRDdatabase_path".$metric->{'metric_id'}.".rrd\n");					
				
				# Get All Data
				$sth4 = $con_ods->prepare("SELECT * FROM data_bin WHERE id_metric = '".$metric->{'metric_id'}."' ORDER BY ctime");
				writeLogFile("Error when getting perfdata file : " . $sth4->errstr . "\n") if (!$sth4->execute);
				
				for ($flag = 0, $cpt = 0;$data = $sth4->fetchrow_hashref();$cpt++){
					if (!$flag){
						# Calculate first entry in database					
						my $begin = $data->{'ctime'} - 200;
						
						my $my_len_storage_rrd = $len_storage_rrd / $interval;
						
						removeOldRRDDatabase($RRDdatabase_path, $metric->{'metric_id'}, $interval, $my_len_storage_rrd);
						
						# Create DB
						createRRDDatabase($RRDdatabase_path, $metric->{'metric_id'}, $begin, $interval, $metric->{'metric_name'}, $my_len_storage_rrd);
						tuneRRDDatabase($RRDdatabase_path, $metric->{'metric_id'}, $metric->{'metric_name'}, $interval_hb);
						
						undef($begin);
						undef($my_len_storage_rrd);
						$flag++;
					}
					updateRRDDatabase($RRDdatabase_path, $metric->{'metric_id'}, $metric->{'metric_name'}, $data->{'ctime'}, $data->{'value'});				
				}
				undef($sth4);
				# -----------------------------------------------------
			}
		}
		undef($interval);
		undef($sth3);
		$sth = $con_ods->prepare("UPDATE index_data SET `must_be_rebuild` = '0' WHERE id = '".$svc_mst_be_rbld->{'id'}."'");
		writeLogFile("Error when getting perfdata file : " . $sth->errstr . "\n") if (!$sth->execute);
		undef($sth);
		undef($cpt);
		undef($metric);
	}
	$sth2->finish();
	undef($flag);
	undef($svc_mst_be_rbld);
	undef($sth2);
	undef($data);
	if (defined($con_oreon)){
		$con_oreon->disconnect();
    }
    if (defined($con_ods)){
     	$con_ods->disconnect();
    }
}

# here make statistics
my ($lineReadpermin, $valueRecordedpermin, $lastlineRead, $lastvalueRecorded);
$lastlineRead = 0;
$lastvalueRecorded = 0;

my $pid  = 0;
my $timeParser = time();
my $timePurge = time();
my $timeSynchro = time();
my $timeRebuild = time();

my $flagParser = 0;
my $flagPurge = 0;
my $flagSynchro = 0;
my $flagRebuild = 0;

$stop = 1;

my @tabPID;

# Init Proc table
my %tabProc;
$tabProc{'parser'} = 0;
$tabProc{'purge'} = 0;
$tabProc{'synchro'} = 0;
$tabProc{'rebuild'} = 0;

sub killProc($){
#	my $str = " - ". $_[0]." ->";
	if ($_[0]){
		if (waitpid($_[0], WNOHANG)){
#			print $str."0\n";
			return 0;
		} else {
#			print $str.$_[0]."\n";
			return $_[0];
		}	
	}
}

if ($pid ne fork()) {
	  if (!fork()) {
	  	
	  	# Starting ODS Engine
		writeLogFile("Starting ODS engine...\n");
		writeLogFile("PID : ".$$."\n");
		
		# Writing PID
		open (PID, ">> ".$PID) || print "can't write PID : $!";
		print PID $$ ;
		close PID or warn $!;
	    my $i = 0;
	    while ($stop){
	    	if (time() - $timeParser >= 30 && !$tabProc{'parser'}){
            	my $timeP = time() - $timeParser;
	            $tabProc{'parser'} = fork();
	            if (!$tabProc{'parser'}){
                	GetPerfData();
	                exit();
	            } else {
	               	my $id = waitpid($tabProc{'parser'}, WNOHANG);
	            }
	        	$timeParser = time();
            }
            if (time() - $timePurge >= 600 && !$tabProc{'purge'}){
                $tabProc{'purge'} = fork();
                if (!$tabProc{'purge'}){
                    writeLogFile("Begin MySQL Purge...\n");
                    purgeMysqlData();
                    writeLogFile("End of MySQL Purge...\n");
                    exit();
                } else {
	                my $id = waitpid($tabProc{'purge'}, WNOHANG);
                }
       	        $timePurge = time();
        	}
        	
            if (time() - $timeSynchro >= 60 && !$tabProc{'synchro'}){
           		$tabProc{'synchro'} = fork();
		        if (!$tabProc{'synchro'}){
    	         	CheckRestart();
                    exit();
	            } else {
		           my $id = waitpid($tabProc{'synchro'}, WNOHANG);
	            }
		        $timeSynchro = time();
	       	}
            if (time() - $timeRebuild >= 120 && !$tabProc{'rebuild'}){
	        	$tabProc{'rebuild'} = fork();
	            if (!$tabProc{'rebuild'}){
	            	CheckRebuild();
		            exit();
	            } else {
		          	my $id = waitpid($tabProc{'rebuild'}, WNOHANG);
	            }
	            $timeRebuild = time();
           	}
           	
			$tabProc{'parser'} = killProc($tabProc{'parser'}) if ($tabProc{'parser'});
			$tabProc{'purge'} = killProc($tabProc{'purge'}) if ($tabProc{'purge'});
			$tabProc{'synchro'} = killProc($tabProc{'synchro'}) if ($tabProc{'synchro'});
			$tabProc{'rebuild'} = killProc($tabProc{'rebuild'}) if ($tabProc{'rebuild'});
			
			sleep(1);
            $i++;
        }
    	writeLogFile("Stopping ODS engine...\n");
		writeLogFile("Error When removing pid file : $!") if (!unlink($PID));
	}
    exit 0;
} 

waitpid($pid, 0);
exit(1);