// A state in the property automaton -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "PropertyState.h"
#include "Constant.h"
#include "BitVector.h"
#include "LeafValue.h"
#include <string.h>

/** @file PropertyState.C
 * A state in the property automaton
 */

/* Copyright © 2000-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. */

PropertyState::~PropertyState ()
{
  delete[] mySuccessors;
  while (myNumSuccessors--)
    myGates[myNumSuccessors]->destroy ();
  delete[] myGates;
}

void
PropertyState::addSuccessor (unsigned num,
			     class Expression& gate)
{
  /** Flag: is this a constant (constantly enabled) gate */
  bool constant = gate.getKind () == Expression::eConstant;

  if (constant) {
    const class Value& v = static_cast<class Constant&>(gate).getValue ();
    assert (v.getKind () == Value::vLeaf);
    // Ignore constantly disabled gates
    if (!bool (static_cast<const class LeafValue&>(v))) {
      gate.destroy ();
      return;
    }
  }

  unsigned i = myNumSuccessors++;
  unsigned* successors = new unsigned[myNumSuccessors];
  class Expression** gates = new class Expression*[myNumSuccessors];
  if (constant) {
    // add constantly enabled gates to the beginning of the array
    memcpy (successors + 1, mySuccessors, i * sizeof *successors);
    memcpy (gates + 1, myGates, i * sizeof *gates);
    *successors = num;
    *gates = &gate;
  }
  else {
    // add conditionally enabled gates to the end of the array
    memcpy (successors, mySuccessors, i * sizeof *successors);
    memcpy (gates, myGates, i * sizeof *gates);
    successors[i] = num;
    gates[i] = &gate;
  }
  delete[] mySuccessors;
  delete[] myGates;
  mySuccessors = successors;
  myGates = gates;
}

bool
PropertyState::eval (const class Valuation& valuation,
		     unsigned*& result,
		     unsigned final) const
{
  assert (valuation.isOK ());
  *(result = new unsigned[myNumSuccessors + 1]) = 0;
  for (unsigned i = myNumSuccessors; i--; ) {
    if (class Value* v = myGates[i]->eval (valuation)) {
      assert (valuation.isOK ());
      assert (v->getKind () == Value::vLeaf);
      if (bool (static_cast<const class LeafValue&>(*v))) {
	result[++(*result)] = mySuccessors[i];
	delete v;
	if (mySuccessors[i] == final)
	  return false;
      }
      else
	delete v;
    }
    else {
      assert (!valuation.isOK ());
      return false;
    }
  }

  return true;
}

#ifdef EXPR_COMPILE
# include "CExpression.h"

void
PropertyState::compileGates (class CExpression& cexpr,
			     unsigned indent,
			     const char* result,
			     unsigned final) const
{
  class StringBuffer& out = cexpr.getOut ();
  out.indent (indent);
  out.append ("*"), out.append (result), out.append ("=0;\n");
  for (unsigned i = myNumSuccessors; i--; ) {
    if (myGates[i]->getKind () == Expression::eConstant) {
      const class Value& v =
	static_cast<const class Constant*>(myGates[i])->getValue ();
      assert (v.getKind () == Value::vLeaf);
      if (!bool (static_cast<const class LeafValue&>(v)))
	continue;
      out.indent (indent);
    }
    else {
      const char* work = cexpr.getFlag ();
      myGates[i]->compile (cexpr, indent, work, 0);
      out.indent (indent);
      out.append ("if ("), out.append (work), out.append (") ");
    }
    if (mySuccessors[i] == final) {
      out.append ("{\n");
      cexpr.compileError (indent + 2, errNone);
      out.indent (indent + 2);
    }
    out.append (result);
    out.append ("[++(*"), out.append (result); out.append (")]=");
    out.append (mySuccessors[i]), out.append (";\n");
    if (mySuccessors[i] == final) {
      out.indent (indent + 2), out.append ("return errComp;\n");
      out.indent (indent), out.append ("}\n");
    }
  }
  cexpr.compileError (indent, errNone);
}
#endif // EXPR_COMPILE
