// Expression list class -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "ExpressionList.h"
#include "Expression.h"
#include <string.h>

/** @file ExpressionList.C
 * List of expressions
 */

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

ExpressionList::ExpressionList () :
  myReferences (1), mySize (0), myExprs (0)
{
}

ExpressionList::~ExpressionList ()
{
  assert (!myReferences);
  for (card_t i = 0; i < size (); i++)
    myExprs[i]->destroy ();
  delete[] myExprs;
}

void
ExpressionList::append (class Expression& expression)
{
  assert (expression.getKind () == Expression::eUndefined ||
	  expression.getKind () == Expression::eEmptySet ||
	  expression.getKind () == Expression::eMarking ||
	  expression.getType ());
  if (empty ()) {
    assert (!myExprs);
    myExprs = new class Expression*[1];
  }
  else {
    class Expression** exprs = new class Expression*[mySize + 1];
    memcpy (exprs, myExprs, mySize * sizeof *exprs);
    delete[] myExprs;
    myExprs = exprs;
  }

  myExprs[mySize++] = &expression;
}

void
ExpressionList::prepend (class Expression& expression)
{
  assert (expression.getKind () == Expression::eUndefined ||
	  expression.getKind () == Expression::eEmptySet ||
	  expression.getKind () == Expression::eMarking ||
	  expression.getType ());
  if (empty ()) {
    assert (!myExprs);
    myExprs = new class Expression*[1];
  }
  else {
    class Expression** exprs = new class Expression*[mySize + 1];
    memcpy (exprs + 1, myExprs, mySize * sizeof *exprs);
    delete[] myExprs;
    myExprs = exprs;
  }

  *myExprs = &expression, mySize++;
}

const class Type*
ExpressionList::getType () const
{
  const class Type* type = NULL;
  for (card_t i = 0; i < mySize; i++)
    if ((type = myExprs[i]->getType ()))
      break;
  return type;
}

bool
ExpressionList::isBasic () const
{
  for (card_t i = 0; i < size (); i++)
    if (!myExprs[i]->isBasic ())
      return false;
  return true;
}

bool
ExpressionList::isTemporal () const
{
  for (card_t i = 0; i < size (); i++)
    if (myExprs[i]->isTemporal ())
      return true;
  return false;
}

bool
ExpressionList::isSet () const
{
  for (card_t i = 0; i < size (); i++)
    if (myExprs[i]->isSet ())
      return true;
  return false;
}

bool
ExpressionList::operator== (const class ExpressionList& other) const
{
  if (this == &other)
    return true;
  if (size () != other.size ())
    return false;
  for (card_t i = 0; i < size (); i++)
    if (!(*myExprs[i] == *other.myExprs[i]))
      return false;
  return true;
}

bool
ExpressionList::operator< (const class ExpressionList& other) const
{
  if (this == &other)
    return false;
  if (size () < other.size ())
    return true;
  if (other.size () < size ())
    return false;
  for (card_t i = 0; i < size (); i++) {
    if (*myExprs[i] < *other.myExprs[i])
      return true;
    if (*other.myExprs[i] < *myExprs[i])
      return false;
  }
  return false;
}

class ExpressionList*
ExpressionList::ground (const class Valuation& valuation,
			class Transition* transition,
			bool declare)
{
  bool same = true;
  class ExpressionList* l = new class ExpressionList;

  for (card_t i = 0; i < size (); i++) {
    class Expression* e = myExprs[i]->ground (valuation, transition, declare);
    if (!e) {
      l->destroy ();
      return NULL;
    }

    assert (valuation.isOK ());

    if (e != myExprs[i])
      same = false;
    l->append (*e);
  }

  if (same) {
    l->destroy ();
    return copy ();
  }

  return l;
}

class ExpressionList*
ExpressionList::substitute (class Substitution& substitution)
{
  bool same = true;
  class ExpressionList* l = new class ExpressionList;

  for (card_t i = 0; i < size (); i++) {
    class Expression* e = myExprs[i]->substitute (substitution);
    if (e != myExprs[i])
      same = false;
    l->append (*e);
  }

  if (same) {
    l->destroy ();
    return copy ();
  }

  return l;
}

bool
ExpressionList::depends (const class VariableSet& vars,
			 bool complement) const
{
  for (card_t i = 0; i < size (); i++)
    if (myExprs[i]->depends (vars, complement))
      return true;
  return false;
}

bool
ExpressionList::forVariables (bool (*operation)
			      (const class Expression&,void*),
			      void* data) const
{
  for (card_t i = 0; i < size (); i++)
    if (!myExprs[i]->forVariables (operation, data))
      return false;
  return true;
}
