package Yaala::Parser;

use strict;
use warnings;
use vars qw(%DATAFIELDS);

use Exporter;
use Yaala::Parser::WebserverTools qw(%MONTH_NUMBERS);
use Yaala::Data::Persistent qw#init#;
use Yaala::Config qw#get_config#;

@Yaala::Parser::EXPORT_OK = qw(parse extra %DATAFIELDS);
@Yaala::Parser::ISA = ('Exporter');

our $LASTDATE = init ('$LASTDATE', 'scalar');
our $EXTRA = init ('$EXTRA', 'hash');

if (!$$LASTDATE) { $$LASTDATE = 0; }
if (!defined ($EXTRA->{'total'})) { $EXTRA->{'total'} = 0; }
if (!defined ($EXTRA->{'days'} )) { $EXTRA->{'days'}  = {}; }

%DATAFIELDS = (
	host	=> 'key:host',
	user	=> 'key',
	date	=> 'key:date',
	hour	=> 'key:hour',
	tld	=> 'key',
	file	=> 'key',
	status	=> 'key:numeric',
	bytes	=> 'agg:bytes',
	requests => 'agg'
);

# This needs to be done at runtime, since Data uses Setup which relies on
# %DATAFIELDS to be defined  -octo
require Yaala::Data::Core;
import Yaala::Data::Core qw#store#;

my $VERSION = '$Id: Common.pm,v 1.14 2003/12/07 14:56:38 octo Exp $';
print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);

return (1);

sub parse
{
	my $line = shift or return undef;
	if ($line =~ /^(\S+) (\S+) (\S+) \[([^\]]+)\] "([^"]+)" (\d+) (\d+|-)$/)
	{
		my ($host, $ident, $user, $date, $request, $status, $bytes) =
			($1, $2, $3, $4, $5, $6, $7);

		my ($day, $month, $year, $hour, $minute, $second) =
			$date =~ m#(\d\d)/(\w{3})/(\d{4}):(\d\d):(\d\d):(\d\d)#;
		
		$month = $MONTH_NUMBERS{$month};
		$date = sprintf("%04u-%02u-%02u", $year, $month, $day);

		{
			my $tmp = int (sprintf ("%04u%02u%02u%02u%02u%02u",
					$year, $month, $day, $hour, $minute, $second));
			
			if ($tmp < $$LASTDATE)
			{
				print STDERR $/, __FILE__, ": Skipping.. ($tmp < $$LASTDATE)" if ($::DEBUG & 0x0200);
				return (undef);
			}
			else { $$LASTDATE = $tmp; }
		}
		
		my ($method, $file, $params);
		if ($request =~ m#(\S+) ([^ \?]+)\??(\S*)#)
		{
			$method = $1;
			$file = $2;
			$params = (defined ($3) ? $3 : '');
		}
		else
		{
			print STDERR $/, __FILE__, ": Malformed request: ``$request''." if ($::DEBUG);
			return (0);
		}
		
		if (($user ne '-') and ($status >= 400) and ($status < 500))
		{
			$user = '*INVALID*';
		}

		if ($user eq '-') { $user = '*UNKNOWN*'; }
		if ($bytes eq '-') { $bytes = 0; }

		my $tld;
		if ($host =~ m/\.([a-z]{2,})$/i)
		{
			$tld = lc ($1);
		}
		else
		{
			$tld = '*UNRESOLVED*';
		}

		$EXTRA->{'total'}++;
		$EXTRA->{'days'}{$date}++;

		my %combined = (
					'host'		=>	$host,
					'user'		=>	$user,
					'date'		=>	$date,
					'hour'		=>	$hour,
					'tld'		=>	$tld,
					'file'		=>	$file,
					'status'	=>	$status,
					'bytes'		=>	$bytes,
					'requests'	=>	1
				);
		store (\%combined);
	}
	elsif ($::DEBUG)
	{
		chomp ($line);
		print STDERR $/, __FILE__, ": Unable to parse: '$line'";
	}
}

sub extra
{
	my ($average, $days) = (0, 0);
	
	$days = scalar (keys (%{$EXTRA->{'days'}}));

	return (0) unless ($days);
	
	$average = sprintf ("%.1f", ($EXTRA->{'total'} / $days));

	$::EXTRA->{'Total requests'} = $EXTRA->{'total'};
	$::EXTRA->{'Average requests per day'} = $average;
	$::EXTRA->{'Reporting period'} = "$days days";
}
