#!/usr/bin/perl

use warnings;
use strict;
use DBI;

use Socket;

my $inBase = "trafstat";
my $outBase = "temp_base";

my ($user, $passwd) = ("root", "");
my ($inDbh, $inSth, $outDbh, $outSth);

my ($beginDate, $endDate);
my $count = 0;
my $curYear = 1900 + (localtime)[5];

$inDbh = DBI->connect("DBI:mysql:host=localhost;database=$inBase",
	$user, $passwd, {PrintError => 1, RaiseError => 1}) or
		die("Connect to database '$inBase' failed: $DBI::errstr");
$outDbh = DBI->connect("DBI:mysql:host=localhost;database=$outBase",
	$user, $passwd, {PrintError => 1, RaiseError => 1}) or
		die("Connect to database '$outBase' failed: $DBI::errstr");

# выгрузим активный трафик за прошедшие 30 дней
my ($d, $m, $y) = (localtime(time() - 30 * 24 * 60 * 60))[3..5];
$beginDate = "" . ($y + 1900) . "-" . ($m + 1) . "-$d";

print "Processing period '$beginDate\:\:current': ";

$inSth = $inDbh->prepare("select date, srcIp, dstIp, dstPort, pId, inBytes, outBytes
	from traffic where `date` > ?");
$outSth = $outDbh->prepare("insert into traffic_cur
	(date, srcIp, dstIp, dstPort, pId, inBytes, outBytes)
	values(?, ?, ?, ?, ?, ?, ?)");

$inSth->execute($beginDate);
while (my ($date, $srcIp, $dstIp, $dstPort, $pId, $inBytes, $outBytes) = $inSth->fetchrow_array()) {
	$outSth->execute($date, $srcIp, $dstIp, $dstPort, $pId, $inBytes, $outBytes);
	$count++;
}
$inSth->finish();

print "precessed $count\n\n";

# запрос считывающий информацию о трафике
$inSth = $inDbh->prepare("select date, srcIp, dstIp, dstPort, pId, inBytes, outBytes
	from traffic where `date` >= ? and date < ?");

# получим самый удаленный год хранящийся в базе с трафиком
my $minYear = $inDbh->selectrow_array('select date_format(min(date), "%Y") as `date` from traffic');

# переберем все года
while ($minYear <= $curYear) {

	# создадим таблицу в которой будут храниться данные за этот год
	my $tabName = "traffic_${minYear}";
	# добавим запись о создаваемой таблице
	$outDbh->do("insert into list_traffic values($minYear)");
	# создадим саму таблицу в которой будет храниться трафик
	$outDbh->do("create table $tabName (
		`date` date not null,
		`srcIp` int unsigned not null,
		`dstIp` int unsigned not null,
		`dstPort` int not null,
		`pId` tinyint not null,
		`inBytes` int unsigned not null,
		`outBytes` int unsigned not null,
		key `key1` (`date`),
		key `key2` (`srcIp`, `date`)
		) engine = MyISAM");

	# создадим указатель для добавления данных в таблицу
	$outSth = $outDbh->prepare("insert into $tabName
		(date, srcIp, dstIp, dstPort, pId, inBytes, outBytes)
		values(?, ?, ?, ?, ?, ?, ?)");

	# переберем все месяца
	my $mon = 1;
	while ($mon <= 12) {
		my $tmp = $count;
		$beginDate = "$minYear-$mon-1";

		# Получим текущее число, если выгружается текущий месяц то
		# конечная дата будет сегодняшнее число.
		($d, $m, $y) = (localtime)[3..5];
		$m++; $y += 1900;
		last if $mon > $m;

		if ($minYear == $y && $mon == $m) {
			# Так как скрипт 'trafarch.pl' выгрузки текущего трафика в архивные таблицы
			# будет выгружать данные за сегодняшний день, то скоректируем конечную
			# дату так, что бы трафик за сегоднешний день не выгружался.
			# Эти данные автаматически попадут потом в архивную таблицу
			# при запуске 'trafarch.pl'.
			$endDate = sprintf("%04d-%02d-%02d", $y, $m, $d);
		} else {
			$endDate = ($mon == 12) ? ($minYear + 1) . "-1-1" : "$minYear-" . ($mon + 1) . "-1";
		}

		print "Processing period '$beginDate\:\:$endDate': ";

		# получим данные за выбранный месяц
		$inSth->execute($beginDate, $endDate);
		while (my ($date, $srcIp, $dstIp, $dstPort, $pId, $inBytes, $outBytes) = $inSth->fetchrow_array()) {
			# округлим значение времени до одного месяца
			my ($y, $m) = $date =~ /^(\d+)-(\d+).+/;
			$date = "$y-$m-1";

			# добавим трафик у уже имеющемуся в базе
			my $rv = $outDbh->do("update $tabName set inBytes = inBytes + $inBytes, outBytes = outBytes + $outBytes
				where date = '$date' && srcIp = '$srcIp' && dstIp = '$dstIp' && dstPort = '$dstPort' && pId = '$pId'");

			# если в базе еще нет записи о данном трафике, то добавим ее
			if ($rv eq "0E0") {
				$outSth->execute($date, $srcIp, $dstIp, $dstPort, $pId, $inBytes, $outBytes);
			} elsif ($rv > 1) {
				die("When add data to the database updated more than one record ($rv).");
			}
			$count++;
		}
		$inSth->finish();

		print "processed " . ($count - $tmp) . "\n";

		$mon++;
	}

	# покажем статистику
	print "Total processed $count records\n\n";

	$minYear++;
}

# сохраним дату последней выгрузки данных
($d, $m, $y) = (localtime)[3..5];
$m++; $y += 1900;
$outDbh->do("update config set value = '$endDate' where name = 'last_unload_to_archive'")
	or die("Failed update data: " . $outDbh->errstr . "\n");

$inDbh->disconnect();
$outDbh->disconnect();

# преобразует строковое представление IP адреса в цифровое
sub ip2long {
	return unpack("L*", pack("N*", unpack("L*", inet_aton(shift))));
}

# преобразует цифровое представление IP адреса в строковое
sub long2ip {
	return inet_ntoa(pack("N*", shift));
}
