#!/usr/bin/perl
use strict;
use warnings;
use lib qw(/usr/local/lib/mpmasql/modules);


use IndexedTable;
##Version:
my $thisversion = "v1.6 beta";
my $lastchange = "19-Sep-2019";

my $longwelcome = <<WC;
####################################################################
####    MPMASQL Solving a Batch of Standalone MIPs $thisversion    ####
####    Perl-script to solve a batch of MPMAS matrices (.mtx)   ####
####                                                            ####
####    (c) Christian Troost, Univ. Hohenheim, 2011-2019        ####
####	Version: $thisversion		$lastchange	        ####
####################################################################
WC

my $shortwelcome = <<WC2;
MPMASQL Matrix Solving Batch $thisversion		
(c)	Christian Troost, Universität Hohenheim, 2011-2019
WC2

my $indir = "./input/dat/";
my $actdesname;
my $condesname;
my $desdir = "./input/dat/";
my $milpcheck = "/usr/local/bin/mpmasMipSolver";
my $outdir = "./";
my $shell = 1;
my $ini = "mqlmatrix.conf";
my $solveroptions = " ";

if (-e $ini) {
	open (my $INI,"<", $ini) or die "Error when trying to read configuration:$ini\n $!\n";
	while (<$INI>) {
		my $line = $_;
		if ($line =~ /^\s*outdir\s*=\s*(.*)$/){
			$outdir = $1;
			$outdir =~ s/\s*$//;
		}
		elsif ($line =~ /^\s*(milpcheck|solver)\s*=\s*(.*)$/){
			$milpcheck = $2;
			$milpcheck =~ s/\s*$//;
		}
		elsif ($line =~ /^\s*infofiles\s*=\s*(.*)$/){
			$desdir = $1;
			$desdir =~ s/\s*$//;
		}
		elsif ($line =~ /^\s*samdir\s*=\s*(.*)$/){
			$indir = $1;
			$indir =~ s/\s*$//;
		}
		elsif ($line =~ /^\s*(milpcheck|solver)_options\s*=\s*(.*)$/){
			$solveroptions = $1;
			$indir =~ s/\s*$//;
		}
	}
	close ($INI);
}
my $samlist = "sam_list.txt";
my $prefix ="";
my $skip_solving = 0;
my $skip_failed = 0;

#Parse commandline arguments
my $parselevel = 0;
my @grouplist;
while (@ARGV) {
	my $element = shift @ARGV;
	if ($parselevel == 0) {
		if ($element =~ /^-G/ ){
			$parselevel = 1;
		}
		
		elsif (not $element =~ /^-/) {
				# samlist prefix
				$prefix = $element;
				$samlist = $prefix.$samlist;
				print "\nLooking for agent list in file:\t\t". $samlist."\n";  
		}
		elsif ($element =~ /^-O/) {
				# output directory
				$outdir = shift @ARGV unless ($ARGV[0] =~ /^-/);
		}
		elsif ($element =~ /^-I/) {
				# input directory
				$indir = shift @ARGV unless ($ARGV[0] =~ /^-/);
		}
		elsif ($element =~ /^-D/) {
				# input directory
				$desdir = shift @ARGV unless ($ARGV[0] =~ /^-/);
		}
		elsif ($element =~ /^-M/) {
				#MilpCheckExe
				$milpcheck = shift @ARGV unless ($ARGV[0] =~ /^-/);
		}
		elsif ($element =~ /^-S/) {
				# solver options
				$solveroptions = shift @ARGV;
		}
		elsif ($element =~ /^--skip-solving/) {
				# solver options
				$skip_solving = 1;
		}
		elsif ($element =~ /^--skip-failed/) {
				# solver options
				$skip_failed = 1;
		}
		elsif ($element =~ /^-h/ or $element =~ /^-\?/ or $element =~ /^--help/) {
			print $shortwelcome;
			print <<HELP;
Usage:
	mpmasqlBatchSolve	<prefix> [options]

	<prefix>	the prefix of the sam_list.txt file containing 
			the list of matrices to process (usually the PREFIX
			used in the .ini file when running mpmasql/mpmasql4)

Options:

	-I <directory>	input directory (<scenario>_sam_list.txt and .mtx files are expected here)
	-O <directory>	output directory
	-D <directory>  location of activity and constraint description files
	-M <filename>	mpmasMipSolver executable to be used
	(if not specified, the directories are read from mqlmatrix.conf entries samdir, outdir, infofiles, milpcheck.
	If these do not exist either, they default to the current working directory and 
	mpmasMipSolver defaults to /usr/local/bin/mpmasMipSolver)

	-S "<solver_options>" options for mpmasMipSolver, such as "-c mpmasCbcOptions.txt" etc.

	-G <resultgroup1> <resultgroup2> ... [-G]
			Resultgroups (as specified in .cll) to which solution activities shall be aggregated.
			(Note: everything after the -G flag will be interpreted as a resultgroup until a second
			-G flag is encountered)

	--skip-solving 	skip solving and only import existing .pri files
	--skip-failed 	do not include entry for failed problems in solution file
	
	-h, -?, --help	print this help
	-v		print version information

HELP
			exit (0);
		}
		elsif ($element =~ /^-v/ ) {
			print $longwelcome;
			exit(0);
		}
		elsif ($element =~ /^-/) {
			print STDERR "Error: Unknown option '$element'\n";
			exit(1);
		}
	}
	elsif ($parselevel == 1) {
		if ($element =~ /-G$/) {
			$parselevel = 0;
		}
		else {
			my @groups = split (/\s*,\s*/, $element);
			push @grouplist ,  @groups ;
		}
	}
	
}
my $milplist = IndexedTable->create_from_ascii($indir.$samlist, 2, "samlist");

my $out;
my $file = $outdir.$prefix."solution.tab";
open ($out, ">", $file ) or (print STDERR "Error: Could not open $file: $!\n" and exit(1));
print $out join("\t", "scenario", "rhs", "variable", "value")."\n";

my %groupfhs;
for my $g (@grouplist) {
	my $gfile = $outdir.$prefix."${g}_solution.tab";
	open ($groupfhs{$g}, ">", $gfile ) or (print STDERR "Error: Could not open $gfile: $!\n" and exit(1));
	my $gout = $groupfhs{$g};
	print $gout join("\t", "scenario", "rhs", "variable", "value")."\n";
}


for my $scen (sort {$a cmp $b} $milplist->query([],0 )) {

	
	my $actdesname = $desdir.$scen."_ActivityInfo.txt" if (not defined $actdesname);
	my $condesname = $desdir.$scen."_ConstraintInfo.txt" if (not defined $condesname);
	my $actinfo = IndexedTable->create_from_ascii($actdesname, 1, "activity_description");

	my $rtcode = 0;
	for my $ag (sort {$a cmp $b} $milplist->query([$scen],0 )) {
		#my $solutiontab = IndexedTable->create_empty(3, "solutiontab", ["scenario", "rhs", "variable", "value"]);
		my %grouptabs;
		for my $g (@grouplist) {
			$grouptabs{$g} = IndexedTable->create_empty(3, "$g", ["scenario", "rhs", "variable", "value"]);
		}
		my $fn = $indir.$scen."_MILP_".$ag;
		unless ($skip_solving) {
			print "Solving $scen, $ag\n";
			
			my $string = $milpcheck." ".$fn." ".$solveroptions;
			$rtcode = system($string);
		}
		if ($rtcode == 0 ) {
			my $solutionfile = $fn.".pri";
			open (my $fh, "<", $solutionfile) or (print STDERR "Warning: Could not open $solutionfile: $!\nSkipping." and next );
			print "Importing Solution Vector from $solutionfile\n";
			my $cc = 0;
			my @rows;
			while (<$fh>) {
				chomp;
				my $line = $_;
				next if ($line =~ /^\s*$/); #skip empty lines	

				#my @colvalues;
				if ($line =~ /\s*Target value:\s*([-\d.E+e]*)/) {
					print $out join("\t", $scen, $ag, "OptimalObjectiveValue",$1)."\n";
				}
				elsif ($line =~/^\s*?((\s|-)[-\d.E+e]+)/) {
					my $sol = $1;
					 if (sprintf("%.6f", $sol) > 0 or sprintf("%.6f", $sol) < 0) {
						my $actcode = $actinfo->query([$cc],2);
						print $out join("\t", $scen, $ag, $actcode, sprintf("%.6f", $sol))."\n";
						for my $g (@grouplist) {
							my $gcn = $actinfo->column_by_name($g);
							my $isgroup = $actinfo->query([$cc], $gcn);
							unless ($isgroup eq "-1") {
								my $curval = $grouptabs{$g}->query([$scen, $ag, $isgroup],4) || 0;
								$grouptabs{$g}->set_column_value([$scen, $ag, $isgroup],4, sprintf("%.6f",$curval + $sol));
						
							}
						}
					}
					$cc++;
				}
				#push @rows, \@colvalues if (scalar @colvalues > 0);
			}
			close $fh;
		
			#$solutiontab->add_rows(\@rows);
			#$solutiontab->printme_with_header_sorted($outdir.$prefix."solution.tab");
			for my $k (keys %grouptabs) {
				$grouptabs{$k}->print_sorted_to_fh(groupfhs{$k});
			}		
		}
		else { #rtcode != 0
			unless ($skip_failed) {
				print $out join("\t", $scen, $ag, "Failed", 1),"\n";
			}
		}
	}
	
}

close($out);
for my $k (keys %groupfhs) {
	close($groupfhs{$k});
}

