package jetbrains.mps.internal.collections.runtime;

/*Generated by MPS */

import java.lang.reflect.Array;
import jetbrains.mps.internal.collections.runtime.impl.NullSequence;
import java.util.Iterator;

public class ArrayUtils {
  public ArrayUtils() {
  }
  public static boolean[] toBooleanArray(ISequence<? extends Boolean> seq) {
    return (boolean[]) ArrayUtils.createAndFillArray(Boolean.TYPE, seq);
  }
  public static byte[] toByteArray(ISequence<? extends Byte> seq) {
    return (byte[]) ArrayUtils.createAndFillArray(Byte.TYPE, seq);
  }
  public static char[] toCharArray(ISequence<? extends Character> seq) {
    return (char[]) ArrayUtils.createAndFillArray(Character.TYPE, seq);
  }
  public static double[] toDoubleArray(ISequence<? extends Double> seq) {
    return (double[]) ArrayUtils.createAndFillArray(Double.TYPE, seq);
  }
  public static float[] toFloatArray(ISequence<? extends Float> seq) {
    return (float[]) ArrayUtils.createAndFillArray(Float.TYPE, seq);
  }
  public static int[] toIntArray(ISequence<? extends Integer> seq) {
    return (int[]) ArrayUtils.createAndFillArray(Integer.TYPE, seq);
  }
  public static long[] toLongArray(ISequence<? extends Long> seq) {
    return (long[]) ArrayUtils.createAndFillArray(Long.TYPE, seq);
  }
  public static short[] toShortArray(ISequence<? extends Short> seq) {
    return (short[]) ArrayUtils.createAndFillArray(Short.TYPE, seq);
  }
  public static ISequence<Boolean> fromBooleanArray(boolean[] array) {
    return Sequence.<Boolean>fromIterable(ArrayUtils.<Boolean>iterableFromArray(array));
  }
  public static ISequence<Byte> fromByteArray(byte[] array) {
    return Sequence.<Byte>fromIterable(ArrayUtils.<Byte>iterableFromArray(array));
  }
  public static ISequence<Character> fromCharacterArray(char[] array) {
    return Sequence.<Character>fromIterable(ArrayUtils.<Character>iterableFromArray(array));
  }
  public static ISequence<Double> fromDoubleArray(double[] array) {
    return Sequence.<Double>fromIterable(ArrayUtils.<Double>iterableFromArray(array));
  }
  public static ISequence<Float> fromFloatArray(float[] array) {
    return Sequence.<Float>fromIterable(ArrayUtils.<Float>iterableFromArray(array));
  }
  public static ISequence<Integer> fromIntegerArray(int[] array) {
    return Sequence.<Integer>fromIterable(ArrayUtils.<Integer>iterableFromArray(array));
  }
  public static ISequence<Long> fromLongArray(long[] array) {
    return Sequence.<Long>fromIterable(ArrayUtils.<Long>iterableFromArray(array));
  }
  public static ISequence<Short> fromShortArray(short[] array) {
    return Sequence.<Short>fromIterable(ArrayUtils.<Short>iterableFromArray(array));
  }
  public static Object newArrayInstance(Class<?> componentType, int length) {
    return Array.newInstance(componentType, length);
  }
  public static Object newArrayInstance(Class<?> componentType, int... dims) {
    return Array.newInstance(componentType, dims);
  }
  public static <T> T[] asArray(T... ts) {
    return ts;
  }
  private static <T> Object createAndFillArray(Class<T> type, ISequence<? extends T> seq) {
    Object arr = Array.newInstance(type, seq.count());
    int idx = 0;
    for (Object o : seq) {
      Array.set(arr, idx++, o);
    }
    return arr;
  }
  private static <T> Iterable<T> iterableFromArray(final Object array) {
    if (Sequence.USE_NULL_SEQUENCE) {
      if (array == null) {
        return NullSequence.instance();
      }
    }
    return new Iterable<T>() {
      @Override
      public Iterator<T> iterator() {
        return new ArrayIterator<T>(array);
      }
    };
  }
  private static class ArrayIterator<T> implements Iterator<T> {
    private int idx = 0;
    private Object array;
    private int length;
    private ArrayIterator(Object array) {
      this.array = array;
      length = Array.getLength(array);
    }
    @Override
    public boolean hasNext() {
      return idx < length;
    }
    @SuppressWarnings(value = "unchecked")
    @Override
    public T next() {
      return (T) Array.get(array, idx++);
    }
    @Override
    public void remove() {
      throw new UnsupportedOperationException();
    }
  }
}
