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

#ident "$Project: polymake $$Id: Poly.cc,v 1.58 2006/01/19 14:21:19 gawrilow Exp $"

#if defined(__GNUC__) && __GNUC__==3 && __GNUC_MINOR__<3 && !defined(__APPLE__) && !defined(__COMO__)
#pragma implementation
#endif

#include <Poly.h>
#include <Polybuf.h>
#include <CharBuffer.h>

namespace pm { namespace client {

void Object::init(const char *object_arg, std::ios::openmode mode_arg, const char *obj_type)
{
   if (mode
       || !mode_arg
       || (mode_arg & ~(std::ios::in|std::ios::out|std::ios::trunc))
       || (mode_arg & (std::ios::out|std::ios::trunc)) == std::ios::trunc)
      throw std::logic_error("Poly: invalid open mode");

   mode=mode_arg;
   id=streambuf_holder::inst()->new_object(object_arg, !(mode_arg & std::ios::trunc), obj_type);
}

Object::~Object()
{
   if (mode)
      streambuf_holder::inst()->delete_object(id);
}

std::iostream Object::stream_inst(0);

void Object::set_options(const char* opt_arg)
{
   streambuf_holder::inst()->set_options(opt_arg);
}

bool Object::client_mode()
{
   return streambuf_holder::inst()->client_mode();
}

void Object::send_cmd(const char *cmd)
{
   streambuf_holder::get()->send_cmd(id, cmd, false);
}

void Object::send_arg(const char *arg)
{
   streambuf_holder::get()->send_arg(arg);
}

bool Object::send_last_arg_and_ret()
{
   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_arg(0);
   return mybuf->sbumpc();
}

Object::istream_germ Object::give (const char *req)
{
   if (!(mode & std::ios::in))
      throw std::logic_error("Poly::give() in write-only mode");

   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_cmd(id, "give", req);
   mybuf->check_exception();
   mybuf->start_input();
   return istream_germ(mybuf);
}

Object::istream_germ Object::lookup (const char *req)
{
   if (!(mode & std::ios::in))
      throw std::logic_error("Poly::lookup() in write-only mode");

   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_cmd(id, "look", req);
   mybuf->check_exception();
   mybuf->start_input();
   return istream_germ(mybuf, std::ios::badbit);
}

Object::ostream_germ Object::take (const char *req)
{
   if (!(mode & std::ios::out))
      throw std::logic_error("Poly::take() in read-only mode");

   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_cmd(id, "take", req, false);
   return ostream_germ(mybuf);
}

Object::istream_germ::istream_germ(streambuf *buf)
   : super(Object::stream_inst)
{
   is->rdbuf(buf);
   is->exceptions(is->failbit | is->badbit);
}

Object::istream_germ::istream_germ(streambuf *buf, std::ios::iostate exc_flags)
   : super(Object::stream_inst)
{
   is->rdbuf(buf);
   is->exceptions(exc_flags);
   if (buf->name.empty()) is->setstate((is->failbit | is->eofbit) & ~exc_flags);
}

Object::ostream_germ::ostream_germ(streambuf *buf)
   : super(Object::stream_inst)
{
   os->rdbuf(buf);
   os->precision(20);
   os->exceptions(os->failbit | os->badbit);
}

static const char undefined_token[]= "==UNDEF==\n";

void Object::ostream_germ::operator<< (const undefined&)
{
   os->write(undefined_token, sizeof(undefined_token)-1);
}

Object::istream_germ::~istream_germ()
{
   if (is) {
      is->exceptions(is->goodbit);
      streambuf *mybuf=(streambuf*)is->rdbuf(0);
      mybuf->clear_input();
      is=0;
   }
}

Object::ostream_germ::ostream_germ(const ostream_germ& other)
   : super(other)
{
   const_cast<ostream_germ&>(other).os=0;
}

Object::ostream_germ::~ostream_germ()
{
   if (os) {
      os->exceptions(os->goodbit);
      streambuf *mybuf=(streambuf*)os->rdbuf(0);
      mybuf->finish_output();
   }
}

const std::string& Object::given() const
{
   return streambuf_holder::get()->name;
}

bool Object::exists (const char *req)
{
   if (!(mode & std::ios::in))
      throw std::logic_error("Poly::exists() in write-only mode");

   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_cmd(id, "exis", req);
   return mybuf->sbumpc();
}

bool Object::defined (const char *req)
{
   if (!(mode & std::ios::in))
      throw std::logic_error("Poly::defined() in write-only mode");

   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_cmd(id, "defi", req);
   return mybuf->sbumpc();
}

bool Object::isa (const char *type)
{
   if (!mode) return false;
   streambuf *mybuf=streambuf_holder::get();
   mybuf->send_cmd(id, "isa_", type);
   return mybuf->sbumpc();
}

std::string Object::type()
{
   std::string t;
   if (mode) {
      streambuf *mybuf=streambuf_holder::get();
      mybuf->send_cmd(id, "type");
      CharBuffer::get_string(mybuf, t, '\n');
   }
   return t;
}

} } // end namespace pm::client
