// Valuation (value distribution for variables) -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "Valuation.h"
#include "Value.h"
#include "VariableDefinition.h"
#ifndef NDEBUG
# include "Type.h"
#endif // NDEBUG

/** @file Valuation.C
 * Assignment of variables to values
 */

/* Copyright © 1999-2001 Marko Mäkelä (msmakela@tcs.hut.fi).

   This file is part of MARIA, a reachability analyzer and model checker
   for high-level Petri nets.

   MARIA 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.

   MARIA 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.

   The GNU General Public License is often shipped with GNU software, and
   is generally kept in a file called COPYING or LICENSE.  If you do not
   have a copy of the license, write to the Free Software Foundation,
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */

Valuation::Valuation () :
  myValues (), myError (errNone), myExpr (0), myGlobalMarking (0)
{
}

Valuation::Valuation (const class Valuation& old) :
  myValues (), myError (old.myError), myExpr (old.myExpr),
  myGlobalMarking (old.myGlobalMarking)
{
  for (const_iterator i = old.myValues.begin (); i != old.myValues.end ();
       i++) {
    assert (i->second != NULL);
    myValues[i->first] = i->second->copy ();
  }
}

Valuation::~Valuation ()
{
  for (iterator i = myValues.begin (); i != myValues.end (); i++)
    delete i->second;
}

const class Value*
Valuation::getValue (const class VariableDefinition& var) const
{
  const_iterator i = myValues.find (&var);
  if (i == myValues.end ())
    return NULL;

  return i->second;
}

void
Valuation::setValue (const class VariableDefinition& var, class Value& value)
{
  assert (var.getType ().isConstrained (value));
  Map::value_type p (&var, &value);
  std::pair<iterator, bool> status = myValues.insert (p);
  if (!status.second) {
    delete status.first->second;
    myValues.erase (status.first);
    status = myValues.insert (p);
    assert (status.second);
  }
}

bool
Valuation::increment (const class VariableDefinition& var)
{
  const_iterator i = myValues.find (&var);
  assert (i != myValues.end ());
  return i->second->increment ();
}

bool
Valuation::decrement (const class VariableDefinition& var)
{
  const_iterator i = myValues.find (&var);
  assert (i != myValues.end ());
  return i->second->decrement ();
}

bool
Valuation::undefine (const class VariableDefinition& var)
{
  iterator i = myValues.find (&var);
  if (i == myValues.end ())
    return false;
  delete i->second;
  myValues.erase (i);
  return true;
}

const char*
Valuation::msg (enum Error err)
{
  switch (err) {
  case errNone:
    return "noError";
  case errConst:
    return "constraintViolation";
  case errVar:
    return "undefinedVariable";
  case errUndef:
    return "undefinedExpression";
  case errFatal:
    return "fatalExpression";
  case errDiv0:
    return "divisionByZero";
  case errOver:
    return "overflow";
  case errMod:
    return "modulusError";
  case errShift:
    return "shiftError";
  case errUnion:
    return "unionViolation";
  case errBuf:
    return "bufferViolation";
  case errCard:
    return "cardinalityOverflow";
  case errComp:
    return "unificationError";
  }
  assert (false);
  return 0;
}

#include "Printer.h"
#include "Expression.h"
void
Valuation::display (const class Printer& printer,
		    bool hide) const
{
  printer.delimiter ('<')++;
  if (myError) {
    printer.printRaw (msg (myError));
    if (myExpr) {
      printer.delimiter (':');
      printer++.linebreak ();
      myExpr->display (printer);
      printer--;
    }
  }
  else
    assert (!myExpr);

  for (const_iterator i = myValues.begin (); i != myValues.end (); i++) {
    if (hide && i->first->isHidden ())
      continue;
    printer.linebreak ();
    printer.print (i->first->getName ());
    printer.delimiter (':')++;
    i->second->display (printer);
    printer--;
  }

  printer--.linebreak ();
  printer.delimiter ('>');
}

void
Valuation::displayEscaped (class StringBuffer& out,
			   bool hide) const
{
  assert (!myError);
  class Printer printer;
  printer.setOutput (&out);
  for (const_iterator v = myValues.begin (); v != myValues.end (); v++) {
    if (hide && v->first->isHidden ())
      continue;
    out.append ('_', 2);
    unsigned i = out.getLength ();
    out.append (v->first->getName ());
    out.escape (i);
    out.append ('_', 2);
    i = out.getLength ();
    v->second->display (printer);
    out.escape (i);
  }
}
