#!/usr/bin/env perl
use strict;
use File::Basename;
use Cwd qw(realpath);

my $TAUROOT="@TAUROOTDIR@";
my $TAUARCH="@ARCH@";
my $BASEDIR="$TAUROOT/$TAUARCH";
my $SICORTEX="no";
my $PREFIX="no";
my $DEFAULT_MAKEFILE="";
my $DEFAULT_BINDING="";

my $TauOptions="";
my $TauOptionsExclude="";

my $listmatching="false";
my $makefile="false";
my $getbinding="false";
my $ProfileSpecified="false";
my $TraceSpecified="false";
my $DisableSpecified="false";
my $SerialSpecified="false";
my $MPISpecified="false";
my $listoptions="false";


sub trim($)
  {
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
  }


if (@ARGV == 0) {
    print "TAUROOT=$TAUROOT\n";
    print "TAUARCH=$TAUARCH\n";
    print "BASEDIR=$BASEDIR\n";
    print "SICORTEX=$SICORTEX\n";
    print "PREFIX=$PREFIX\n";
    print "DEFAULT_MAKEFILE=$DEFAULT_MAKEFILE\n";
    print "DEFAULT_BINDING=\"$DEFAULT_BINDING\"\n";
    exit 0
}

# process command line arguments
foreach my $argnum (0 .. $#ARGV) {
    my $arg = $ARGV[$argnum];
    if ($arg eq "profile") {
        $ProfileSpecified="true";
    } elsif ($arg eq "trace") {
        $TraceSpecified="true";
    } elsif ($arg eq "vampirtrace") {
        $TraceSpecified="true";
        $TauOptions="$TauOptions $arg";
    } elsif ($arg eq "epilog") {
        $TraceSpecified="true";
	$TauOptions="$TauOptions $arg";
    } elsif ($arg eq "disable") {
        $DisableSpecified="true";
    } elsif ($arg eq "--list-matching") {
        $listmatching="true";
    } elsif ($arg eq "--makefile") {
        $makefile="true";
    } elsif ($arg eq "--list-options") {
        $listoptions="true";
    } elsif ($arg eq "--binding") {
        $getbinding="true";
    } elsif ($arg eq "serial") {
        $SerialSpecified="true";
    } elsif ($arg eq "mpi") {
        $MPISpecified="true";
	$TauOptions="$TauOptions $arg";
    } else {
	$TauOptions="$TauOptions $arg";
    }
}


# if neither profiling or tracing is specified, assume profiling
if ($ProfileSpecified eq "false" && $TraceSpecified eq "false") {
    $ProfileSpecified="true";
}

# if serial is specified, exclude all mpi builds
if ($SerialSpecified eq "true") {
    $TauOptionsExclude="mpi";
}

# if neither mpi or serial is specified, assume mpi
if ($MPISpecified eq "false" && $SerialSpecified eq "false") {
    $TauOptions="$TauOptions mpi";
}

if ($ProfileSpecified eq "true" && $TraceSpecified eq "false") {
    # exclude trace
    $TauOptionsExclude="$TauOptionsExclude trace";
} elsif ($ProfileSpecified eq "true" && $TraceSpecified eq "true") {
    # require both
    $TauOptions="$TauOptions profile trace"
} elsif ($ProfileSpecified eq "false" && $TraceSpecified eq "true") {
    # exclude profile, require trace
    $TauOptionsExclude="$TauOptionsExclude profile";
    $TauOptions="$TauOptions trace";
}

if ($DisableSpecified eq "false") {
    # exclude disable if not specified
    $TauOptionsExclude="$TauOptionsExclude disable";
} else {
    # exclude was specified
    $TauOptions="";
}

my $bindingsdir;
my @bindings;

if ($makefile eq "true") {
    # we are searching for makefiles
    if ("$SICORTEX" eq "yes") {
	$bindingsdir="$PREFIX/lib64";
	@bindings=`ls $PREFIX/share/TAU/64/Makefile.tau*`;
    } else {
	$bindingsdir="$BASEDIR/lib";
	@bindings=`ls $bindingsdir/Makefile.tau*`
    }
} else {
    # we are searching for shared library bindings directories
    if ("$SICORTEX" eq "yes") {
	$bindingsdir="$PREFIX/lib64";
	@bindings=`ls $PREFIX/lib64 | grep TAU-shared`;
    } else {
	$bindingsdir="$BASEDIR/lib";
	@bindings=`ls $BASEDIR/lib | grep shared`;
    }
}

chomp(@bindings);

if ($listoptions eq "true") {
    # list the available options, then quit

    # process the list of bindings, split on "-" and add to a hash 
    # (to avoid duplicates)
    my %options;
    foreach my $b (@bindings) {
	my @opts = split ('-',$b);
	foreach my $o (@opts) {
	    $options{$o} = 1;
	}
    }

    # don't print 'shared' or 'opari'
    delete $options{"shared"};
    delete $options{"opari"};

    # always print 'profile' and 'serial'
    $options{"profile"} = 1;
    $options{"serial"} = 1;

    my @keys = keys(%options);
    @keys = sort @keys;
    map{$_ = uc($_)} @keys;
    $"=","; # sets delimeter to comma for printing arrays
    print "@keys\n";
    $"=" "; # set it back to space
    exit
}

# process included options
my @opts = split(" ", $TauOptions);
foreach my $opt (@opts) {
    # for each option, search the bindings for matches
    my $newbindings="";
    foreach my $b (@bindings) {
	my $proc="-$b-";
	if ($proc =~ /-$opt-/) {
	    $newbindings="$newbindings $b";
	}
    }
    @bindings=split(" ",$newbindings);
}

# process excluded options
my @opts = split(" ", $TauOptionsExclude);
foreach my $opt (@opts) {
    # for each option, search the bindings for matches
    my $newbindings="";
    chomp(@bindings);
    foreach my $b (@bindings) {
	my $proc="-$b-";
	if (!($proc =~ /-$opt-/)) {
	    $newbindings="$newbindings $b";
	}
    }
    @bindings=split(" ",$newbindings);
}

# sort by length so that we get the one with the minimal extra options
my @sorted = sort { length $a <=> length $b } @bindings;

if ($#sorted < 0) {
  # no matches
  $TauOptions = trim($TauOptions);
  warn "Error: No matching binding for '$TauOptions' in directory $bindingsdir\n";
  warn "Available bindings ($bindingsdir):\n";
  @bindings=`ls $BASEDIR/lib | grep shared`;
  foreach my $binding (@bindings) {
    warn "  $bindingsdir/$binding";
  }
  exit -1;
}

if ("$listmatching" eq "true" ) {
    print "@bindings\n";
} else { 
    print "$sorted[0]\n";
}

