#  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: JavaViewInteractiveViewer.pm,v 1.13 2004/10/26 19:00:06 gawrilow Exp $

use JavaView;
use Poly::Sockets;

package JavaView::Interactive::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 JavaView::Interactive::Window;

declare $suppress_dynamic;
@ISA=qw( JavaView::File );

sub append {
   my $self=shift;

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

package JavaView::Interactive::Viewer;

my $static_launcher="de.tuberlin.polymake.common.StaticGeometryControl";

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

sub new_drawing {
   my ($pkg, $title)=@_;
   my $self=( $main::scope->repeating->{$pkg} ||= new JavaView::Interactive::Viewer);
   push @{$self->windows}, new JavaView::Interactive::Window( defined($title) ? (TITLE => $title) : ());
   $self;
}

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

sub proceed {
   my ($self)=@_;

   # 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 (my $params=$w->{interactive_params})) {
	 push @cl_sockets, new Poly::ServerSocket;
	 push @clients, [ $params->compose_command($cl_sockets[-1]->fileno) ];
	 push @classes, $params->launcher_class, "-client_port", $cl_sockets[-1]->port;
	 @jars{@{$params->jars}}=();
	 while (my ($prop, $value)=each %{$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;

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

      my @java_command = ($JavaView::Viewer::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; }
   
   foreach my $w (@{$self->windows}) {
      my $initial_jvx = $w->toString;
      warn $initial_jvx if $Switches::d>=2;
      print $JVX $initial_jvx;
   }
   foreach (@clients) {
      ### FIXME: background_client when implemented
      client(@$_);
   }
}

sub DESTROY {
   # it's JavaView that shuts down the connection, hence just wait here
   waitpid $_[0]->jvpid, 0 if $_[0]->jvpid;
   undef $_[0]->jvx_socket;
   undef $_[0]->jv_server_socket;
}

1

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