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

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

#include <PlainParser.h>

namespace pm { namespace client {

class streambuf;

class Object {
private:
   std::ios::openmode mode;
   int id;

   static std::iostream stream_inst;
   static bool client_mode();
   void send_cmd(const char*);
   void send_arg(const char*);
   bool send_last_arg_and_ret();

   static const char* get_str(const std::string& s) { return s.c_str(); }
   static const char* get_str(const char* s) { return s; }

public:
   Object() : mode(std::ios::openmode(0)) { }

   /// @param object_arg filename or 0 if the object is temporary
   Object(const char *object_arg, std::ios::openmode mode_arg=std::ios::in, const char *obj_type=0)
      : mode(std::ios::openmode(0))
   {
      init(object_arg,mode_arg,obj_type);
   }

   Object(const char *object_arg, std::ios::openmode mode_arg, const std::string& obj_type)
      : mode(std::ios::openmode(0))
   {
      init(object_arg,mode_arg,obj_type.c_str());
   }

   static void set_options(const char *options_arg);

   void init(const char *object_arg, std::ios::openmode mode_arg=std::ios::in, const char *obj_type=0);
   ~Object();

   std::ios::openmode get_mode() const { return mode; }

   struct undefined { };

   class istream_germ;
   class ostream_germ;

   istream_germ give(const char *req);
   istream_germ lookup(const char *req);
   ostream_germ take(const char *req);
   const std::string& given() const;
   bool exists(const char *req);
   bool defined(const char *req);
   std::string type();
   bool isa(const char *type);

   template <typename Container>
   bool provide(const Container& props)
   {
      if (client_mode())
	 return true;
      if (!(mode & std::ios::in))
	 throw std::logic_error("Poly::provide() in write-only mode");
      send_cmd("prov");
      for (typename Entire<Container>::const_iterator p=entire(props); !p.at_end(); ++p)
	 send_arg(get_str(*p));
      return send_last_arg_and_ret();
   }

   template <size_t n>
   bool provide(const char* const (&props)[n])
   {
      return provide(array2container(props));
   }

   template <typename Container>
   void remove(const Container& props)
   {
      if (mode & (std::ios::in|std::ios::out) != (std::ios::in|std::ios::out))
	 throw std::logic_error("Poly::remove() in read-only or write-only mode");
      send_cmd("remo");
      for (typename Entire<Container>::const_iterator p=entire(props); !p.at_end(); ++p)
	 send_arg(get_str(*p));
      send_arg(0);
   }

   template <size_t n>
   void remove(const char* const (&props)[n])
   {
      remove(array2container(props));
   }
};

class Object::istream_germ : public PlainParser<> {
   friend class Object;
   typedef PlainParser<> super;
protected:
   istream_germ(streambuf *buf);
   istream_germ(streambuf *buf, std::ios::iostate exc_flags);

public:
   template <typename T>
   super& operator>> (T& x)
   {
      if (!is->eof()) static_cast<super&>(*this) >> x;
      return *this;
   }

   ~istream_germ();

   template <typename T>
   operator T ()
   {
      T x;
      static_cast<super&>(*this) >> x;
      return x;
   }
};

class Object::ostream_germ : public ostream_wrapper<> {
   friend class Object;
   typedef ostream_wrapper<> super;
protected:
   ostream_germ(streambuf *buf);

public:
   template <typename T>
   super& operator<< (const T& x)
   {
      static_cast<super&>(*this) << x;
      return static_cast<super&>(*this);
   }

   // this one is void since it makes no sense to print trailing data after an UNDEFINED value
   void operator<< (const undefined&);

   ostream_germ(const ostream_germ&);
   ~ostream_germ();
};
} } // end namespace pm::client

namespace polymake {
   typedef pm::client::Object Poly;	// the historical name
}

#endif // _POLYMAKE_POLY_H

// Local Variables:
// mode:C++
// End:
