#  Copyright (c) 1997-2006
#  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.pm 7476 2006-11-28 17:16:30Z gawrilow $

use strict;
require 'JavaView.def';

package JavaView::File;

use Struct (
   [ new => '$;$' ],
   [ '$workfile' => '#1' ],
   [ '$title' => '#2' ],
   '@geometries',
   [ '$unnamed' => '0' ],
);

sub append
{
   my $self = shift;
   push @{$self->geometries}, @_;
   foreach (@_) {
      if (length($_->{name})) {
	 if (!length($self->title)) {
	    $self->title=$_->{name};
	 }
      } else {
	 $_->{name}="unnamed__" . ++$self->unnamed;
      }
   }
}

sub header
{
   my ($self) = @_;
   my $who=$ENV{USER};
   my $when=localtime();
   my $title=$self->title;
   if (!length($title)) {
      $title="unnamed";
   }
   return <<".";
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<!DOCTYPE jvx-model SYSTEM "http://www.javaview.de/rsrc/jvx.dtd">
<jvx-model>
  <meta generator="polymake for $who"/>
  <meta date="$when"/>
  <version type="dump">1.0</version>
  <title>$title</title>
  <geometries>
.
}

sub trailer
{
   return <<".";
  </geometries>
</jvx-model>
.
}

sub toString
{
   my $self=shift;
   $self->header . join("", map { $_->toString } @{$self->geometries}) . $self->trailer;
}

sub print_it
{
   my ($self) = @_;
   open my $file, ">".$self->workfile
      or die ref($self), "::print_it: could not write file ", $self->workfile, ": $!\n";
   print $file $self->toString;
   close $file;
}

##############################################################################################
#
#  Basis class for all graphical objects handled by javaview
#
package JavaView::geometry;

sub new
{
   my $class = shift;
   my $self = { @_ };
   bless $self, $class;
   $self->initialize;
   return $self;
}

sub initialize
{
   my $self=shift;
   if (! exists $self->{name}) {
      $self->{name}="geometry";
   }
   if (! exists $self->{points}) {
      croak( ref($self), "::initialize: parameter 'points' missing" );
   }
   if (! exists $self->{pointSet_dim}) {
      croak( ref($self), "::initialize: parameter 'pointSet_dim' missing" );
   }
   $self->{pointSet_point_flag} ||= "show";

   if (! exists $self->{points_thickness}) {
      $self->{points_thickness}=$JavaView::default::points_thickness;
   }
   $self->{pointSet_thicknesses_flag} ||= exists $self->{points_thicknesses_list} ? "show" : "hide";

   $self->{pointSet_color_flag} = exists $self->{points_colors_list} ? "show" : "hide";
}

sub header
{
   my ($self)=@_;
   my $attr=" name=\"$self->{name}\"";
   if (defined $self->{visibleFlag}) {
      $attr .= " visible=\"$self->{visibleFlag}\"";
   }
   return <<".";
    <geometry$attr>
.
}

sub trailer
{
   return <<".";
    </geometry>
.
}

sub color_list
{
   my ($self, $name)=@_;
   my $text="";
   if (exists $self->{$name}) {
      $text .= <<".";
        <colors>
.
      foreach (@{$self->{$name}}) {
	 my @color = /\d+/g;
	 $text .= <<".";
          <c>@color</c>
.
      }
      $text .= <<".";
        </colors>
.
   }
   return $text;
}

sub thickness_list
{
   my ($self, $name)=@_;
   my $text="";
   if (exists $self->{$name}) {
      $text .= <<".";
        <thicknesses>
.
      foreach (@{$self->{$name}}) {
	 /[.\d]+/;
	 $text .= <<".";
          <th>$&</th>
.
      }
      $text .= <<".";
        </thicknesses>
.
   }
   return $text;
}

sub pointSet
{
   my ($self) = @_;
   my $text="";
   $text .= <<".";
      <pointSet dim="$self->{pointSet_dim}" point="$self->{pointSet_point_flag}" color="$self->{pointSet_color_flag}" thicknesses="$self->{pointSet_thicknesses_flag}">
        <points>
.
   my $k=0;
   my $labels=$self->{points_labels_list};
   foreach (@{$self->{points}}) {
      my $point=$_; chomp $point;
      my $attr="";
      if (defined($labels)) {
	 $attr=' name="' . $labels->($k) . '"';
      }
      $text .= "          <p$attr>$point</p>\n";
      ++$k;
   }
   if (exists $self->{points_thickness}) {
      $text .= <<".";
          <thickness>$self->{points_thickness}</thickness>
.
   }
   if (exists $self->{points_color}) {
      $text .= <<".";
          <color type="rgb">$self->{points_color}</color>
.
   }
   my $show_labels= defined($labels) ? "show" : "hide";
   $text .= <<"." . $self->color_list('points_colors_list') . $self->thickness_list('points_thicknesses_list') . <<"..";
          <labelAtt visible="$show_labels"/>
        </points>
.
      </pointSet>
..
}

sub toString
{
   my $self=shift;
   return $self->header . $self->pointSet . $self->trailer;
}

##############################################################################################
#
#  Solid 2-d or 3-d body
#
package JavaView::solid;
@ISA=qw( JavaView::geometry );

sub initialize
{
   my $self=shift;
   $self->SUPER::initialize;
   if (! exists $self->{faces}) {
      croak( ref($self), "::initialize: parameter 'faces; missing\n" );
   }
   $self->{faceSet_face_flag} ||= "show";
   $self->{faceSet_backface_flag} ||= "hide";	# our objects are convex by default
   $self->{faceSet_edge_flag} ||= "show";
   $self->{faceSet_color_flag} = exists $self->{faces_colors_list} ? "show" : "hide";
   if (! exists $self->{faces_color}) {
      $self->{faces_color}=$JavaView::default::faces_color;
   }
   if (defined $self->{material_flag}) {
      $self->{faceSet_backface_flag}    = $self->{material_flag};
      $self->{material_diffuseColor}  ||= $JavaView::default::diffuseColor;
      $self->{material_emissiveColor} ||= $JavaView::default::emissiveColor;
      $self->{material_shininess}     ||= $JavaView::default::shininess;
      $self->{material_specularColor} ||= $JavaView::default::specularColor;
      $self->{material_transparency}  ||= $JavaView::default::transparency;
   } else {
      $self->{material_flag} = "hide";
   }
}

sub faceSet
{
   my ($self) = @_;
   my $text="";
   $text .= <<".";
      <faceSet face="$self->{faceSet_face_flag}" edge="$self->{faceSet_edge_flag}" backface="$self->{faceSet_backface_flag}" color="$self->{faceSet_color_flag}">
        <faces>
.
   foreach (@{$self->{faces}}) {
      s/^\s*\{?\s*(.*)\s*\}?\s*$/$1/;
      $text .= <<".";
          <f>$_</f>
.
   }
   $text .= <<".";
          <color type="rgb">$self->{faces_color}</color>
        </faces>
.
   if (exists $self->{neighbours}) {
      $text .= <<".";
        <neighbours>
.
      foreach (@{$self->{neighbours}}) {
	 my ($first, $rest)=/(\d+)\s+(.*)/;	# javaview expects the neighbors in a rather weird order
	 $text .= <<".";
          <nb>$rest $first</nb>
.
      }
      $text .= <<".";
        </neighbours>
.
   }
   my $edges="";
   if (exists $self->{edges_color}) {
      $edges .= <<".";
           <color type="rgb">$self->{edges_color}</color>
.
   }
   if (exists $self->{edges_thickness}) {
      $edges .= <<".";
           <thickness>$self->{edges_thickness}</thickness>
.
   }
   if ($edges) {
      $text .= <<"." . $edges . <<"..";
        <edges>
.
        </edges>
..
   }
   $text .= $self->color_list('faces_colors_list') . <<'.';
      </faceSet>
.
}

sub material
{
  my ($self) = @_;
  my $text = "";
  return $text if($self->{material_flag} eq "hide");
  $text .= <<".";
       <material>
	 <ambientIntensity>$self->{material_ambientIntensity}</ambientIntensity>
	 <diffuse>
	   <color type="rgb">$self->{material_diffuseColor}</color>
	 </diffuse>
	 <emissive>
	    <color type="rgb">$self->{material_emissiveColor}</color>
	 </emissive>
	 <shininess>$self->{material_Shininess}</shininess>
	 <specular>
	    <color type="rgb">$self->{material_specularColor}</color>
	  </specular>
	  <transparency visible="show">$self->{material_transparency}</transparency>
	</material>
.
}

sub toString
{
   my ($self) = @_;
   return $self->header . $self->pointSet . $self->faceSet . $self->material . $self->trailer;
}

##############################################################################################
#
#  Wire model (e.g. a graph)
#
package JavaView::wire;
@ISA=qw( JavaView::geometry );

sub initialize
{
   my $self=shift;
   $self->SUPER::initialize;
   if (! exists $self->{lines}) {
      croak( ref($self), "::initialize: parameter 'lines' missing" );
   }
   $self->{lineSet_line_flag} ||= "show";
   $self->{lineSet_arrow_flag} ||= "hide";

   if (! exists $self->{lines_thickness}) {
      $self->{lines_thickness}=$JavaView::default::lines_thickness;
   }
   $self->{lineSet_thicknesses_flag} ||= exists $self->{lines_thicknesses_list} ? "show" : "hide";

   if (! exists $self->{lines_color}) {
      $self->{lines_color}=$JavaView::default::lines_color;
   }
   $self->{lineSet_color_flag} = exists $self->{lines_colors_list} ? "show" : "hide";
}

sub lineSet
{
   my ($self)=@_;
   my $text="";
   $text .= <<".";
      <lineSet line="$self->{lineSet_line_flag}" arrow="$self->{lineSet_arrow_flag}" color="$self->{lineSet_color_flag}" thicknesses="$self->{lineSet_thicknesses_flag}">
        <lines>
.
   foreach (@{$self->{lines}}) {
      $text .= <<".";
          <l>$_</l>
.
   }
   $text .= <<"." . $self->color_list('lines_colors_list') . $self->thickness_list('lines_thicknesses_list') . <<'..';
          <thickness>$self->{lines_thickness}</thickness>
          <color type="rgb">$self->{lines_color}</color>
        </lines>
.
      </lineSet>
..
}

sub toString
{
   my ($self)=@_;
   return $self->header . $self->pointSet . $self->lineSet . $self->trailer;
}

1

# Local Variables:
# c-basic-offset:3
# End:
