#  Copyright (c) 1997-2018
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
#  http://www.polymake.org
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------

REQUIRE graph::graphviz.rules

sub getRadius_sq {
   my $vec = $_[0];
   my $vec_sliced=$vec->slice(1,$vec->dim-1); # cut off homog. 1
   my $rad_sq=0;
   foreach my $entry (@$vec_sliced) {
      $rad_sq+=$entry*$entry;
   }
   return $rad_sq;
}

sub listOfRadii {
   my $lp_reps = $_[0];
   my %radii = ();
   my $rad=-1;
   for (my $i=0; $i<$lp_reps->rows; ++$i) {
      $rad=sprintf( getRadius_sq($lp_reps->[$i]) );
      my @list=();
      if(exists($radii{$rad})) {
         my $list_ref=$radii{$rad};
         @list=@$list_ref;
      }
      push(@list,$i);
      $radii{$rad}=\@list;
   }

   my @array = ();
   my $count = 0;
   foreach(keys %radii) {
      my $list_ref=$radii{$_};
      my @nodes=@$list_ref;
      $array[$count]=new Pair<Int, Set<Int>>($_, new Set<Int>(@nodes));
      ++$count;
   }
   return new Array < Pair< Int,Set<Int> > >(\@array);
}

sub visualizeNOPGraph_sub {
   my ($Graph,$colors_ref,$filename,$radii)=@_;
   my $my_tmp=new Tempfile;
   my $my_tmp_tred="${my_tmp}_tred";
   graphviz($Graph->VISUAL(NodeColor=>$colors_ref),File=>"$my_tmp");
   my $command_txt1 = "tred $my_tmp.dot > $my_tmp_tred.dot;";
   $command_txt1 .= " sed \'\$d\' $my_tmp_tred.dot > $filename.dot\;";
   system($command_txt1);
   open DOT_FILE, ">>$filename.dot"
      or die "cannot open file: $!";
   my @my_radii=map {$_->first} @$radii;
   my @sorted_radii=sort{$a<=>$b} (@my_radii);
   print DOT_FILE << ".";
ranksep=1;
nodesep=0.25;
node [shape=plaintext, fontsize=14];
edge [shape=plaintext, fontsize=14];
/* radii */
.

   for (my $i=$radii->size-1;$i>0;--$i) {
      my $r=$sorted_radii[$i]; 
      print DOT_FILE '"r^2='.$r.'"'; 
      print DOT_FILE ' -> '; 
   }
   print DOT_FILE '"r^2='.$sorted_radii[0].'";'."\n";

   foreach ( @$radii ) { 
      print DOT_FILE '{'."\n rank = same\;\n"; 
      my $r=$_->first; 
      print DOT_FILE '"r^2='.$r.'";'; 
      foreach my $index(@{$_->second}) {
         print DOT_FILE '"n'.$index.'"; '
      } 
      print DOT_FILE "\n".'};'."\n"; 
   } 

   print DOT_FILE "\n\n".'}'; # closing bracket was removed by sed
   close DOT_FILE;

   my $command_txt2 = "$Graphviz::dot -Tps -o$filename.ps $filename.dot; $Postscript::viewer $filename.ps \&";
   system($command_txt2);
}

object_specialization Polytope::PointOrbit {

# @category Symmetry
# Visualizes the NOP-graph of an orbit polytope.
# Requires 'graphviz' and a Postscript viewer.
# Produces a file which is to be processed with
# the program 'dot' from the graphviz package.
# If 'dot' is installed, the NOP-graph is visualized
# by the Postscript viewer.
# @param String filename the filename for the 'dot' file

user_method VISUAL_NOP_GRAPH ($) : GROUP.COORDINATE_ACTION.NOP_GRAPH , GROUP.COORDINATE_ACTION.REPRESENTATIVE_CERTIFIERS , GROUP.COORDINATE_ACTION.CP_INDICES {
   my ($orb, $filename) = @_;
   my @colors = map {$orb->GROUP->COORDINATE_ACTION->CP_INDICES->contains($_) ? $Visual::Color::CorePointColor : $Visual::Color::NonCorePointColor} 0..$orb->GROUP->COORDINATE_ACTION->N_REPRESENTATIVE_CERTIFIERS-1;
   my $radii = listOfRadii($orb->GROUP->COORDINATE_ACTION->REPRESENTATIVE_CERTIFIERS);
   visualizeNOPGraph_sub($orb->GROUP->COORDINATE_ACTION->NOP_GRAPH,\@colors,$filename,$radii);
}


# @category Symmetry
# Visualizes all (nested) orbit polytopes contained in 
# //orb// in one picture.
# @param ARRAY colors_ref the reference to an array of colors
# @param ARRAY trans_ref the reference to an array of transparency values
user_method VISUAL_NOP ($,$) : GROUP.COORDINATE_ACTION.NOP_GRAPH , GROUP.COORDINATE_ACTION.REPRESENTATIVE_CERTIFIERS , GROUP.COORDINATE_ACTION.CP_INDICES {
   my ($orb, $colors_ref, $trans_ref) = @_;
   my $N_reps = $orb->GROUP->COORDINATE_ACTION->N_REPRESENTATIVE_CERTIFIERS;
   my @polys = ();
   my @polys_degen = ();
   if ($orb->AMBIENT_DIM > 4) {
      die "visualizeNestedOPs: Cannot visualize orbit polytopes of dimension greater than 4!";
   } else {
      for (my $i = 0; $i < $N_reps; ++$i) {
         my $p = new Polytope("GROUP.COORDINATE_ACTION.POINTS_GENERATORS"=>[$orb->GROUP->COORDINATE_ACTION->REPRESENTATIVE_CERTIFIERS->[$i]],"GROUP.COORDINATE_ACTION.GENERATORS"=>$orb->GROUP->COORDINATE_ACTION->GENERATORS); 
         if ($orb->AMBIENT_DIM == 4) {
            my $proj = ortho_project($p);
            if ($proj->DIM == 3) {
               push(@polys,$proj);
            } else {
               push(@polys_degen,$proj);
            }
         } else {
            if ($p->DIM == 3) {
               push(@polys,$p);
            } else {
               push(@polys_degen,$p);
            }
         }
      }
   } 

   my @colors = @{$colors_ref};
   if (scalar(@colors) < $N_reps) {
      print "\nWarning: Number of specified colors is too small! Added default color 'red'.\n";
      while (scalar(@colors) < $N_reps) {
         push(@colors,"red");
      }
   }
   my @trans = @{$trans_ref};
   if (scalar(@trans) < $N_reps) {
      print "\nWarning: Number of specified transparency values is too small! Added default transparency value '0.2'\n.";
      while (scalar(@trans) < $N_reps) {
         push(@trans,0.2);
      }
   }

   compose((map{$polys[$_]->VISUAL(FacetTransparency=>$trans[$_],
         FacetColor=>$colors[$_],
         EdgeColor=>$colors[$_],
         EdgeThickness=>2,
         VertexThickness=>0.6,
         VertexLabels=>[],
         VertexColor=>$colors[$_]
         )}0..$#polys),
      (map{$polys_degen[$_]->VISUAL(
         VertexThickness=>1,
         VertexLabels=>[],
         VertexColor=>$colors[$_+scalar(@polys)]
         )}0..$#polys_degen)
   );
}

}

# Local Variables:
# mode: perl
# c-basic-offset:4
# End:
