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

#ifndef VALUATION_H_
# define VALUATION_H_
# ifdef __GNUC__
#  pragma interface
# endif // __GNUC__

# include <assert.h>
# include <map>
# include "Error.h"

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

/* Copyright © 1999-2002 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 (value distribution for variables) */
class Valuation
{
  /** Pointer comparator */
  struct vptr
  {
    bool operator () (const class VariableDefinition* v1,
		      const class VariableDefinition* v2) const {
      return v1 < v2;
    }
  };
public:
  /** Map from variables to their values */
  typedef std::map<const class VariableDefinition*,class Value*,vptr> Map;
  /** Iterator to the valuation map */
  typedef Map::iterator iterator;
  /** Constant iterator to the valuation map */
  typedef Map::const_iterator const_iterator;

  /** Constructor */
  Valuation ();
  /** Copy constructor */
  Valuation (const class Valuation& old);
private:
  /** Assignment operator */
  class Valuation& operator= (const class Valuation& old);
public:
  /** Destructor */
  ~Valuation ();

  /** Get the value of a variable
   * @param var		identifies the variable
   * @return		the value, or NULL if there is none
   */
  const class Value* getValue (const class VariableDefinition& var) const;

  /** Assign a value to a variable.  If the variable already has a value,
   * delete the old value.
   * @param var		identifies the variable
   * @param value	value to be assigned
   */
  void setValue (const class VariableDefinition& var, class Value& value);

  /** Get the global marking */
  const class GlobalMarking* getGlobalMarking () const {
    return myGlobalMarking;
  }
  /** Set the global marking
   * @param m		the new global marking
   */
  void setGlobalMarking (const class GlobalMarking* m) {
    myGlobalMarking = m;
  }

  /** Increase the value of a variable in the valuation
   * @param var		identifies the variable
   * @return		false if the value wrapped around; otherwise true
   */
  bool increment (const class VariableDefinition& var);
  /** Decrease the value of a variable in the valuation
   * @param var		identifies the variable
   * @return		false if the value wrapped around; otherwise true
   */
  bool decrement (const class VariableDefinition& var);

  /** Remove the value of a variable from the valuation
   * @param var		identifies the variable
   * @return		true if the value was previously defined
   */
  bool undefine (const class VariableDefinition& var);

  /** Iterator to the beginning of the assignment collection */
  const_iterator begin () const { return myValues.begin (); }
  /** Iterator to the end of the assignment collection */
  const_iterator end () const { return myValues.end (); }

  /** Determine whether the valuation is clear of errors */
  bool isOK () const { return !myError; }
  /** Determine whether the valuation is clear of errors
   * or a variable is undefined */
  bool isOKorVar () const { return !myError || myError == errVar; }
  /** Clear the errors associated with the valuation */
  void clearErrors () const { myError = errNone, myExpr = 0; }
  /** Copy the errors from one valuation to another */
  void copyErrors (const class Valuation& v) const {
    myError = v.myError, myExpr = v.myExpr;
  }
  /** Read the error code */
  enum Error getError () const { return myError; }
  /** Determine which expression caused the error */
  const class Expression& getExpr () const {
    assert (!!myExpr); return *myExpr;
  }
  /** Flag an error
   * @param error	error code
   * @param expr	expression that caused the error
   */
  void flag (enum Error error,
	     const class Expression& expr) const {
    assert (error && !myError && !myExpr);
    myError = error, myExpr = &expr;
  }
  /** Flag a unification error */
  void flagUnificationError () const {
    myError = errComp;
  }
  /** Flag an undefined situation
   * @param fatal	flag: is this a fatal situation?
   */
  void flagUndefined (bool fatal) const {
    assert (!myError && !myExpr);
    myError = fatal ? errFatal : errUndef;
  }

  /** Translate an error code to an error message
   * @param err		error code
   * @return		the translated message
   */
  static const char* msg (enum Error err);

  /** Display this object
   * @param printer	The printer object
   * @param hide	Flag: omit hidden variables and values
   */
  void display (const class Printer& printer,
		bool hide = false) const;

  /** Convert the valuation to an alphanumeric identifier
   * @param out		The output stream
   * @param hide	Flag: omit hidden variables and values
   */
  void displayEscaped (class StringBuffer& out,
		       bool hide = false) const;

private:
  /** The values sorted by variable names */
  Map myValues;
  /** Errors occurred while processing the valuation */
  mutable enum Error myError;
  /** Expression that caused the error */
  mutable const class Expression* myExpr;
  /** The global marking (if available) */
  const class GlobalMarking* myGlobalMarking;
};

#endif // VALUATION_H_
