#  Copyright (c) 1997-2007
#  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: JRealityViewer.pm 7550 2007-01-10 12:25:54Z gawrilow $

use JReality;
use Poly::Sockets;

package JReality::WindowParams;

use Struct (
   [ new => '$' ],
   [ '$embedding' => '#1' ],
   '$client',
   '@client_args',
   '%client_params',
   '$launcher_class',
   '@jars',
   '%jre_properties',
);

# will overload it later
unimport_function(*new);

sub compose_command {
   my ($self, $socket_no)=@_;
   ( $self->client,
     map { $_ eq "==FD==" ? $socket_no : $_ } @{$self->client_args}, 
     map { ("-$_", (defined($self->client_params->{$_}) ? ($self->client_params->{$_}) : ())) } keys %{$self->client_params},
   )
}

package JReality::Window;

use Struct (
   [ '@ISA' => 'JReality::File' ],
   [ new => '$' ],
   [ '$title' => '#1' ],
   [ '$workfile' => 'undef' ],
   [ '$params' => 'undef' ],
);

sub append { 
   my $self = shift;
  
   foreach my $elem (@_) {
      if (defined (my $p=$elem->{points})) {
	 if (defined (my $dyn=detect_dynamic($p))) {
	    if (defined $self->params) {
	       die "multiple interactive components in the same window are not supported\n"
	       if $self->params->embedding != $dyn;
	    } else {
	       $self->params=new WindowParams($dyn);
	    }
	
	    my @indices=flatten_indices($p);
	    $elem->{points}=[ map { "$_ 0 0" } @indices ? @indices : 0..$p->get_n_vertices-1 ];
	    $elem->{name} =~ s/^/dynamic:/;

	    $elem->{number_of_points} = @indices ? scalar @indices : $p->get_n_vertices;
	 } else {
	    $elem->{number_of_points} = @{$p};
	 }
      }
   }
  
   $self->SUPER::append(@_);
}

package JReality::Viewer;

use Struct (
   '@windows',
   [ '$jvpid' => 'undef' ],
   [ '$jv_server_socket' => 'undef' ],
   [ '$jvx_socket' => 'undef' ]
);

sub new_drawing {
   my ($self, $title)=@_;
   push @{$self->windows}, new Window($title);
   $self;
}

sub append { 
   my $self = shift;
   $self->windows->[-1]->append(@_);
}


sub proceed {
   my ($self)=@_;
   my $static_launcher = qw( de.tuberlin.polymake.common.JRealityStaticControl );
   # my $static_launcher = qw( de.tuberlin.polymake.polytope.JRealitySchlegelControl );

   # starter class with main() method
   my @classes=qw( de.tuberlin.polymake.common.Launcher );

   my (@cl_sockets, @cl_ports, @clients, %jars, %jre_properties);

   foreach my $w (@{$self->windows}) {
      if (defined $w->params) {
	 push @cl_sockets, new Poly::ServerSocket;
	 push @clients, [ $w->params->compose_command($cl_sockets[-1]->fileno) ];
	 push @classes, $w->params->launcher_class, "-client_port", $cl_sockets[-1]->port;
	 @jars{@{$w->params->jars}}=();
	 while (my ($prop, $value)=each %{$w->params->jre_properties}) {
	    $jre_properties{$prop}=$value;
	 }
      } else {
	 push @classes, $static_launcher;
      }
   }

   ### FIXME:
   die "interactive viewer: unimplemented feature: cannot run several embedding clients simultaneously\n"
   if @clients>1;

   $self->jv_server_socket=new Poly::ServerSocket;
   my $jv_port=$self->jv_server_socket->port;

   if (!defined ($self->jvpid=fork)) {
      die "fork failed: $!\n";
   }
   if (!$self->jvpid) {	# child process
      undef @cl_sockets;
      undef $self->jv_server_socket;

      if ($Switches::d) {
	 $jre_properties{"polymake.debug"} = $Switches::d >= 2 ? "max" : "yes";
      }
      my @jre_args = map { "-D$_=$jre_properties{$_}" } keys %jre_properties;
      
      my $polymake_jar_path = $main::InstallTop;
      if (-f "$polymake_jar_path/jars/common.jar") {
	 $polymake_jar_path .= "/jars";
      } elsif (-f "$polymake_jar_path/java_build/common.jar") {
	 $polymake_jar_path .= "/java_build";
      }
      my $classpath = join(":", (map { "$polymake_jar_path/$_.jar" } keys %jars), "$polymake_jar_path/common.jar",
			        (map { "$JReality::Viewer::jar_path/$_" } @JReality::Viewer::jars)
			  );
	  if($JReality::Viewer::jogl) {
	  	$classpath .= ":$JReality::Viewer::jogl_path/jogl.jar";
	  }
      my $bsh_jar = $JReality::Viewer::bean_shell_jar;

      push @jre_args,  (   
			# jreality needs this, don't know why
			"-Djreality.bsh.jar=file://$JReality::Viewer::jar_path/$bsh_jar", 
			# ...
			# "-Djreality.data=$JReality::Viewer::jar_path"
			#"-Dpolymake.window.title= "
		       );
      push @jre_args, "-Djava.library.path=$JReality::Viewer::jogl_native_path" if($JReality::Viewer::jogl);

      my @java_command = ($Modules::common::java, @jre_args, "-cp", $classpath, @classes, "-ps_port", $jv_port);
      dbg_print( "launching @java_command" ) if $Switches::d;
      exec @java_command;
      die "exec($java_command[0]) failed: $!\n";
   } # end child process

   my $JVX = $self->jvx_socket = $self->jv_server_socket->accept;
   { my $old_handle = select $JVX; $| = 1; select $old_handle; }

   my $n_geom = 0;
   foreach my $w (@{$self->windows}) {
      my $initial_jvx = $w->toString($n_geom);
      $n_geom++;
      warn $initial_jvx if $Switches::d>=2;
      print $JVX $initial_jvx;
   }
   foreach (@clients) {
      ### FIXME: background_client when implemented
      client(@$_);
   }

   $self;
}

sub DESTROY {
   my ($self)=@_;
   waitpid $self->jvpid, 0 if $self->jvpid;
   undef $self->jvx_socket;
   undef $self->jv_server_socket;
}


1

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