//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// PLEASE DO NOT EDIT WITHOUT THE EXPLICIT CONSENT OF THE AUTHOR! \\
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\

package ilog.language.design.kernel;

/**
 * @version     Last modified on Fri Oct 18 17:51:39 2002 by hak
 * @version          modified on Thu Jul 18 17:45:46 2002 by pviry
 * @author      <a href="mailto:hak@ilog.fr">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; 2000-2002 <a href="http://www.ilog.fr/">ILOG, S.A.</a>
 */

import ilog.language.design.types.*;
import ilog.language.design.base.*;
import ilog.language.tools.Misc;

import java.util.ArrayList;

/**
 * This is the class representing tuples whose components are identified by field names.
 * It derives from <a href="./Tuple.html"><tt>Tuple</tt></a>, and in addition keeps an
 * array of <a href="./TupleFieldName.html"><tt>TupleFieldName</tt></a>s recording the
 * names.  The reason for using <tt>TupleFieldName</tt>s rather than <tt>String</tt>s is
 * so that the array of field names may be sorted lexicographically for the purpose of
 * normalizing all named tuples and named tuple types, while recording their original
 * indices for displaying components in their "original" order. Note that this notion is
 * rather fuzzy as it corresponds to the ordering of components found by the constructor
 * (which is meant to be used by a parser) and can only be that of a specific written
 * named tuple (type) occurrence. Thus, this order may only be <i>one</i> among many if
 * distinct occurrences of this type, or tuples of this type, are written using
 * differring orders of components. Nevertheless, for consistently written tuples, the
 * components will be displayed in the expected order.
 *
 * <p>
 *
 * <b>N.B.</b>: the names in a named tuple may not be overloaded (<i>i.e.</i>, the same
 *              name cannot appear more than once in a named tuple with distinct types.
 */

public class NamedTuple extends Tuple
{
  private TupleFieldName[] _fields;
  // Should the field names be considered subexpressions? In this version, they ain't!

  private NamedTuple (Expression[] components, TupleFieldName[] fields)
    {
      _components = components;
      _fields = fields;
    }

  public NamedTuple (ArrayList components, ArrayList names)
    {
      // NB: this assumes that both lists are non-empty, and have the same size.

      _fields = new TupleFieldName[names.size()];
      for (int i=0; i<_fields.length; i++)
        _fields[i] = new TupleFieldName((String)names.get(i),i);
      if(_fields.length>0)
          Misc.sort(_fields);

     _components = new Expression[components.size()];
      for (int i=0; i<_components.length; i++)
        _components[i] = (Expression)components.get(_fields[i].index());
    }

  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      if (typeCheckLocked()) return;

      _checkDuplicateFields(typeChecker);

      Type[] componentTypes = new Type[dimension()];

      for (int i=dimension(); i-->0;)
        _components[i].typeCheck(componentTypes[i] = new TypeParameter(),typeChecker);

      typeChecker.typeCheck(this,new NamedTupleType(componentTypes,_fields));
    }

  private final void _checkDuplicateFields (TypeChecker typeChecker) throws TypingErrorException
    {
      TupleFieldName field = null;
      for (int i=_fields.length; i-->0;)
        {
          if (_fields[i].equals(field))
            typeChecker.error(new TypingErrorException("duplicate field: "+field).setExtent(this));
          field = _fields[i];
        }
    }

  public final String toString ()
    {
      int[] index = new int[dimension()];

      for (int i=0; i<index.length; i++)
        index[_fields[i].index()] = i;

      StringBuffer buf = new StringBuffer("<");

      for (int i=0; i<dimension(); i++)
        buf.append(_fields[index[i]])
           .append("=")
           .append(component(index[i]))
           .append(i==dimension()-1?"":",");

      return buf.append(">").toString();
    }
}
