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

#ifndef _POLYMAKE_SIMPLE_GEOMETRY_PARSER_H
#define _POLYMAKE_SIMPLE_GEOMETRY_PARSER_H "$Project: polymake $$Id: SimpleGeometryParser.h 7315 2006-04-02 21:37:53Z gawrilow $"

#include <Map.h>
#include <Matrix.h>
#include <Vector.h>
#include <Set.h>
#include <Graph.h>
#include <sstream>
#include <cctype>

namespace polymake { namespace graph {

// A simple line parser
class SimpleGeometryParser {
private:
   typedef Map<std::string, double> param_map;
   typedef Map<std::string, bool> iparam_map;

   template <typename Traits>
   void _print_name(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name) const
   {
      if (!os) throw std::runtime_error("communication error");
      os << "n " << this_geom_name << '\n';
   }

   template <typename Traits, typename Window>
   void _print_points(std::basic_ostream<char, Traits>& os, const Window& W) const
   {
      const Matrix<double>& P=W.get_points();
      os << "# " << P.rows() << '\n';

      for (Entire< Rows< Matrix<double> > >::const_iterator p_i=entire(rows(P)); !p_i.at_end(); ++p_i)
	 wrap(os) << "p " << *p_i << '\n';
   }

   template <typename Traits, typename Window>
   void _print_params(std::basic_ostream<char, Traits>& os, const Window& W) const
   {
      const param_map& params = W.get_params();
      const iparam_map& iparams = W.get_iparams();
      for (Entire<param_map>::const_iterator pi = entire(params); !pi.at_end(); ++pi){
	 os << "s " << pi->first << " " << pi->second << '\n';
	 if(iparams.find(pi->first) != iparams.end()) {
	    os << "i " << pi->first << " " << iparams[pi->first] << '\n';
	 }
      }
   }

   template <typename Traits, typename Window, typename Params>
   void _print_params(std::basic_ostream<char, Traits>& os, const Window& W, const Params& params) const
   {
      _print_params(os, W, params, typename pm::object_traits<Params>::model());
   }

   template <typename Traits, typename Window, typename Params>
   void _print_params(std::basic_ostream<char, Traits>& os, const Window& W, const Params& param_name, pm::is_scalar) const
   {
      const param_map& params = W.get_params();
      const iparam_map& iparams = W.get_iparams();
      os << "s " << param_name << " " << params[param_name] << '\n';
      if(iparams.find(param_name) != iparams.end()) {
	 os << "i " << param_name << " " << iparams[param_name] << '\n';
      }
   }

   template <typename Traits, typename Window, typename Params>
   void _print_params(std::basic_ostream<char, Traits>& os, const Window& W, const Params& param_name, pm::is_container) const
   {
      const param_map& params = W.get_params();
      const iparam_map& iparams = W.get_iparams();
      for (typename Entire<Params>::const_iterator param_name=entire(params); !param_name.at_end(); ++param_name) {
	 os << "s " << *param_name << " " << params[*param_name] << '\n';
	 if(iparams.find(*param_name) != iparams.end()) {
	    os << "i " << *param_name << " " << iparams[*param_name] << '\n';
	 }
      }

   }

   template <typename Traits>
   void _print_graph(std::basic_ostream<char, Traits>& os, const Graph<>& vertex_graph) const
   {
      for (Entire< Edges< Graph<> > >::const_iterator ei = entire(edges(vertex_graph));
	   !ei.at_end(); ++ei)
	 os << "l " << ei.from_node() << " " << ei.to_node() << '\n';
   }

   template <typename Traits, typename VSet>
   void _print_facet(std::basic_ostream<char, Traits>& os, const VSet& facet) const
   {
      if (!facet.empty()) {
	 os << "f ";
	 for (typename Entire< VSet >::const_iterator vi = entire(facet); !vi.at_end(); ++vi)
	    os << *vi << ' ';
	 os << '\n';
      }
   }

   template <typename Traits>
   void _print_end(std::basic_ostream<char, Traits>& os) const
   {
      os << 'x' << endl;
   }

public:
   std::istringstream line;

   template <typename Traits, typename Window>
   void print_short(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
		    const Window& W) const;

   template <typename Traits, typename Window, typename VSet>
   void print_full(std::basic_ostream<char, Traits>& os,  const std::string& this_geom_name,
		   const Window& W, const Graph<>& vertex_graph, const VSet& facet) const;
   
   template <typename Traits>
   void print_warning(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
		      const std::string& message) const;

   template <typename Traits, typename Window, typename Params>
   void print_error(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
		    const Window& W, const Params& params, const std::string& message) const;

   template <typename Traits>
   char get_command(std::basic_istream<char, Traits>& is);

   std::pair<int, Vector<double> > get_point();

   Set<int> get_facet();
};

template <typename Traits, typename Window>
void SimpleGeometryParser::print_short(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
				       const Window& W) const
{
   _print_name(os, this_geom_name);
   _print_points(os, W);
   _print_params(os, W);
   _print_end(os);
}

template <typename Traits, typename Window, typename VSet>
void SimpleGeometryParser::print_full(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
				      const Window& W, const Graph<>& vertex_graph, const VSet& facet) const 
{
   _print_name(os, this_geom_name);
   _print_points(os, W);
   _print_params(os, W);
   _print_graph(os, vertex_graph);
   _print_facet(os, facet);
   _print_end(os);
}

template <typename Traits>
void SimpleGeometryParser::print_warning(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
					 const std::string& message) const
{
   _print_name(os, this_geom_name);
   os << "w " << message << '\n';
   _print_end(os);
}

template <typename Traits, typename Window, typename Params>
void SimpleGeometryParser::print_error(std::basic_ostream<char, Traits>& os, const std::string& this_geom_name,
				       const Window& W, const Params& params, const std::string& message) const
{
   _print_name(os, this_geom_name);
   _print_points(os, W);
   _print_params(os, W, params);
   os << "e " << message << '\n';
   _print_end(os);
}

template <typename Traits>
char SimpleGeometryParser::get_command(std::basic_istream<char, Traits>& is)
{
   std::string line_s;
   char command=0;
   if (getline(is,line_s)) {
      line.clear();
      line.str(line_s);
      command=line.get();
      while (isspace(line.peek())) line.ignore();
   }
   return command;
}

std::pair<int, Vector<double> >
SimpleGeometryParser::get_point()
{
   Vector<double> pt(3);
   for (Entire< Vector<double> >::iterator p_i=entire(pt); !p_i.at_end(); ++p_i)
      if (!(line >> *p_i))
	 throw std::runtime_error("error parsing point: " + line.str());
   int index=-1;
   char l=0;
   if (line >> l && l=='l') {
      if (!(line >> index))
	 throw std::runtime_error("error parsing point index: " + line.str());
   }
   return std::make_pair(index, pt);
}

Set<int> SimpleGeometryParser::get_facet()
{
   Set<int> facet;
   int vertex;
   while (line >> vertex) facet += vertex;
   if (!line.eof())
      throw std::runtime_error("error parsing vertex list: " + line.str());
   return facet;
}

} }

#endif // _POLYMAKE_SIMPLE_GEOMETRY_PARSER_H

// Local Variables:
// mode:C++
// c-basic-offset:3
// End:
