#!/usr/bin/perl
# Bibliography script

use strict;
use HTML::Template;
use CGI qw(:standard escapeHTML);
use CGI::Carp qw(fatalsToBrowser);

#my $template = HTML::Template->new(filename => 'biblio.shtml', path => [ '../', '']);
my $template = HTML::Template->new(filename => 'biblio.shtml', path => [ '../html/']);

#my $in = "../biblio-data.txt";
my $in = "../html/doc/biblio-data.txt";

my %name = ( category => { 1 => "by GO", 2 => "overviews of GO", 3 => "GO annotations", 4 => "genome annotation", 5 => "EST annotation", 6 => "protein annotation", 7 => "use of GO in gene expression studies", 8 => "use of GO in proteomics studies", 9 => "prediction of GO annotations", 10 => "GO tools", 11 => "use of GO in biological databases", 12 => "use of GO in data or text mining", 13 => "other applications of GO ", 14 => "publications on biomedical ontologies mentioning GO", 15 => "publications on OBO ontologies", 16 => "use of GO in clinical applications", 17 => "use of GO in network modeling and analysis", 18 => "use of GO in comparative genomics and evolutionary analysis", 19 => "use of GO to support predictions" }, 
sort => { year => "Date, oldest first", title => "Title", author => "First author", publication => "Publication" }, 
sort2 => { year => "Date, oldest first", title => "Title", author => "First author", publication => "Publication" }, 
view => { year => "by year", category => "by category", all => "full list" }, 
show => [ "all", 10, 20, 50, 100 ]
);

my $query = new CGI;
my $qsCore = "";
my %filter;

#my $str = "";
if (!param())
{	# bibliography entry page. don't need to load data.
	# still need create pull down menus

	# read the database file
	my @data = readFile($in);
	
	$template->param(total => (scalar(@data) - 1) );

	#	create the pull down menus
	foreach ("sort", "sort2", "show", "view")
	{	$template->param($_."SelectLoop" => menuMaker($_, $filter{$_}) );
	}
	# send the obligatory Content-Type
	print "Content-Type: text/html\n\n";

	# print the template
	print $template->output;

	exit;
}
else
{	my @names = $query->param;
	foreach my $i (@names)
	{	#$str .= "key = $i; value = ".$query->param($i)."<br>";
		if ($query->param($i) ne "")
		{	$filter{$i} = $query->param($i);
			$qsCore .= "$i=$filter{$i}&amp;" unless $i eq "start";
		}
	}
}

if ($filter{oldValue} && !$filter{value} && $filter{view} ne "all")
{	$filter{value} = $filter{oldValue};
}

if ($filter{value})
{	$template->param(oldValue => $filter{value});
}

$qsCore =~ s/&amp;$//;

# read the database file
my @data = readFile($in);

chomp $data[0];

# get the names of the fields in the database
my @fields = split('\t', shift @data);
my %field;
my $temp = 0;
foreach (@fields)
{	$field{$_} = $temp;
	$temp++;
}

&HTMLdie("No database headers") if !@fields;
&HTMLdie("No data in database") if @data < 1;

$temp = 0;
my %newData = ();
my @idList = ();
foreach (@data)
{	chomp;
	my @line = split('\t', $_);
	$newData{$temp} = \@line;
	push(@idList, $temp);
	$temp++;
}

#	create the pull down menus
foreach ("sort", "sort2", "show", "view")
{	$template->param($_."SelectLoop" => menuMaker($_, $filter{$_}) );
}

#	search
if (exists $filter{search})
{	@idList = simplesearch(\@idList, $filter{search}, $filter{searchType});
	$template->param(search => 1);
	$template->param(str => $filter{search});
	$template->param(match => scalar(@idList));
}

#	browse by data type
if (exists $filter{view} && $filter{view} ne "all")
{	(my $results, my $valueList, $filter{value}) = viewList(\@idList, $filter{view}, $filter{value});

	@idList = @$results;
	$template->param(view => 1);
	$template->param(crit => $filter{view});
	if (exists $name{$filter{view}}{$filter{value}})
	{	$template->param(valueName => $name{$filter{view}}{$filter{value}});
	}
	else
	{	$template->param(valueName => $filter{value});
	}

	#generate links to the other results
	$template->param(viewLoop => viewLinks($valueList, $qsCore, $filter{view}, $filter{value}) );
}

if (@idList)
{	#sort the list
	foreach ("sort2", "sort")
	{	@idList = sortList(\@idList, $filter{$_}, $filter{$_."rev"});
		$template->param($_."Crit" => lc($name{$_}{$filter{$_}}) );
		$template->param($_."rev" => 1) if ($filter{$_."rev"});
	}

	#how many results to show
	if (exists $filter{show} && $filter{show} ne "all")
	{	# generate the links to the other results
		if (@idList > $filter{show})
		{	$template->param(showLoop => showLinks(scalar(@idList), $qsCore, $filter{show}, $filter{start}) );
		}
		# show only a subset of the results
		my ($start, $end, $results) = showList(\@idList, $filter{show}, $filter{start});
		@idList = @$results;
		$template->param(show => 1);
		$template->param(start => $start);
		$template->param(end => $end);
	}

	if (exists $filter{comments})
	{	$template->param(commentsOn => 1);
	}

	if (exists $filter{showCat})
	{	$template->param(showCatOn => 1);
	}

	if (exists $filter{linkOut})
	{	$template->param(linkOutOn => 1);
	}

	if (scalar %filter)
	{	my @dataLoop;
		$template->param(data => 1);
		foreach my $paper (@idList)
		{	my %row;

			foreach my $i (keys %field)
			{	$row{$i} = $newData{$paper}[$field{$i}] unless !$newData{$paper}[$field{$i}];
			}

			if ($row{link} && $row{link} =~ /(.*?)\|(.*)/)
			{	$row{linkUrl} = $1;
				$row{$2} = 1;
				$row{linkUrl} =~ s/\&(amp;)?/&amp;/g;
			}

			if ($row{author} =~ /(.*?)\|etAl/)
			{	$row{author} = $1;
				$row{etAl} = 1;
			}

			if ($row{issue} && $row{issue} eq "epub")
			{	$row{epub} = 1;
				delete $row{issue};
			}

			if ($newData{$paper}[$field{category}] && $filter{showCat})
			{	my @list = split(/,/, $newData{$paper}[$field{category}]);
				foreach (@list)
				{	$row{$_} = 1;
				}
#				my $catString = "";
#				foreach my $cat (@list)
#				{	$catString .= "<li>$name{category}{$cat}</li>";
#				}	
#				$row{category} = $catString;
			}
			elsif (!$filter{showCat})
			{	delete $row{category} unless (!$row{category});
			}

			if (!$filter{comments})
			{	delete $row{extra} unless (!$row{extra});
			}

			# put this row into the loop by reference
			push(@dataLoop, \%row);
		}

		# call param to fill in the loop with the loop data by reference.
		$template->param(dataLoop => \@dataLoop);
	}
}

my $total = keys %newData;

$template->param(total => $total);
# send the obligatory Content-Type
print "Content-Type: text/html\n\n";

# print the template
print $template->output;

exit;

#########################################################

# Die, outputting HTML error page
# If no $title, use a default title
sub HTMLdie {
    my ($msg, $title) = @_ ;
    $title= "CGI Error" if $title eq '' ;
    print <<EOF ;
Content-type: text/html

<html>
<head>
<title>$title</title>
</head>
<body>
<h1>$title</h1>
<h3>$msg</h3>
</body>
</html>
EOF

    exit ;
}

sub menuMaker
{	my $var = shift;
	my $filter = shift;
	if (!$filter && $var eq "sort")
	{	$filter = "year";
	}

	my @temp = ();
	if (ref($name{$var}) eq 'HASH')
	{	foreach my $i (sort keys %{$name{$var}})
		{	my $code = "<option value=\"$i\" title=\"$name{$var}{$i}\"";
			$code .= " selected" if ($filter && $filter eq $i);
			$code .= "> $name{$var}{$i} <\/option>";
			my %array = ($var."Code" => $code);
			push(@temp, \%array);
		}
	}
	else
	{	# for the 'show' variables
		foreach (@{$name{$var}})
		{	my $code = "<option value=\"$_\" title=\"display $_ results per page\"";
			$code .= " selected" if ($filter && $filter eq $_);
			$code .= "> $_ <\/option>";
			my %array = ($var."Code" => $code);
			push(@temp, \%array);
		}
	}
	return \@temp;
}

sub simplesearch
{	my $list = shift;
	my $string = shift;
	my $type = shift;
	my @results = ();

	$string =~ tr/+/ /;
	$string =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack ("C",hex($1))/eg;

	if ($type eq "exact")
	{	my $id = 0;
		foreach (@$list)
		{	if ($data[$_] =~ /$string/i)
			{	push(@results, $id);
			}
			$id++;
		}
	}
	else
	{	my @keys = split(" ", $string);
		my $id = 0;
		if ($type eq "and")
		{	foreach (@$list)
			{	my $hits = 1;
				foreach my $key (@keys)
				{	if ($data[$_] !~ /$key/i)
					{	$hits = 0;
						last;
					}
				}
				push(@results, $id) if $hits == 1;
				$id++;
			}
		}
		else
		{	foreach (@$list)
			{	foreach my $key (@keys)
				{	if ($data[$_] =~ /$key/i)
					{	push(@results, $id);
						last;
					}
				}
				$id++;
			}
		}

	}
	return @results;
}

sub sortList
{	my $list = shift;
	my $sortBy = shift;
	my $rev = shift;
	my @sorted = (sort { lc($newData{$a}[$field{$sortBy}]) cmp lc($newData{$b}[$field{$sortBy}]) } @$list);
	($rev) ? return reverse @sorted : return @sorted;
}

sub showList
{	my $list = shift;
	my $showPerPage = shift;
	my $offset = shift;
	if (!$offset)
	{	$offset = 0;
	}

	my @temp = splice(@$list, $offset, $showPerPage);
	my $end = @temp;
	$end += $offset;
	$offset++;
	return ($offset, $end, \@temp);
}	

sub viewList
{	my $list = shift;
	my $viewCategory = shift;
	my $viewValue = shift;
	my @results = ();
	my %values = ();
	
	# make an array with key = possible filter criteria and value = a list of matching ids
	foreach my $id (@$list)
	{	# if the filter is category, we need to split up the data
		if ($viewCategory eq "category")
		{	my $string = $newData{$id}[$field{$viewCategory}];
			my @temp = split(/,/, $string);
			foreach (@temp)
			{	push(@{$values{$_}}, $id);
			}
		}
		else
		{	push(@{$values{$newData{$id}[$field{$viewCategory}]}}, $id);
		}
	}
	if ($viewValue ne "" && exists $values{$viewValue})
	{	@results = @{$values{$viewValue}};
	}
	else
	{	for (sort { $a cmp $b } keys %values)
		{	@results = @{$values{$_}};
			$viewValue = $_;
			last;
		}
	}
	return (\@results, \%values, $viewValue);
}	

sub showLinks
{	my $listLength = shift;
	my $url = shift;
	my $perPage = shift;
	my $offset = shift;
	if (!$offset)
	{	$offset = 0;
	}
	my $totalPages;
	if ($listLength % $perPage == 0)
	{	$totalPages = $listLength/$perPage;
	}
	else
	{	$totalPages = ($listLength + ($perPage - ($listLength%$perPage))) / $perPage;
#		$totalPages++;
	}
	my @loop;
	my $page = 0;
	while ($page < $totalPages)
	{	my %array = (pageUrl => $url."&amp;start=".$page*$perPage);
		$page++;
		$array{page} = $page;
#		$array{page} = ((($page-1)*$perPage)+1)."-".$page*$perPage;
		if ($offset/$perPage == ($page - 1))
		{	$array{page} = "<em>$array{page}</em>";
		}
		push(@loop, \%array);
	}
	return \@loop;
}

sub viewLinks
{	my $values = shift;
	my $url = shift;
	my $cat = shift;
	my $this = shift;
	my @loop;
	
	foreach my $i (sort keys %$values)
	{	# does this need to be altered?
		$url =~ s/(&value=.*?){0,1}($|&)/&amp;value=$i$2/m;
		my %array;
		$array{viewUrl} = $url;
		if ($name{$cat}{$i})
		{	$array{viewName} = $name{$cat}{$i};
		}
		else
		{	$array{viewName} = $i;
		}
		if ($i eq $this)
		{	$array{viewName} = "<em>$array{viewName}</em>";
		}
		$array{viewNo} = scalar @{$$values{$i}};
		push(@loop, \%array);
	}
	return \@loop;
}

sub readFile
{	open(FH, $_[0]) or die "Can't open file $_[0]!";
	my @data = <FH>;
	close FH;
	return @data;
}
