#!/usr/bin/perl -w
# Given a tab-delimited file with optional attributes (!Attr=Value lines at the top),
# produce an output file with an additional VIMSS column for the locus id(s) that match.
#
# Currently, matching is only implemented by synonyms, using the input column given by the
# -name attribute.
#
# Use -keepColumns 0 to report just the matching (and not the original attributes or other columns)
# Use -uniq 0 to show non-unique matches (will produce a comma-delimited list)
# Use -matchOnly 0 to keep input lines that did not match any VIMSS locus
#
use strict;
use lib "../Perl/modules";
use Gene;
use GeneMethods;
use GenomicsUtils;
use Genome;
use lib "../seq";
use Vector;
use Getopt::Long;

{
    my $usage = "matchGenes.pl -in=file -genome=Genome [-name=Name -matchOnly 1 -keepColumns 1\n"
	. "   -host=host -truncate 0 -synonymCase 0 -synonymType -1 -uniq 1 -debug 0 -usePlasmids 0 ] > outFile\n";
    my $genomeName = undef;
    my $synonymField = "Name";
    my $host = undef;
    my $synonymCase = undef;
    my $synonymType = undef;
    my $uniq = 1;
    my $file = undef;
    my $debug = 0;
    my $keepColumns = 1;
    my $matchOnly = 1;
    my $usePlasmids = 0;
    my $truncate = 0;
    (GetOptions('genome=s' => \$genomeName,
		'host=s' => \$host,
		'name=s' => \$synonymField,
		'synonymType=i' => \$synonymType,
		'synonymCase=i' => \$synonymCase,
		'in=s' => \$file,
		'uniq=i' => \$uniq,
		'debug=i' => \$debug,
		'keepColumns=i' => \$keepColumns,
		'usePlasmids=i' => \$usePlasmids,
		'matchOnly=i' => \$matchOnly,
		'truncate=i' => \$truncate)
     && @ARGV == 0) || die $usage;
    die $usage if (!defined $file) || (!defined $genomeName);
    GenomicsUtils::setDebug($debug) if $debug > 0;
    connect($host);

    my $genome = Genome::new("taxonomyId" => $genomeName);

    my ($lines, $attrs) = Vector::readXLSList($file);
    print STDERR "Read " . scalar(@{ $lines }) . " queries\n";
    my @genes = $genome->genes("preload" => ["synonym"]);
    if ($usePlasmids) {
	push @genes, $genome->nongenomicGenes("preload" => ["synonym"]);
    }
    print STDERR "Matching to " . scalar(@genes) . " genes\n";

    my @queries = ();
    # build the input to the gene matcher
    foreach my $line (@{ $lines }) {
	die "Missing field $synonymField" if !exists $line->{$synonymField};
	my $query = {};
	$query->{"synonym"} = $line->{$synonymField};
	$query->{"attrs"} = $line;
	push @queries, $query;
    }
    my $matches = GeneMethods::geneMatcher(\@queries, \@genes, { "uniq" => $uniq,
								 "synonymType" => $synonymType,
 								 "synonymCase" => $synonymCase, 
							         "truncate" => $truncate});
    print STDERR "Received " . scalar(@{ $matches}) . " matches\n";
    if ($keepColumns) {
	foreach my $attr (keys %{ $attrs }) {
	    print "!$attr=" . $attrs->{$attr} . "\n";
	}
    }
    $matches->[0]->{"attrs"}->{"VIMSS"} = 0; # a hack to get the right column names
    if ($keepColumns) {
	print join("\t", keys %{ $matches->[0]->{"attrs"} }), "\n";
    } else {
	print join("\t", "VIMSS", $synonymField ), "\n";
    }

    my @unmatched = ();

    my $nUniq = 0;
    my $nDup = 0;
    my $nUnmatched = 0;
    foreach my $match (@{ $matches }) {
	if (!$matchOnly || $match->{"success"}) {
	    my $attrs = $match->{"attrs"};
	    $attrs->{"VIMSS"} = join(",", @{ $match->{"locusIds"} } );
            if ($keepColumns) {
		print join("\t", map { $attrs->{$_} } (keys %{ $attrs }) ), "\n";
	    } else {
		print join("\t", $attrs->{"VIMSS"}, $attrs->{$synonymField}),"\n";
	    }
	}
	if (scalar @{ $match->{"nonuniq"} } > 0) {
	    print STDERR join("\t", "Nonuniq",$match->{"attrs"}->{$synonymField}, @{ $match->{"nonuniq"} }), "\n";
	}
	$nUniq++ if scalar @{ $match->{"locusIds"} } == 1 && scalar @{ $match->{"nonuniq"} } == 0;
	$nDup++ if scalar @{ $match->{"locusIds"} } > 1 || scalar @{ $match->{"nonuniq"} } >= 1;
	$nUnmatched++ if scalar @{ $match->{"locusIds"} } == 0;
	push(@unmatched, $match->{"attrs"}->{$synonymField}) if scalar @{ $match->{"locusIds"} } == 0;
    }
    print STDERR join("\t", "Unmatched", Vector::uniq(sort(@unmatched))),"\n";
    print STDERR "Matched uniquely $nUniq with-duplicates $nDup unmatched $nUnmatched\n";
}
