package ilog.language.design.kernel;

/**
 * @version     Last modified on Thu Apr 11 14:58:44 2002 by hak
 * @author      <a href="mailto:hak@ilog.fr">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; 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 an array literal - <i>i.e.</i>, expressions enumerating
 * elements that comprise the extension of an array or map. This always a unidimensional
 * array.
 */

public class ArrayExtension extends Expression 
{
  /**
   * This contains the extension.
   */
  private Expression[] _extension;

  /**
   * This is the indexable, eventually.
   */
  private NewSet _indexable;

  private Type _type = new TypeParameter();
  private Type _checkedType;

  public ArrayExtension (ArrayList extension, ArrayList indices)
    {
      if (extension != null)
        {
          _extension = new Expression[extension.size()];

          for (int i=_extension.length; i-->0;)
            _extension[i] = (Expression)extension.get(i);

          if (indices != null)
            _indexable = new NewSet(indices);
        }
    }  

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

  public final int numberOfSubexpressions ()
    {
      return size() + (_indexable == null ? 0 : 1);
    }

  public final Expression subexpression (int n) throws NoSuchSubexpressionException
    {
      if (0 <= n && n < size())
        return _extension[n];

      if (n == size() && _indexable != null)
        return _indexable;

      throw new NoSuchSubexpressionException(this,n);
    }

  public final Expression[] extension ()
    {
      return _extension;
    }

  public final NewSet indexable ()
    {
      return _indexable;
    }

  public final Type type ()
    {
      return _type.value();
    }

  public final void setType (Type type)
    {
      _type = type;
    }

  public final Type typeRef ()
    {
      return _type;
    }

  public final Type checkedType ()
    {
      return _checkedType;
    }

  public final void setCheckedType (Type type)
    {
      _checkedType = type;
    }

  public final Expression sanitizeNames (ParameterStack parameters)
    {
      for (int i=0; i<_extension.length; i++)
        _extension[i] = _extension[i].sanitizeNames(parameters);

      if (_indexable != null)
        _indexable = (NewSet)_indexable.sanitizeNames(parameters);

      return this;
    }

  public final void sanitizeSorts (Enclosure enclosure)
    {
      for (int i=0; i<_extension.length; i++)
        _extension[i].sanitizeSorts(enclosure);

      if (_indexable != null)
        _indexable.sanitizeSorts(enclosure);
    }

  public final Expression shiftOffsets (int intShift, int realShift, int objectShift,
                                        int intDepth, int realDepth, int objectDepth)
    {
      for (int i=0; i<_extension.length; i++)
        _extension[i] = _extension[i].shiftOffsets(intShift,realShift,objectShift,
                                                   intDepth,realDepth,objectDepth);

      if (_indexable != null)
        _indexable = (NewSet)_indexable.shiftOffsets(intShift,realShift,objectShift,
                                                     intDepth,realDepth,objectDepth);

      return this;
    }

  public final void setCheckedType ()    
    {
      for (int i=_extension.length; i-->0;)
        _extension[i].setCheckedType();

      if (_indexable != null)
        _indexable.setCheckedType();

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

  public final void typeCheck (TypeChecker typeChecker) throws TypingErrorException
    {
      TypeParameter baseType = new TypeParameter();
      TypeParameter indexSetType = new TypeParameter();

      for (int i=0; i<_extension.length; i++)
        _extension[i].typeCheck(baseType,typeChecker);

      if (_indexable == null)
        typeChecker.unify(indexSetType,Type.INT());
      else
        _indexable.typeCheck(indexSetType,typeChecker);

      typeChecker.typeCheck(this,new ArrayType(baseType,indexSetType));
    }

  public final void compile (Compiler compiler)
    { // compile: (1) the extension
      //          (2) the size
      //          (3) the indexable, if there is one
      //          (4) MAKE_[ARRAY,MAP]_[I,R,O]

      for (int i = size(); i-->0;)
        _extension[i].compile(compiler);

      compiler.generate(new PushValueInt(size()));

      if (_indexable == null)
        switch (((ArrayType)_checkedType).baseType().boxSort())
          {
          case Type.INT_SORT:
            compiler.generate(Instruction.MAKE_ARRAY_I);
            return;
          case Type.REAL_SORT:
            compiler.generate(Instruction.MAKE_ARRAY_R);
            return;
          default:
            compiler.generate(Instruction.MAKE_ARRAY_O);
            return;
          }

      _indexable.compile(compiler);

      switch (((ArrayType)_checkedType).baseType().boxSort())
        {
        case Type.INT_SORT:
          compiler.generate(Instruction.MAKE_MAP_I);
          return;
        case Type.REAL_SORT:
          compiler.generate(Instruction.MAKE_MAP_R);
          return;
        default:
          compiler.generate(Instruction.MAKE_MAP_O);
        }
    }


  public final String toString ()
    {
      StringBuffer buf = new StringBuffer("#[");

      if (_indexable == null)
        for (int i=0; i<_extension.length; i++)
          buf.append(_extension[i])
             .append(i == _extension.length-1 ? "" : ",");
      else
        {
          Expression[] elements = _indexable.elements();
          for (int i=0; i<_extension.length; i++)
            buf.append(elements[i]).append(":").append(_extension[i])
               .append(i == _extension.length-1 ? "" : ",");;
        }

      return buf. append("]#").toString();
    }
}




