package PPPUsage::Query;

# provides:
#
# query ($datafile)

use strict;
use DB_File;
use Exporter;
use PPPUsage::Lib qw(xbytes format_secs usage);

use vars qw(@EXPORT @ISA);

@ISA    = qw(Exporter);
@EXPORT = qw(query);

# -----> query ($datafile)
#
# Queries $datafile. The value of $opt_t is parsed to see whether the
# relevant timeframe is specified (if not, simply all available data
# is used). Returns pointers to %sum, @months, and %mm_sums.
#
sub query {

	my $datafile = shift;
	my $me       = $main::me;

	my ($i,$s,$f_date,$l_date,$ret);
	my (%sum,%mm_sums,@months);

	my %DB;

	# tie %DB to a Berkeley DB HASH in $datafile (opened read only)

	tie(%DB, 'DB_File', $datafile, O_RDONLY)
		or die "$me: Can't tie Hash \"\%DB\" to $datafile (try `-c'): $!\n";

	(defined $DB{'connects'} && defined $DB{'years'} && $DB{'thisyear'})
		or die "$me: Database in $datafile not okay (try `-c')\n";

	$i = $sum{'connects'}
	   = $sum{'secs'}
	   = $sum{'ly'}
	   = $sum{'lm'}
	   = $sum{'i'}
	   = $sum{'o'}
	   = 0;

	# if $opt_t is set, get timeframe by setting $i (the first
	# connection to be parsed), $s (the last connection to be
	# parsed), $f_date and $l_date appropriately

	if ($main::opt_t) {

		my ($opty,$reggy);

		if ($main::opt_t =~ /-/) {

			my ($first,$last,$tmp_f,$tmp_l);

			usage(1) unless ($main::opt_t =~ /^(\d{4,8})-(\d{4,8})$/);

			# if a time range has been specified by using
			# `-t <date>-<date>', save <firstdate>-<lastdate>
			# in $opty

			for (($tmp_f,$tmp_l)=($first=$1,$last=$2)) {
				$_.='0000' if /^\d{4}$/;
				$_.='00'   if /^\d{6}$/;
			}
			$opty  = ($tmp_f>$tmp_l) ? "$last-$first" : "$first-$last";
			$reggy = '^(\d{4})(\d{2})?(\d{2})?-(\d{4})(\d{2})?(\d{2})?$';

		} else {

			$opty  = $main::opt_t;
			$reggy = '^(\d{4})(\d{2})?(\d{2})?$';
		}

		if ($opty =~ /$reggy/) {

			my ($l_year,$l_mon,$l_day);

			my $f_year = $DB{'years'}-($DB{'thisyear'}-$1);
			my $f_mon  = $2 ? $2 : '01';
			my $f_day  = $3 ? $3 : '01';

			usage(1) if (($f_mon > 12) || ($f_day > 31));

			# if $4 is set, a time range has been specified by
			# using `-t <date>-<date>', else, we're looking at
			# `-t <date>'

			if ($4) {

				$l_year = $DB{'years'}-($DB{'thisyear'}-$4);
				$l_mon  = $5 ? $5 : '12';
				$l_day  = $6 ? $6 : '31';

				usage(1) if (($l_mon > 12) || ($l_day > 31));

			} else {

				$l_year = $f_year;
				$l_mon  = $2 ? $f_mon : '12';
				$l_day  = $3 ? $f_day : '31';
			}

			$i = ($2)     ? $DB{"$f_year-$f_mon-start"} : $DB{"$f_year-start"};
			$s = ($2||$5) ? $DB{"$l_year-$l_mon-end"}   : $DB{"$l_year-end"};
			$f_date = $DB{'thisyear'}-$DB{'years'}+$f_year.$f_mon.$f_day;
			$l_date = $DB{'thisyear'}-$DB{'years'}+$l_year.$l_mon.$l_day;

		} else {

			usage(1);
		}
	}

	defined($i) or $i = $DB{'0-start'};
	defined($s) or $s = $DB{'connects'} - 1;

	# main read loop

	for(;$i<=$s;$i++) {

		my ($i_in,$i_out,$i_year,$i_month,$i_day,$i_secs,$i_date);

		$DB{$i} =~ /^(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)$/
			or die "$me: Database in $datafile not okay (try `-c')\n";

		$i_year  = $DB{'thisyear'}-$DB{'years'}+$1;
		$i_month = $2;
		$i_day   = $3;
		$i_secs  = $4;
		$i_in    = $5;
		$i_out   = $6;

		# *urgs*, why didn't we add the `0' in Parse.pm?

		$i_day   =~ s/^(\d)$/0$1/;
		$i_date  = $i_year.$i_month.$i_day;

		if (!$main::opt_t || (($f_date <= $i_date) && ($i_date <= $l_date))) {

			if ($sum{'connects'} == 0) {

			# if it's the first turn, save the date

				$sum{'fy'} = $i_year;
				$sum{'fm'} = $i_month;
				$sum{'fd'} = $i_day;
			}

			$sum{'i'}    += $i_in;
			$sum{'o'}    += $i_out;
			$sum{'secs'} += $i_secs;

			# we could use Tie::IxHash instead of maintaining
			# the @months list, but we're still trying to get
			# by with default modules

			push (@months, "$i_year-$i_month")
				if ("$i_year-$i_month" ne "$sum{'ly'}-$sum{'lm'}");

			$mm_sums{$months[$#months]} += $i_in+$i_out;
			$sum{'connects'}++;

			# save the date as "last" y/m/d

			$sum{'ly'} = $i_year;
			$sum{'lm'} = $i_month;
			$sum{'ld'} = $i_day;
		}
	}

	untie %DB;

	die "$me: No connections logged on $main::opt_t\n" unless $sum{'connects'};

	$sum{'t'} = $sum{'i'} + $sum{'o'};

	# convert in, out and total sums to kb, mb, gb

	($sum{'i_k'}, $sum{'i_m'}, $sum{'i_g'}) = xbytes($sum{'i'});
	($sum{'o_k'}, $sum{'o_m'}, $sum{'o_g'}) = xbytes($sum{'o'});
	($sum{'t_k'}, $sum{'t_m'}, $sum{'t_g'}) = xbytes($sum{'t'});

	# format online time (connection average and total)

	$sum{'time_c'} = format_secs(sprintf("%d", $sum{'secs'}/$sum{'connects'}));
	$sum{'time_t'} = format_secs($sum{'secs'});

	if (@months > 1) {

		# $sum{'t'}/@months may of course be not precise if your
		# not querying full months

		$sum{'m_av'} = $sum{'t'} / @months;
		($sum{'m_av_k'}, $sum{'m_av_m'}, $sum{'m_av_g'}) = xbytes($sum{'m_av'});
	}

	return (\%sum, \@months, \%mm_sums);
}

1;
