package de.gurkenlabs.litiengine.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.ThreadLocalRandom;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

public final class ArrayUtilities {
  private static final Logger log = Logger.getLogger(ArrayUtilities.class.getName());

  private ArrayUtilities() {
    throw new UnsupportedOperationException();
  }

  public static byte[] arrayConcat(final byte[] firstArray, final byte[] secondArray) {
    final int aLen = firstArray.length;
    final int bLen = secondArray.length;
    final byte[] combinedArray = new byte[aLen + bLen];
    System.arraycopy(firstArray, 0, combinedArray, 0, aLen);
    System.arraycopy(secondArray, 0, combinedArray, aLen, bLen);
    return combinedArray;
  }

  public static int[] getIntegerArray(String commaSeperatedString) {
    if (commaSeperatedString == null || commaSeperatedString.isEmpty()) {
      return new int[0];
    }

    final String[] split = commaSeperatedString.split(",");
    int[] integers = new int[split.length];
    if (integers.length == 0) {
      return integers;
    }

    for (int i = 0; i < split.length; i++) {
      if (split[i] == null || split[i].isEmpty()) {
        continue;
      }

      try {
        integers[i] = Integer.parseInt(split[i]);
      } catch (final NumberFormatException e) {
        log.log(Level.SEVERE, e.getMessage(), e);
      }
    }

    return integers;
  }

  public static double[] getDoubleArray(String commaSeperatedString) {
    if (commaSeperatedString == null || commaSeperatedString.isEmpty()) {
      return new double[0];
    }

    final String[] split = commaSeperatedString.split(",");
    double[] doubles = new double[split.length];
    if (doubles.length == 0) {
      return doubles;
    }

    for (int i = 0; i < split.length; i++) {
      if (split[i] == null || split[i].isEmpty()) {
        continue;
      }

      try {
        doubles[i] = Double.parseDouble(split[i]);
      } catch (final NumberFormatException e) {
        log.log(Level.SEVERE, e.getMessage(), e);
      }
    }

    return doubles;
  }

  public static String join(boolean[] arr) {
    return joinArray(arr, ",");
  }

  public static String join(boolean[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(int[] arr) {
    return joinArray(arr, ",");
  }

  public static String join(int[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(double[] arr) {
    return joinArray(arr, ",");
  }

  public static String join(double[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(float[] arr) {
    return joinArray(arr, ",");
  }

  public static String join(float[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(short[] arr) {
    return joinArray(arr, ",");
  }

  public static String join(short[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(long[] arr) {
    return join(arr, ",");
  }

  public static String join(long[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(byte[] arr) {
    return join(arr, ",");
  }

  public static String join(byte[] arr, String separator) {
    return joinArray(arr, separator);
  }

  public static String join(List<?> list) {
    return joinArray(list, ",");
  }

  public static String join(List<?> list, String separator) {
    return joinArray(list.toArray(), separator);
  }

  public static String join(Object[] arr) {
    return joinArray(arr, ",");
  }

  public static String join(Object[] arr, String separator) {
    return joinArray(arr, separator);
  }

  // general method for joining an array
  // encapsulated for type safety
  private static String joinArray(Object arr, String separator) {
    if (arr == null) {
      return null;
    }

    int len = Array.getLength(arr);
    if (len == 0) {
      return "";
    }

    StringBuilder sb = new StringBuilder(String.valueOf(Array.get(arr, 0)));
    for (int i = 1; i < len; i++) {
      sb.append(separator);
      sb.append(Array.get(arr, i));
    }

    return sb.toString();
  }

  public static <T> List<T> toList(T[][] arr) {
    List<T> list = new ArrayList<>();
    for (T[] rows : arr) {
      list.addAll(Arrays.asList(rows));
    }

    return list;
  }

  public static <T> T getRandom(T[] arr) {
    return getRandom(arr, ThreadLocalRandom.current());
  }

  public static <T> T getRandom(T[] arr, Random rand) {
    if (arr.length == 0) {
      return null;
    }
    return arr[rand.nextInt(arr.length)];
  }

  public static void shuffle(Object[] arr) {
    shuffle(arr, ThreadLocalRandom.current());
  }

  public static void shuffle(Object[] arr, Random rand) {
    for (int i = arr.length - 1; i > 0; i--) {
      int swap = rand.nextInt(i + 1);
      Object temp = arr[i];
      arr[i] = arr[swap];
      arr[swap] = temp;
    }
  }

  public static boolean contains(Object[] arr, Object value) {
    if (value == null) {
      return false;
    }

    for (Object v : arr) {
      if (v != null && v.equals(value)) {
        return true;
      }
    }

    return false;
  }

  public static boolean containsArgument(String[] args, String argument) {
    if (args == null || args.length == 0) {
      return false;
    }

    for (int i = 0; i < args.length; i++) {
      final String a = args[i];
      if (a != null && !a.isEmpty() && a.equalsIgnoreCase(argument)) {
        return true;
      }
    }

    return false;
  }

  /**
   * Removes the specified deleteItem from the input array and returns a trimmed new array instance without null entries.
   * The resulting array will have a length -1;
   * 
   * @param <T>
   *          The element type of the array.
   * @param input
   *          The original array
   * @param deleteItem
   *          The item to delete
   * @return A new array with the length input.length - 1.
   */
  @SuppressWarnings("unchecked")
  public static <T> T[] remove(T[] input, T deleteItem) {
    List<T> result = new ArrayList<>();

    for (T item : input) {
      if (!deleteItem.equals(item)) {
        result.add(item);
      }
    }

    result.removeAll(Collections.singleton(null));
    return result.toArray((T[]) Array.newInstance(input.getClass().getComponentType(), result.size()));
  }

  public static int[] toIntegerArray(List<Integer> intList) {
    Integer[] objArray = intList.toArray(new Integer[0]);
    int[] intArray = new int[objArray.length];
    for (int i = 0; i < intArray.length; i++) {
      intArray[i] = objArray[i];
    }
    return intArray;
  }

}

@@ -3580,16 +3580,26 @@
 ray(list
+.toArray()
 , %22,%22);%0A
@@ -4168,10 +4168,12 @@
 urn 
-%22%22
+null
 ;%0A  

Fix the unit test