#  Copyright (c) 1997-2004
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
#  http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de
#
#  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.
#-----------------------------------------------------------------------------
#  $Project: polymake $$Id: javaview.rules,v 1.12 2004/12/08 09:42:08 gawrilow Exp $

INCLUDE
   javaview_configure

CONFIGURE : javaview_configure

###############################################################################
#
#  Basis class for both static and interactive Viewers.
#  It defines only common configuration variables as well as the global methods
#  used by visualize
#
package JavaView::Viewer;

### try to use the interactive viewer first
INCLUDE
   interactive.rules

my $viewer_impl;

if ($Modules::common::rulefiles{"interactive.rules"}) {
   $viewer_impl="JavaView::Interactive::Viewer";
} else {
   $viewer_impl="JavaView::Static::Viewer";
   require JavaViewStaticViewer;
}

sub new_drawing {
   shift;
   $viewer_impl->new_drawing(@_);
}

###########################################################################################
#
#  for user preferences
#

# Use @see external.JavaView - default tool for the visualization of 3- or 4-dimensional geometric objects.
#
# Recently you can also use it for graph visualization.  The 3-d spring embedder starts with random node placement, so
# you have a chance to get various embeddings when trying it several times.
label javaview

prefer javaview.geometry

###########################################################################################
#
#  Drawing methods for graphical primitives defined in this module
#

sub visible {
   my ($P)=@_;
   return $P->Hidden
          ? (visibleFlag => "hide")
          : ();
}

sub colors {
   my ($P, $items, $color_name, $default_color, $key)=@_;
   my @params;
   if (defined (my $get_color=$P->$color_name)) {
      if (is_code($get_color)) {
	 my @colors;
	 if (is_numeric($items)) {
	    @colors=map { (Visual::parse_color($get_color->($_)))[1] || $default_color } 0..($items-1)
	 } else {
	    while ($items) {
	       push @colors, (Visual::parse_color($get_color->($items)))[1] || $default_color;
	       ++$items;
	    }
	 }
	 push @params, "${key}Set_color_flag" => "show",
	               "${key}s_colors_list" => \@colors;
      } elsif (my @color=Visual::parse_color($get_color)) {
	 push @params, "${key}s_color" => $color[1];
      }
   }

   $color_name =~ /Color$/;
   my $style_name="$`Style";
   my $get_style=$P->$style_name;
   if (!is_code($get_style)  &&  $get_style =~ $Visual::hidden_re) {
      push @params, "${key}Set_${key}_flag" => "hide";
      if ($style_name =~ /^Face/) {
	 push @params, faceSet_backface_flag => "show";
      }
   } elsif (!@params && defined($default_color)) {
      push @params, "${key}s_color" => $default_color;
   }
   return @params;
}

sub vertex_colors {
   if (@_==1) {
      push @_, scalar @{$_[0]->Vertices}, "VertexColor";
   }
   push @_, $Visual::Color::vertices, "point";
   &colors;
}

sub facet_colors {
   if (@_==1) {
      push @_, scalar @{$_[0]->Facets}, "FacetColor";
   }
   push @_, $Visual::Color::facets, "face";
   &colors;
}

sub thicknesses {
   my ($P, $items, $style_name, $default_thickness, $key)=@_;
   if (defined (my $get_style=$P->$style_name)) {
      if (is_code($get_style)) {
	 my ($seen, @th);
	 if (is_numeric($items)) {
	    @th=map { $get_style->($_) =~ $Visual::thickness_re ? do { $seen=1; $1 } : $default_thickness } 0..($items-1);
	 } else {
	    while ($items) {
	       push @th, $get_style->($items) =~ $Visual::thickness_re ? do { $seen=1; $1 } : $default_thickness;
	       ++$items;
	    }
	 }
	 if ($seen) {
	    return ( "${key}Set_thicknesses_flag" => "show",
		     "${key}Set_thicknesses_list" => \@th );
	 }
      } elsif ($get_style =~ $Visual::thickness_re) {
	 return ( "${key}s_thickness" => $1 );
      }
   }
   return ();
}

sub vertex_thicknesses {
   if (@_==1) {
      push @_, scalar @{$_[0]->Vertices}, "VertexStyle";
   }
   push @_, $JavaView::default::points_thickness, "point";
   &thicknesses;
}

sub edges {
   my ($P, $color_name)=@_;
   $color_name ||= "EdgeColor";
   my @params;
   if (defined (my $color=(Visual::parse_color($P->$color_name))[1])) {
      push @params, edges_color => $color;
   }
   $color_name =~ /Color$/;
   my $style_name="$`Style";
   if (defined (my $style=$P->$style_name)) {
      if ($style =~ $Visual::hidden_re) {
	 push @params, faceSet_edge_flag => 'hide';
      } elsif ($style =~ $Visual::thickness_re) {
	 push @params, edges_thickness => $1;
      }
   }
   return @params;
}

sub labels {
   my ($P, $items, $label_name, $key)=@_;
   if (defined (my $labels=$P->$label_name)) {
      if (is_array($labels)) {
	 return "${key}s_labels_list" => $labels;
      } elsif (is_code($labels)) {
	 return "${key}s_labels_list" => [ map { $labels->($_) } 0..($items-1) ];
      } elsif ($labels eq "hidden") {
	 return "${key}s_labels_list" => [ (" ") x $items ];
      }
   }
   return ();
}

sub vertex_labels {
   if (@_==1) {
      push @_, scalar @{$_[0]->Vertices}, "VertexLabels";
   }
   push @_, "point";
   &labels;
}

global_method javaview.geometry: draw(Visual::PointSet, @) {
   my ($self, $P)=@_;
   my @params = ( name => $P->Name,
		  points => $P->Points,
		  pointSet_dim => $P->Dim,
		  vertex_labels($P),
		  vertex_colors($P),
		  vertex_thicknesses($P),
		  visible($P),
		);
   $self->append(new JavaView::geometry(@params));
}

global_method javaview.geometry: draw(Visual::Polygon, @) {
   my ($self, $P)=@_;
   my $face=$P->Facet;
   if ($face) {
      $face =~ s/\{\s*(.*)\s*\}/$1/;
   } else {
      $face=join(" ", 0..$#{$P->Vertices});
   }

   my @params = ( name => $P->Name,
		  points => $P->Vertices,
		  pointSet_dim => $P->Dim,
		  faces => [ $face ],
		  faceSet_backface_flag => "show",
		  vertex_labels($P), vertex_colors($P), vertex_thicknesses($P),
		  edges($P), visible($P),
		);

   if (defined (my $color=(Visual::parse_color($P->FacetColor))[1])) {
      push @params, faces_color => $color;
   }

   if ($#{$P->Vertices} >= 2) {
      if (defined (my $style=$P->FacetStyle)) {
	 if ($style =~ $Visual::hidden_re) {
	    push @params, faceSet_face_flag => "hide",
	                  faceSet_backface_flag => "show";
	 }
      }
      $self->append(new JavaView::solid(@params));

   } else {
      for (my $i=0; $i<$#params; $i+=2) {
	 $params[$i] =~ s/^face/line/;
      }
      $self->append(new JavaView::wire(@params));
   }
}

global_method javaview.geometry: draw(Visual::Polygons, @) {
   my ($self, $P)=@_;
   my @params = ( name => $P->Name,
		  points => $P->Vertices,
		  pointSet_dim => $P->Dim,
		  faces => [ map { $_->Facet =~ /\{(.*)\}/ ? $1 : $_->Facet } @{$P->Polygons} ],
		  faceSet_backface_flag => "show",
		  vertex_labels($P), vertex_colors($P), vertex_thicknesses($P),
		  facet_colors($P, scalar @{$P->Polygons}, "FacetColor"), edges($P),
		  visible($P),
		);

   $self->append(new JavaView::solid(@params));
}

###########################################################################################
package JavaView::JVX::Viewer;
@ISA=qw( JavaView::Viewer JavaView::File );

sub new_drawing {
   my ($self, $title)=@_;
   $self->{TITLE}=$title;
   my $cleanup=delete $main::scope->cleanup->{\$viewer_impl};
   $viewer_impl=$cleanup->[1];
   $self;
}

sub DESTROY {
   my $self=shift;
   if (@{$self->{GEOMETRIES}}) {
      $self->print_it;
   }
}

package default;

# Category: Visualization
# args: [ FILENAME ]
# Redirect the drawing produced by the next visualization method or function into a JVX file @a FILENAME.
# JVX is the XML-based file format used by @see external.JavaView.
#
# The @c .jvx suffix is added automatically.  If @a FILENAME is omitted, the contents will be printed to @c STDOUT.

user_function JVXfile {
   my $filename=shift;
   if (defined $filename) {
      $filename.=".jvx" unless $filename =~ /\.\w+$/;
   } else {
      $filename="-";
   }
   if (!UNIVERSAL::isa($viewer_impl, "JavaView::JVX::Viewer")) {
      $main::scope->cleanup->{\$viewer_impl} ||= [ sub { ${$_[0]}=$_[1] }, $viewer_impl ];
   }
   $viewer_impl=new JavaView::JVX::Viewer(workfile => $filename);
   Poly::User::javaview();
}

# Local Variables:
# mode: perl
# End:
