package ilog.language.design.base;

/**
 * @version     Last modified on Thu Apr 11 14:02:03 2002 by hak
 * @author      <a href="mailto:hak@ilog.fr">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; 2001 <a href="http://www.ilog.fr/">ILOG, S.A.</a>
 */

import java.lang.reflect.Array;
import ilog.language.design.backend.*;
import ilog.language.design.backend.Runtime;

public class ArrayInitialize extends Instruction
{
  public ArrayInitialize ()
    {
      setName("ARRAY_INITIALIZE");
    }

public final void execute (Runtime r) throws NullValueException,
                                             SizeMatchException,
                                             ArrayAllocationErrorException
    {
      int dimension = r.popInt();
      Object[] indexables = new Object[dimension];
      for (int i=0; i<dimension; i++)
        indexables[i] = r.popObject("can't allocate a map with a null indexable");
      r.pushObject(_initializeArray(indexables, r.popObject(),0));
      r.incIP();
    }

  private Object _initializeArray(Object[] indexables, Object object, int index)
    {
      if (object == null)
        return object;

      if (index == indexables.length)
        return object;

      if (indexables[index] instanceof RuntimeInt)
        {
          int neededSize = ((RuntimeInt)indexables[index]).value();
          int actualSize = Array.getLength(object);

          if (neededSize != actualSize)
            throw new SizeMatchException("can't initialize an array of size "+neededSize+
                                         " with an array of size "+actualSize);

          if (!(object instanceof int[] || object instanceof double[]))
            {
              Object[] array = (Object[])object;
              for (int i=0; i<neededSize; i++)
                array[i] = _initializeArray(indexables,array[i],index+1);
            }

          return object;
        }

      Indexable indexable = (Indexable)indexables[index];
      int neededSize = indexable.size();

      if (!(object instanceof RuntimeMap))  // this is a native array
        {
          int actualSize = Array.getLength(object);

          if (neededSize != actualSize)
            throw new SizeMatchException("can't initialize a map of size "+neededSize+
                                         " with an array of size "+actualSize);

          if (object instanceof int[])
            return new IntMap((int[])object,indexable);

          if (object instanceof double[])
            return new RealMap((double[])object,indexable);

          Object[] array = (Object[])object;
          for (int i=0; i<neededSize; i++)
            array[i] = _initializeArray(indexables,array[i],index+1);

          return new ObjectMap(array,indexable);
        }

      RuntimeMap map = (RuntimeMap)object;

      if (indexable instanceof IntRange && map.indexable() instanceof IntSet)
        map.setIndexable(((IntSet)map.indexable()).toIntRange());

      if (indexable instanceof IntSet && map.indexable() instanceof IntRange)
        map.setIndexable(((IntRange)map.indexable()).toIntSet());

      if (!indexable.equals(map.indexable()))
        throw new ArrayAllocationErrorException
          ("can't initialize a map from one with a different index set");

      if (!(map instanceof IntMap || map instanceof RealMap))
        {
          Object[] array = (Object[])map.extractArray();
          for (int i=0; i<neededSize; i++)
            array[i] = _initializeArray(indexables,array[i],index+1);
        }

      return map;
    }
}
