/* 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.
*/

#ident "$Project: polymake $$Id: schlegel_interactive.cc,v 1.14 2004/07/01 16:28:55 gawrilow Exp $"

#include <Poly.h>
#include <IncidenceMatrix.h>
#include <SchlegelWindow.h>
#include <schlegel_common.h>
#include <Map.h>
#include <Array.h>
#include <vector>
#include <labels.h>
#include <pipestream.h>
#include <SimpleGeometryParser.h>

namespace polymake { namespace polytope {

void schlegel_interactive(Array<Poly>& S, Poly& p, std::socketstream& javaview, const char **points, int n_points)
{
   const Matrix<double> F=p.give("FACETS");
   const IncidenceMatrix<> VIF=p.give("VERTICES_IN_FACETS");
   const Graph<> VG=p.give("GRAPH"), FG=p.give("DUAL_GRAPH");
   Matrix<double> Points;
   for (int i=0; i<n_points; ++i) {
      const Matrix<double> Points_i=p.give(points[i]);
      Points /= Points_i;
   }

   Vector<double> FacetPoint, InnerPoint;

   std::vector<std::string> FacetLabels(F.rows());
   read_labels(p, "FACET_LABELS", FacetLabels.begin(), F.rows());
   graph::SimpleGeometryParser parser;

   // get the geometry name from javaview.
   std::string line;
   if (!getline(javaview,line)) return;
   std::string geom_name= line.substr(0,5)=="read " ? line.substr(5) : "Schlegel diagram";
   geom_name += " on facet ";

   typedef Map<std::string, SchlegelWindow> geometry_map;
   geometry_map geometries;
   geometry_map::iterator g;

   for (Entire< Array<Poly> >::iterator s=entire(S); !s.at_end(); ++s) {
      int proj_facet=s->give("FACET");
      double zoom=s->give("ZOOM");
      s->give("FACET_POINT") >> FacetPoint;
      s->give("INNER_POINT") >> InnerPoint;

      g=geometries.insert( geom_name + FacetLabels[proj_facet],
			   SchlegelWindow(Points,F,FG,FacetPoint,InnerPoint,proj_facet,zoom) );
      parser.print_full(javaview, g->first, g->second, VG, VIF[proj_facet]);
   }

   char command;
   while ((command=parser.get_command(javaview)) != 0) {
      switch (command) {
      case 'n':
      {
	 std::string name=parser.line.str();
	 name.erase(0,2);
	 g=geometries.find(name);
	 if (g.at_end())
	    throw std::runtime_error("unknown geometry name: " + name);
	 break;
      }
      case 'p':
      {
	 SchlegelWindow::dragged_point p=parser.get_point();
	 SchlegelWindow::drag_response resp=g->second.drag_point(p, VIF);
	 if (resp == SchlegelWindow::drag_boundary) {
	    parser.print_error(javaview, g->first, g->second, "zoom", "boundary of projection facet reached");
	 } else {
	    parser.print_short(javaview, g->first, g->second);
	 }
	 break;
      }
      case 's':
      {
	 std::string param;
	 parser.line >> param;
	 if (param == "zoom") {
	    double zoom;
	    parser.line >> zoom;
	    g->second.set_param("zoom",zoom);
	    parser.print_short(javaview, g->first, g->second);

	 } else if (param=="store") {
	    const std::pair< Vector<double>, Vector<double> > params=g->second.reconstruct_params();
	    p.take("SCHLEGEL_PARAMS") << std::setprecision(6)
				      << g->second.get_proj_facet() << ' ' << g->second.get_param("zoom") << '\n'
				      << params.first << '\n'
				      << params.second << '\n';

	 } else if (param=="close") {
	    geometries.erase(g);
	    if (geometries.empty())
	       return;

	 } else {
	    throw std::runtime_error("unknown parameter: " + param);
	 }
	 break;
      }
      case 'f':
      {
	 const Set<int> selected_points=parser.get_facet(),
	                facet=accumulate(cols(VIF.minor(All,selected_points)), operations::mul());
	 if (facet.empty()) {
	    if (selected_points.empty())
	       parser.print_warning(javaview, g->first, "no points selected");
	    else
	       parser.print_warning(javaview, g->first, "selected points don't belong to one facet");

	 } else if (facet.size()>1) {
	    parser.print_warning(javaview, g->first, "selected points belong to more than one facet");

	 } else {
	    int proj_facet=facet.front();
	    std::string new_geom_name = geom_name + FacetLabels[proj_facet];
	    if (geometries.exists(new_geom_name)) {
	       parser.print_warning(javaview, new_geom_name, 
				    "the projection on facet " + FacetLabels[proj_facet] + " is already being displayed");
	    } else {
	       g=geometries.insert(new_geom_name,
				   SchlegelWindow(Points,F,FG,average(rows(Points.minor(VIF[proj_facet],All))),
						  InnerPoint,proj_facet,g->second.get_param("zoom")));
	       parser.print_full(javaview, g->first, g->second, VG, VIF[proj_facet]);
	    }
	 }
	 break;
      }
      case 'x':
	 break;
      default:
	 throw std::runtime_error("unknown command: " + command);
      }
   }
}

} }

using namespace polymake;

/** @file schlegel_interactive
 *
 *  Driver for interactive Schlegel diagram visualization.
 *
 *  @synopsis schlegel_transform <SchlegelDiagram> ... <Polytope> <fd> <points_in> ...
 *
 *  The first section in <points_in> must be Polytope.VERTICES
 */

int main(int argc, const char *argv[])
{
   static const char *usage=" <SchlegelDiagram> ... <Polytope> <fd> <points_in> ...";
   if (argc<5) {
      cerr << "usage: " << argv[0] << usage << endl;
      return 1;
   }
   int fd_arg, c;
   for (fd_arg=1; fd_arg<argc; ++fd_arg) {
      const char *arg=argv[fd_arg];
      for (c=0; isdigit(arg[c]); ++c) ;
      if (!arg[c]) break;
   }
   if (fd_arg==argc) {
      cerr << "usage: " << argv[0] << usage << endl;
      return 1;
   }
   try {
      Array<Poly> S(fd_arg-2);
      c=1;
      for (Entire< Array<Poly> >::iterator s=entire(S); !s.at_end(); ++s, ++c)
	 s->init(argv[c], ios::in);
      Poly p(argv[fd_arg-1], ios::in | ios::out);
      std::socketstream javaview(argv[fd_arg]);
      polytope::schlegel_interactive(S, p, javaview, argv+fd_arg+1, argc-fd_arg-1);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}


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