#!/usr/bin/perl

use strict;
use Getopt::Long qw(:config no_ignore_case);
use vars qw($help $type $inFile $outFile $inDir $outDir $all $All);
use Data::Dumper;
use Sys::Hostname;
use Cwd;

my %options=('h' => \$help,
	     't' => \$type,
	     'i' => \$inFile,
	     'o' => \$outFile,
	     'id' => \$inDir,
	     'od' => \$outDir,
	     'a' => \$all,
	     'A' => \$All,
	     );

&help unless @ARGV;
GetOptions(\%options,qw(h! t=s i=s o=s id=s od=s a! A! ic=i oc=i));
&help if ($help);
$inDir=$inDir.'/' if (($inDir)&&(!($inDir =~ /\/^/)));
$outDir=$outDir.'/' if (($outDir)&&(!($outDir =~ /\/^/)));


unless ($type =~ /g|t|p/){
    print "
You may select a format with -t (mathematica or t, maple or p, magma or g)
Format: [gpt]? ";
    $type = <STDIN>;
    chomp($type);
    unless ($type =~ /g|t|p/){
	print "Format must contain g, t or p.\nExiting.\n";
        exit;
    }
}         

my @files;

if ($All){
    opendir(DIR,"$inDir")||die("Can't open $inDir");
    @files= grep { /^[^\.]+/ } readdir(DIR);
    print "Going to convert all files from $inDir:\n";
    print join "\n", @files;
    print "\nTo get just files starting with Z or Q use -a\n";
}elsif ($all){
    opendir(DIR,"$inDir")||die("Can't open $inDir");
    @files= grep { /^[ZQ]+/ } readdir(DIR);
    print "Going to convert all files from $inDir starting with Z or Q:\n";
    print join ", ", @files;
    print "\nTo get All files use -A\n";
}else{
    die("Must choose an input file with -i or use -a or -A for all files in a directory") unless ($inFile);
    @files=($inFile);
    print "Going to convert $inDir$inFile\n";
}    


foreach my $file (@files){
    my ($operators,$form)=&process($file);
    &output($operators,$form,$file) if (@$operators);
}

sub process{
    my $file=shift;
    print STDOUT "\nWorking on $inDir$file\n";
    open(IN,"<$inDir$file")||print "Can't open $inDir$file.\nSkipping\n";
    my $format;
    if ($file =~ /Cpt/){
	$format='compact';
    }
    my $dimension;
    my $string;
    my @operators;
    my $form;
    foreach my $line (<IN>){
	chomp($line);
	$line =~ s/\s//g;
	$line =~ s/\\//g;   #\ in some of Stembridge's files (carriage returns)
	$string.=$line;
	if ($line =~ /dimension/){
	    $line =~ s/[^0-9]*//g;
	    $dimension=$line;
	}
    }

    if ($string =~ /operators/){
	print STDOUT "Input: Magma format\n";
	print STDOUT "Compact\n" if ($format eq 'compact');
	#magma format
	$string =~ s/.*operators:=\[//;
	$string =~ s/\];F:=/,/;
	$string =~ s/;//g;
	my @matrices= split '\],\[', $string;
	foreach my $i (0..$#matrices){
	    my $matrix=$matrices[$i];
	    my @outMatrix;
	    $matrix =~ s/[\[||\]]//g;
	    my @inMatrix=split ',', $matrix;
	    if (($format eq 'compact')&&($i <$#matrices)){
		my @inMatrixTmp=@inMatrix;
		@inMatrix= (0)x($dimension*$dimension);
		my $position=0;
		foreach my $i (0..(scalar(@inMatrixTmp)/2)-1){
		    my $shift=shift @inMatrixTmp;
		    $position += $shift;
		    my $value=shift @inMatrixTmp;
		    $inMatrix[$position]=$value;
		}
	    }
	    foreach my $i (0..$dimension-1){
		my @row=splice @inMatrix, -$dimension;
		my $row = join ',', @row;
		unshift @outMatrix, $row;
	    }
	push @operators, \@outMatrix;	    
	}
    }elsif ($string =~ /ma/){
	#maple format
	print STDOUT "Input: Maple format\n";
	print STDOUT "Compact\n" if ($format eq 'compact');
	$string =~ s/.*ma:=\[//;
	$string =~ s/.*macpt:=\[//;
	$string =~ s/\];//g;
	my @matrices;
	if ($format eq 'compact'){
	    @matrices= split '\]\]\],\[\[\[', $string;
	    foreach my $matrix (@matrices){
		my @outMatrix;
		my @rowsIn = split '\]\],\[\[', $matrix;
		my $dimension=scalar(@rowsIn);
		my @rows;
		foreach my $rowIn (@rowsIn){
		    $rowIn =~ s/^\[+//g;
		    $rowIn =~ s/\]+$//;
		    my @row = (0)x$dimension;
		    my @entries= split '\],\[', $rowIn;
		    foreach my $entry (@entries){
			$entry =~ s/[\[||\]]//g;
			my ($loc,$val)=split ',', $entry;
			$row[$loc-1]=$val;			
#			print "($loc,$val)\n";
		    }
		    push @outMatrix, join ',', @row;
		}
		push @operators, \@outMatrix;
	    }
	}else{
	    @matrices= split '\]\],\[\[', $string;
	    foreach my $matrix (@matrices){
		my @outMatrix;
		my @rows = split '\],\[', $matrix;
		foreach my $row (@rows){
		    $row =~ s/[\[||\]]//g;
		    push @outMatrix, $row;
		}
	    push @operators, \@outMatrix;	    
	    }
	}
    }
    my $form=pop @operators;
    return (\@operators,$form);
}


sub output{
    
    my $matrices=shift;
    my $form=shift;
    my $file=shift;
    my @matrices=@$matrices;
    if ($outFile){
	my $open=open(OUT,">$outFile");
	unless ($open){
	    print "Can't open $outFile for output.\nSkipping.\n";
	    return;
	}
	select OUT;
    }elsif ($all||$All){
	unless ($outDir){
	    print "You must specify an output directory with -a or -A.\n";
	    exit;
	}
	if ($outDir eq $inDir){
	    print "The output directory (-od) and input directory (-id)  cannot be the same.\n";
	    exit;
	}
	my $open=open(OUT,">$outDir$file");
	unless ($open){
	    print "Cannot open $outDir$file for output\nSkipping.\n";
	}	    
	select OUT;
    }
    if ($type =~ /t|p/){
	my ($a,$b,$terminator,$commentOpen,$commentClose);
	my $date=scalar localtime();
	my $hostname = hostname();
	my $workingDir=cwd();
	if ($type =~ /t/){
	    $a='{';
	    $b='}';
	    $commentOpen="(*";
	    $commentClose="*)";
	    $terminator=';';
	    print STDOUT "Output: Mathematica format\n\n";
	    print "$commentOpen From file $hostname:$workingDir/$inDir$file $commentClose\n";
	    print "$commentOpen Produced by convert.pl, $date $commentClose\n\n";
	}else{
	    $a='[';
	    $b=']';
	    $commentOpen="#";
	    $terminator=':';
	    print STDOUT "Output: Maple format\n\n";
	    print "$commentOpen From file $hostname:$workingDir/$inDir$file $commentClose\n";
	    print "$commentOpen Produced by convert.pl, $date $commentClose\n\n";
	}
	print "operators:=$a\n$a";
	my @out;
	foreach my $i (0..$#matrices){
	    my $m=$matrices[$i];
	    my $matrix=join "$b,\n$a", @$m;
	    push @out, "$a$matrix$b";
	}
	print join "$b,\n$a", @out;
	print "$b\n$b$terminator\n\n";
	print "F:=$a\n$a";
	my $m=$form;
	my $matrix=join "$b,\n$a", @$m;
	print $matrix;
	print "$b\n$b$terminator\n\n";
    }elsif ($type =~ /g/){
	print STDOUT "Output: Magma format\n\n";	

	my ($a,$b,$terminator);
	$a='[';
	$b=']';
	$terminator=';';

	print "operators:=$a\n";
	my @out;
	foreach my $i (0..$#matrices){
	    my $m=$matrices[$i];
	    my $matrix=join ",\n", @$m;
	    push @out, "$a$matrix";
	}
	print join "$b,\n$a", @out;
	print "$b\n$b$terminator\n\n";
	print "F:=\n$a";
	my $m=$form;
	my $matrix=join ",\n", @$m;
	print $matrix;
	print "$b$terminator\n\n";
    }
    close(OUT);
}


sub help{
print <<END;
Convert models between different types.
Usage: convert.pl -i inFile [-o outFile] [-t type]
       convert.pl -a||A -id input Directory [-od output Directory] 

The output is a file which may be read directly into mathematica,
maple or magma.

-i:   file to read
-o:   file to output (instead of stdout)
-t:   type of output (mathematica, maple, or magma, abbreviated t,p,g)
         will be prompted for this if not specified on command line
-a:   do all files in inputDirectory starting with Z or Q
-A:   do all files in input Directory
-id:  input Directory
-od:  output Directory (must be different from input Directory)
-h:   this help file
END
exit;
}
