// FILE. . . . . d:/hak/hlt/src/hlt/fot/Signature.java
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Hak-Laptop
// STARTED ON. . Sat Jul 14 07:23:54 2018

package hlt.fot;

import hlt.language.util.ArrayList;

import java.util.HashMap;
import java.util.Iterator;

/**
 * This is a class containing all the information concerning a
 * term-constructor signature as a set of <a
 * href="Functor.html"><tt>Functor</tt></a> objects.
 *
 * @see         Functor
 * @see         FirstOrderTermStructure
 *
 * @version     Last modified on Wed Nov 13 14:29:44 2019 by hak
 * @author      <a href="mailto:hak@acm.org">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; <a href="http://www.hassan-ait-kaci.net/">Hassan A&iuml;t-Kaci</a>
 */

public class Signature
{
  protected int size = 0;

  public int size ()
  {
    return size;
  }
  
  public boolean isEmpty ()
  {
    return size == 0;
  }

  /**
   * Constructs a new empty signature.
   */
  public Signature ()
  {
  }

  /**
   * Contains the functors.
   */
  protected ArrayList functors;

  /**
   * Returns the functors as an <tt>ArrayList</tt> of <tt>Functor</tt>
   * objects.
   */
  public ArrayList functors ()
  {
    if (functors == null)
      return functors = new ArrayList();

    return functors;
  }

  /**
   * Returns the functor at position <tt>functorPosition</tt>, where <tt>1</tt>
   * &le; <tt>functorPosition</tt> &le; <tt>signature.size()</tt>. If this
   * signature is empty, returns <tt>null</tt>.
   */
  public Functor functor (int functorPosition)
  {
    // HACK: Should NEVER happen!
    // if (functorPosition == 0) functorPosition = 1;

    return (Functor)functors().get(functorPosition-1);
  }

  /**
   * Contains an access-by-name table;
   */
  protected HashMap functorNameTable;

  protected HashMap functorNameTable ()
  {
    if (functorNameTable == null)
      return functorNameTable = new HashMap();

    return functorNameTable;
  }

  /**
   * Resets this signature to empty.
   */
  public void clear ()
  {
    functors.clear();
    functorNameTable.clear();
  }

  /**
   * Returns the functor called <tt>name</tt> in this signature if it is
   * not empty; undefined otherwise (returns <tt>null</tt>).
   */
  public Functor functor (String name)
  {
    return (Functor)functorNameTable().get(name);
  }

  /**
   * Returns the functor <tt>name</tt>/<tt>arity</tt> if it is already
   * defined in this signature, adding it to this signature if not
   * already there. If this functor's name was already defined but with
   * a different arity, throws a <a
   * href="BadFunctorArityException.html"><tt>BadFunctorArityException</tt></a>. If
   * all ok, returns the functor.
   */
  public Functor functor (String name, int arity)
  {
    Functor functor = (Functor)functorNameTable().get(name);
    
    if (functor == null)
      { // this is a new functor: need to create it and add it to this signature
	functor = new Functor(size++,name,arity,this);
	functors().add(functor);
	functorNameTable().put(name,functor);
      }
    else
      if (arity != functor.arity())
	throw new BadFunctorArityException(functor,arity);

    return functor;
  }

  /* ************************************************************************ */

  public Iterator iterator ()
    {
      return functors().iterator();
    }

  /* ************************************************************************ */

  /**
   * Return a string form for this signature.
   */
  public String toString ()
  {
    return setForm();
  }

  protected String setForm ()
  {
    StringBuilder form = new StringBuilder("{");

    for (int i=0; i<size; i++)
      {
	Functor functor = (Functor)functors().get(i);
	form.append(functor+"/"+functor.arity()+(i<size-1?", ":""));
      }

    form.append("}");
    
    return form.toString();
  }

}
