//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// 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:43 2002 by hak
 * @version          modified on Wed Jul 24 12:19:08 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 java.util.ArrayList;

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

/**
 * This is the class denoting sets.
 */

public class NewSet extends ProtoExpression 
{
  /**
   * This is the set's <i>base type</i> (<i>i.e.</i>, the type of its elements).
   */
  private Type _baseType;

  /**
   * This array contains expressions denoting elements of this set.
   */
  private Expression[] _elements;

  public NewSet ()
    {
      _baseType = new TypeParameter();
    }  

  public NewSet (Type baseType)
    {
      _baseType = baseType;
    }  

  public NewSet (ArrayList elements)
    {
      this(new TypeParameter(),elements);
    }

  public NewSet (Type baseType, ArrayList elements)
    {
      _baseType = baseType;
      if (!(elements == null || elements.isEmpty()))
        {
          _elements = new Expression[elements.size()];

          for (int i = _elements.length; i--> 0;)
            _elements[i] = (Expression)elements.get(i);
        }
    }

  public final int numberOfSubexpressions ()
    {
      return _elements == null ? 0 : _elements.length;
    }

  public final Expression subexpression (int n) throws NoSuchSubexpressionException
    {
      if (_elements == null || n < 0 || n >= _elements.length)
        throw new NoSuchSubexpressionException(this,n);

      return _elements[n];
    }

  public final Expression[] elements ()
    {
      return _elements;
    }

  public final Type baseType ()
    {
      return _baseType.value();
    }

  public final Type baseTypeRef ()
    {
      return _baseType;
    }

  public final Expression sanitizeNames (ParameterStack parameters, ClassTypeHandle handle)
    {
      for (int i = numberOfSubexpressions(); i--> 0;)
        _elements[i] = _elements[i].sanitizeNames(parameters, handle);

      return this;
    }

  public final void sanitizeSorts (Enclosure enclosure)
    {
      for (int i = numberOfSubexpressions(); i--> 0;)
        _elements[i].sanitizeSorts(enclosure);
    }

  public final Expression shiftOffsets (int intShift, int realShift, int objectShift,
                                        int intDepth, int realDepth, int objectDepth)
    {
      for (int i = numberOfSubexpressions(); i--> 0;)
        _elements[i] = _elements[i].shiftOffsets(intShift,realShift,objectShift,
                                                 intDepth,realDepth,objectDepth);

      return this;
    }

  public final void setCheckedType ()    
    {
      if (isSetCheckedType()) return;
      for (int i = numberOfSubexpressions(); i--> 0;)
        _elements[i].setCheckedType();

      setCheckedType(type().copy());
    }

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

      for (int i = numberOfSubexpressions(); i--> 0;)
        _elements[i].typeCheck(_baseType,typeChecker);

      typeChecker.typeCheck(this,new SetType(_baseType));
    }

  public final void compile (Compiler compiler)
    {
      if (_elements != null)
        {
          for (int i = _elements.length; i--> 0;)
            _elements[i].compile(compiler);

          compiler.generate(new PushValueInt(_elements.length));
        }

      switch (((SetType)_checkedType).baseType().boxSort())
        {
        case Type.INT_SORT:
          compiler.generate(_elements == null ? Instruction.PUSH_SET_I
                                              : Instruction.MAKE_SET_I);
          return;
        case Type.REAL_SORT:
          compiler.generate(_elements == null ? Instruction.PUSH_SET_R
                                              : Instruction.MAKE_SET_R);
          return;
        default: 
          compiler.generate(_elements == null ? Instruction.PUSH_SET_O
                                              : Instruction.MAKE_SET_O);
        }         
    }

  public final String toString ()
    {
      if (_elements == null)
        return "new {"+(_checkedType == null ? "" : _checkedType.toString()) + "}";

      StringBuffer buf = new StringBuffer("set {");

      for (int i = 0; i < _elements.length; i++)
        buf.append(_elements[i]+(i==_elements.length-1 ? "}" : ","));

      return buf.toString();
    }

  // Added by PV
  public final String toTypedString ()
    {
      if (_elements == null)
        return "new {"+(_checkedType == null ? "" : _checkedType.toString()) + "}";

      StringBuffer buf = new StringBuffer("set {");

      for (int i = 0; i < _elements.length; i++)
        buf.append(_elements[i].toTypedString()+(i==_elements.length-1 ? "}" : ","));

      return typed(buf.toString());
    }
}
