package PB::Log;

# this class can be used to store and analyze the complete log from pb
# this includes more than one vm

use strict;
use Mail::Sendmail;
use PB::Log::Item;

sub new {
	# contains the object name (here PBLog)
	my $object = shift;
	my $self = {};
	# $self should point to an object of type $object
	bless($self, $object);
	
	# this array stores our childs
	$self->{'logitems'} = [];

	return($self);
}

# returns number of handled PB::Log::Item's
sub countItems {
	my $self = shift;
	return scalar(@{$self->{'logitems'}});
}

# returns an array of all names of handled PB::Log::Item's
# the name is the vm name (e.g. ubuntu-10.04-i386 (by default))
sub itemNames {
	my $self = shift;
	my @result = ();
	foreach my $item (@{$self->{'logitems'}}){
		push(@result, $item->name());
	}
	return @result;
}

# set's the log for PB::Log::item $vmname
# if such an item is not present, one is added
# $log should only contain the log of one machine
sub setLog {
	my $self = shift;
	my $vmname = shift;
	my $log = shift;
	
	my $logitem = $self->findItem($vmname);
	if(!$logitem){
		$logitem = new PB::Log::Item($vmname);
		push(@{$self->{'logitems'}}, $logitem);
	}
	$logitem->setLog($log);
}

# used to analyze the complete log of pb
sub setCompleteLog {
	my $self = shift;
	my $log = shift;
	
	my $tmplog;
	my $item;
	foreach my $line (split("\n", $log)){
		if($line =~ m/^Waiting [0-9]+ s for VM/){
			# here starts a new machine, so append the tmplog to the last one
			if(defined($item)){
				$item->setLog($tmplog);
			}
			if($line =~ m/VM ([^\s]+)/){
				$item = new PB::Log::Item($1);
				push(@{$self->{'logitems'}}, $item);
				$tmplog = 0;
			}
		}
		else{
			$tmplog .= $line ."\n";
		}
	}
	if(defined($item) && ($tmplog)){
		$item->setLog($tmplog);
	}
}

# nums the issues (Warnings and Errors from lintian and rpmlint
# if no name is given, the total of all PB::Log::Item's is returned
sub numQaIssues {
	my $self = shift;
	my $itemname = shift || "";
	my $result = 0;
	if($itemname eq ""){
		# no machine selected, so return combine from all items
		foreach my $item (@{$self->{'logitems'}}){
			$result += scalar($item->qaIssues());
		}
	}
	else{
		my $item = $self->findItem($itemname);
		if($item){
			$result = $item->numQaIssues();
		}
	}
	return $result;
}

# returns the issues itself
# behaves like numQaIssues
sub qaIssues {
	my $self = shift;
	my $itemname = shift || "";
	my @result = ();
	if($itemname eq ""){
		# no machine selected, so return combine from all items
		foreach my $item (@{$self->{'logitems'}}){
			push(@result, $item->qaIssues());
		}
	}
	else{
		my $item = $self->findItem($itemname);
		if($item){
			push(@result, $item->qaIssues());
		}
	}
	return @result;
}

# same as num qaIssues but for compile errors
sub numErrors {
	my $self = shift;
	my $itemname = shift || "";

	my $result = 0;
	if($itemname eq ""){
		# no machine selected, so return combine from all items
		foreach my $item (@{$self->{'logitems'}}){
			$result += $item->numErrors();
		}
	}
	else{
		my $item = $self->findItem($itemname);
		if($item){
			$result = $item->numErrors();
		}
	}
	return $result;
}

# returns the compile errors itself
# behaves like numQaIssues
sub errors {
	my $self = shift;
	my $itemname = shift || "";

	my @result = ();
	if($itemname eq ""){
		# no machine selected, so return combine from all items
		foreach my $item (@{$self->{'logitems'}}){
			push(@result, $item->errors());
		}
	}
	else{
		my $item = $self->findItem($itemname);
		if($item){
			push(@result, $item->errors());
		}
	}
	return @result;
}

# same as num qaIssues but for compile warnings
sub numWarnings {
	my $self = shift;
	my $itemname = shift || "";

	my $result = 0;
	if($itemname eq ""){
		# no machine selected, so return combine from all items
		foreach my $item (@{$self->{'logitems'}}){
			$result += $item->numWarnings();
		}
	}
	else{
		my $item = $self->findItem($itemname);
		if($item){
			$result = $item->numWarnings();
		}
	}
	return $result;
}

# returns the compile warnings itself
# behaves like numQaIssues
sub warnings {
	my $self = shift;
	my $itemname = shift || "";

	my @result = ();
	if($itemname eq ""){
		# no machine selected, so return combine from all items
		foreach my $item (@{$self->{'logitems'}}){
			push(@result, $item->warnings());
		}
	}
	else{
		my $item = $self->findItem($itemname);
		if($item){
			push(@result, $item->warnings());
		}
	}
	return @result;
}

# prints out a summary of the log
sub summary {
	my $self = shift;
	my $summary = "";
	$summary = "Items: ". $self->countItems();
	$summary .= " (QA Issues: ". $self->numQaIssues();
	$summary .= ", Warnings: ". $self->numWarnings();
	$summary .= ", Errors: ". $self->numErrors() .")\n";
	foreach my $name ($self->itemNames()){
		$summary .= $name ." (QA Issues: ". $self->numQaIssues($name);
		$summary .= ", Warnings: ". $self->numWarnings($name);
		$summary .= ", Errors: ". $self->numErrors($name) .")\n";
	}
	return $summary;
}

# mails the summary to $to
sub mailSummary {
	my $self = shift;
	my $to = shift || "";
	if($to eq ""){
		print "Please give a to address\n";
		return;
	}
	my %mail = (	To => $to,
								From => "pb\@localhost",
								Message => $self->summary()
							);
	sendmail(%mail) or return $Mail::Sendmail::error;
	print "Mail send to ". $to ."\n";
}

# private part (perl does not no about private, but it is meant so)

# find's item with name $vmname in handled OB::Log::Item's
sub findItem {
	my $self = shift;
	my $vmname = shift;
		# find existing item or add item if needed
	foreach my $logitem (@{$self->{'logitems'}}){
		if($logitem->name eq $vmname){
			return $logitem;
		}
	}
	return 0;
}

1;