#!/usr/bin/perl
use strict;
use warnings;

my $input = "";
my $output = "";
my $p = 2;
my %count;
my %ref;
my %hash_lib;
my %l_count;
my @soma;
my @sentences;
my $pref_name = "tag_";
my $digit = 4;
my $runtype = "kemp";

my $version = 0.41;
my $vname = "kempbasuShell.pl";

if (!$ARGV[0] || $ARGV[0] eq "-h") {
	print  	"\n\t-i <FILE> \t:: configuration file [default:STDIN]\n",
	"\t-o <FILE> \t:: output file name [default:STDOUT]\n",
	"\t-p <integer>\t:: number of threads to use (1 for each processor) [default=$p]\n",
	"\t-n <NAME>   \t:: prefix name of the tags (tag name= <NAME><NUMBER>) [default=$pref_name]\n",
	"\t-d <integer>   \t:: number of digits in the tag name counter (tag name= <NAME><NUMBER>) [default=$digit]\n",
	"\t-B       \t:: use Basu instead Kemp to calculate library correlation(Slower)\n",
	"\t-h      \t:: display help information\n",
	"\t-v      \t:: display current version\n",
	"\n\t$vname Version $version\n\n";
	exit;
}

if ($ARGV[0] eq "-v") {
	print ("\n\t$vname Version $version\n\n");
	exit;
}

#
#first read command line to collect arguments
#
while (my $args = shift(@ARGV)) {
	if ($args eq "-i") {
		if ($args = shift(@ARGV)) {
			$input = $args;
		}
		else {
			print STDERR "CONFIGURATION FILE NOT SPECIFIED!\n";
			exit;
		}
	}
	elsif ($args eq "-o") {
		if ($args = shift(@ARGV)) {
			$output = $args;
		}
		else {
			print STDERR "OUTPUT FILE NOT SPECIFIED!\n";
			exit;
		}
	}
	elsif ($args eq "-n") {
		if ($args = shift(@ARGV)) {
			$pref_name = $args;
		}
		else {
			$pref_name = "";
		}
	}
	elsif ($args eq "-d") {
		if ($args = shift(@ARGV)) {
			$digit = $args;
		}
		else {
			print STDERR "DIGIT NUMBER INVALID!\n";
			exit;
		}
	}
	elsif ($args eq "-B") {
		$runtype = "basu";
	}

	elsif ($args eq "-p") {
		if ($args = shift(@ARGV)) {
			$p = $args;
		}
		else {
			print STDERR "NUMBER OF THREADS NOT SPECIFIED!\n";
			exit;
		}
	}
}


if ($input) {
	open INPUT, "<$input" or die "Could not open $input\n$!\n";
	$input = "<INPUT>";
}
else {
	$input = "<>";
}

my $k = 0;


while (my $in = eval($input)) {
	chomp ($in);
	if (!$in) {
		next;
	}

	#
	#Indentify sentence by the '#' ponctuation adter the reference name
	#
	if ($in =~ m/:/) {
		(my $name, my $sent) = split (/:/, $in);
		$name = &clean ($name);
		$sent = &clean ($sent);

		my @sentence;
		if ($sent=~ m/\*/) {
			@sentence = split (/\s*\*\s*/, $sent);
		}
		else {
			print STDERR "WARNING: Invalid sentence!: [$sent]\n";
			next;
		}

		my %hash_clear;
		%count = %hash_clear;
		@soma = ();

		my $n = 0;
		$k++;

		if (!$name) {
			$name = "sentence".$k;
		}

		foreach my $case (@sentence) {
			my @splitted = split (/\s*\+\s*/, $case);
			my $end = shift (@splitted);

			if (!defined $hash_lib{$end}) {
				print "ERROR: $end library not defined!\n";
				exit(1);
			}

			$n++;

			while (@splitted) {
				my $next = shift (@splitted);

				if (!defined $hash_lib{$end.$next}) {
					&join_hash($end, $next);
				}
				$end .= $next;
			}
			%l_count = %{$hash_lib{$end}};
			&addCount ($n);
		}

		my $lines = keys (%count);

		open TEMP, ">$name" or die "Could not open $name: $!\n";
		open TEMPERR, ">$name"."_tags" or die "Could not open $name"."_tags: $!\n";

		print TEMP ($lines + 1, " $n\n");
		print TEMP ("@soma \n");

		foreach my $key (sort (keys (%count))) {
			print TEMP ("@{$count{$key}}\n");
			print TEMPERR ("$key\n");
		}

		push (@sentences, $name);

		print ("Processing sequence: [$name]...\n$runtype.bin -n $p $name 2> $name", "_$runtype","_err\n\n");
		system ("$runtype.bin -n $p $name"." 2> $name"."_$runtype"."_err");

		close TEMP;

	}

	#
	#Add reference to the hash
	#
	else {
		(my $name, my $ref) = split (/\s+=\s+/, $in);
		if (!$ref) {
			($name, $ref) = split (/\s*=\s*/, $in);
			if (!$ref) {
				($name, $ref) = split (/\s+/, $in);
				if (!$ref) {
					print STDERR "WARNING: Invalid reference!: [$in]\n";
					next;
				}
			}
		}

		$name = &clean ($name);
		$ref = &clean ($ref);

		if (exists $ref{$name}) {
			print STDERR "WARNING: $name already defined [$name:=$ref{$name}]. Substituting...\n"; 
		}
		$ref{$name} = $ref;
		&read_lib ($ref, $name);
	}
}

close INPUT;


my %hash_clear;
%count = %hash_clear;
my $n = 0;


foreach my $sentence (@sentences) {
	open KFILE, "<$sentence"."-$runtype" or die "COULD NOT FIND $sentence"."-$runtype!\n$!\n";
	open TFILE, "<$sentence"."_tags" or die "COULD NOT FIND $sentence"."_tags!\n$!\n";

	$n++;

	my %pvhash;

	<KFILE>;
	while (defined (my $line = <KFILE>) && defined (my $tag = <TFILE>)) {
		chomp $tag;
		(my $pv) = split (/\t/, $line);
		$pvhash{$tag} = $pv;
	}

	%l_count = %pvhash;
	&addCount ($n);


	close KFILE;
	close TFILE;
}

if ($output) {
	open OUTPUT, ">$output" or die "Could not open $output\n$!\n";
}

my @sortRef = sort (keys (%ref));

&printout ("tag name,sequence");
foreach my $lib (@sortRef) {
	&printout (",$lib");
}
foreach my $sentence (@sentences) {
	&printout (",$sentence");
}
&printout ("\n");

my $name_c = 1;

foreach my $key (sort (keys (%count))) {
	my $pr = sprintf ("%0$digit"."d", $name_c++);
	&printout ($pref_name,"$pr,$key");
	foreach my $lib (@sortRef) {
		if (defined $hash_lib{$lib}{$key}) {
			&printout (",$hash_lib{$lib}{$key}");
		}
		else {
			&printout (",0");
		}
	}
	foreach my $count (@{$count{$key}}) {
		&printout (",$count");
	}
	&printout ("\n");
}



sub addCount {
	my $readed = shift;

	my @ckeys = sort (keys (%count));
	my @rkeys = sort (keys (%l_count));

	my $soma = 0;

	my $i = 0;
	my $j = 0;

	my $ii = @rkeys;
	my $jj = @ckeys;

	while ($i < $ii && $j < $jj) {
		my $rkey = $rkeys[$i];
		my $ckey = $ckeys[$j];

		if ($rkey gt $ckey) {
			push (@{$count{$ckey}}, 0);
			$j++;
		}
		elsif ($rkey lt $ckey) {
			for (my $k = 1; $k < $readed; $k++) {
				push (@{$count{$rkey}}, 0);
			}
			push (@{$count{$rkey}}, $l_count{$rkey});
			$soma += $l_count{$rkey};
			$i++;
		}
		else {
			push (@{$count{$rkey}}, $l_count{$rkey});
			$soma += $l_count{$rkey};
			$i++;
			$j++;
		}
	}


	while ($i < $ii) {
		for (my $k = 1; $k < $readed; $k++) {
			push (@{$count{$rkeys[$i]}}, 0);
		}
		push (@{$count{$rkeys[$i]}}, $l_count{$rkeys[$i]});
		$soma += $l_count{$rkeys[$i]};
		$i++;
	}
	while ($j < $jj) {
		push (@{$count{$ckeys[$j]}}, 0);
		$j++;
	}

	push (@soma, $soma);
}

sub read_lib {
	my $file = shift;
	my $ref = shift;

	open OUT, "<$file" or die "COULD NOT OPEN $file!\n$!\n";

	while (my $in = <OUT>) {
		chomp $in;
		(my $tag, my $count) = split (/\s*=\s*/, $in);
		&clean ($tag);
		&clean ($in);

		$hash_lib{$ref}{$tag} = $count;
	}
}

sub join_hash {
	my $hash1 = shift;
	my $hash2 = shift;

	my $mhash = $hash1.$hash2;

	foreach my $key (keys (%{$hash_lib{$hash1}})) {
		$hash_lib{$mhash}{$key} = $hash_lib{$hash1}{$key};
	}
	foreach my $key (keys (%{$hash_lib{$hash2}})) {
		if (defined $hash_lib{$hash1}{$key}) {
			$hash_lib{$mhash}{$key} += $hash_lib{$hash2}{$key};
		}
		else {
			$hash_lib{$mhash}{$key} = $hash_lib{$hash2}{$key};
		}
	}
}

sub clean {
	my $string = shift;

	$string =~ s/^\s+//;
	$string =~ s/\s+$//;

	return $string;
}


sub printout {
	if ($output) {
		while (my $in = shift()) {
			print OUTPUT $in;
		}
	}
	else {
		while (my $in = shift()) {
			print $in;
		}
	}
}

