/*
 * Module.C - methods for L-System module handling.
 *
 * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
 *                     University of Berne, Switzerland
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 *
 */

#include "Module.h"
#include "Error.h"

implementList(ExpressionList, ExpressionPtr);
implementList(ValueList, ValuePtr);
implementList(ModuleList, ModulePtr);
implementList(ProdModuleList, ProdModulePtr);

//___________________________________________________________ Formals

const int MAX_PARAMETERS = 100;
static Value Parameters[100];

Value* Formals(int i)
{
  if (i>=MAX_PARAMETERS)
    Error(ERR_PANIC, "Formals: index out of range");
  return &Parameters[i];
}

//___________________________________________________________ ProdModule

ProdModule::ProdModule(const Name& n, ExpressionList* expressions)
: name(n), parameters(expressions)
{
  extern unsigned int modHash(const char*, long);
  if (expressions)
    hashValue = modHash((const char*) n, expressions->count());
  else
    hashValue = modHash((const char*) n, 0L);
}

ProdModule::~ProdModule()
{
  if (parameters) {
    for (long i=0; i<parameters->count(); i++)
      delete parameters->item(i);
    delete parameters;
  }
}

ostream& operator<<(ostream& os, const ProdModule& m)
{
  os << m.name;
  if (m.parameters) {
    os << '(';
    for (long i=0; i<m.parameters->count()-1; i++)
      os << *m.parameters->item(i) << ", ";    
    os << *m.parameters->item(i) << ')';
  }
  return os;
}

//___________________________________________________________ Module

// Evaluate the parameter of the ProdModule and store the results
//  as the constant arguments of the module
Module::Module(ProdModule* m)
: _name(m->name), _hashValue(m->hashValue)
{
  if (m->parameters) {
    parameters = new ValueList(m->parameters->count());
    for (register long i=0; i<m->parameters->count(); i++)
      parameters->append(new Value(m->parameters->item(i)->evaluate()));
  }
  else
    parameters = NULL;
}

Module::~Module()
{
  if (parameters) {
    for (long i=0; i<parameters->count(); i++)
      delete parameters->item(i);
    delete parameters;
  }
}

// Binding is done by assigning the actual parameters of the module
//  to the Formals-array. This works because all the variables of the
//  productions points to this array!
void Module::bind()
{
  if (parameters)
    for (register long i=0; i<parameters->count(); i++)
      Parameters[i] = *parameters->item(i);
}

ostream& operator<<(ostream& os, const Module& m)
{
  os << m._name;
  if (m.parameters) {
    os << '(';
    for (long i=0; i<m.parameters->count()-1; i++)
      os << *m.parameters->item(i) << ", ";
    os << *m.parameters->item(i) << ')';
  }
  return os;
}
