package org.testory.common;

import java.lang.reflect.Array;
import java.util.Arrays;

public class Objects {
  public static boolean areEqual(@Nullable Object objectA, @Nullable Object objectB) {
    return objectA == null
        ? objectB == null
        : objectA.equals(objectB);
  }

  public static boolean areEqualDeep(@Nullable Object objectA, @Nullable Object objectB) {
    return objectA == null
        ? objectB == null
        : objectA.getClass().isArray()
            ? objectB != null && areEqualArrays(objectA, objectB)
            : objectA.equals(objectB);
  }

  private static boolean areEqualArrays(Object objectA, Object objectB) {
    Class<?> type = objectA.getClass().getComponentType();
    return type != objectB.getClass().getComponentType()
        ? false
        : type == boolean.class
            ? Arrays.equals((boolean[]) objectA, (boolean[]) objectB)
            : type == char.class
                ? Arrays.equals((char[]) objectA, (char[]) objectB)
                : type == byte.class
                    ? Arrays.equals((byte[]) objectA, (byte[]) objectB)
                    : type == short.class
                        ? Arrays.equals((short[]) objectA, (short[]) objectB)
                        : type == int.class
                            ? Arrays.equals((int[]) objectA, (int[]) objectB)
                            : type == long.class
                                ? Arrays.equals((long[]) objectA, (long[]) objectB)
                                : type == float.class
                                    ? Arrays.equals((float[]) objectA, (float[]) objectB)
                                    : type == double.class
                                        ? Arrays.equals((double[]) objectA, (double[]) objectB)
                                        : Arrays.deepEquals((Object[]) objectA, (Object[]) objectB);
  }

  // TODO test print(Object)
  public static String print(@Nullable Object object) {
    return object == null
        ? "null"
        : object.getClass().isArray()
            ? printArray(object)
            : String.valueOf(object);
  }

  private static String printArray(Object array) {
    StringBuilder builder = new StringBuilder();
    builder.append('[');
    int size = Array.getLength(array);
    for (int i = 0; i < size; i++) {
      builder.append(print(Array.get(array, i))).append(", ");
    }
    if (size > 0) {
      builder.delete(builder.length() - 2, builder.length());
    }
    builder.append(']');
    return builder.toString();
  }
}

@@ -54,16 +54,101 @@
 .Array;%0A
+import java.lang.reflect.InvocationTargetException;%0Aimport java.lang.reflect.Method;%0A
 import j
@@ -164,16 +164,16 @@
 Arrays;%0A
-
 %0Apublic 
@@ -743,23 +743,26 @@
     
-Class%3C?%3E type =
+try %7B%0A      return
  obj
@@ -780,1188 +780,624 @@
 ss()
-.getComponentType();%0A    return type != objectB.getClass().getComponentType()%0A        ? false%0A        : type == boolean.class%0A            ? A
+ == objectB.getClass()%0A          && (boolean) a
 rrays
-.e
+E
 quals
-((boolean%5B%5D) objectA, (boolean%5B%5D) objectB)%0A            : type == char.class%0A                ? Arrays.equals((char%5B%5D) objectA, (char%5B%5D) objectB)%0A                : type == byte.class%0A                    ? Arrays.equals((byte%5B%5D) objectA, (byte%5B%5D) objectB)%0A                    : type == short.class%0A                        ? A
+Method(objectA.getClass()).invoke(null, objectA, objectB);%0A    %7D catch (InvocationTargetException e) %7B%0A      throw new Error(e);%0A    %7D catch (IllegalAccessException e) %7B%0A      throw new Error(e);%0A    %7D%0A  %7D%0A%0A  private static Method a
 rrays
-.e
+E
 quals
-((short%5B%5D) objectA, (short%5B%5D) objectB)%0A                        : type == int.class%0A                            ? Arrays.equals((int%5B%5D) objectA, (int%5B%5D) objectB)%0A                            : type == long.class%0A                                ? Arrays.equals((long%5B%5D) objectA, (long%5B%5D) objectB)%0A                                : type == float.class%0A                                    ? Arrays.equals((float%5B%5D) objectA, (float%5B%5D) objectB)%0A                                    : type == double
+Method(Class%3C?%3E arrayType) %7B%0A    try %7B%0A      return arrayType.getComponentType().isPrimitive()%0A          ? Arrays.class.getMethod(%22equals%22, arrayType, arrayType)%0A          : Arrays.class.getMethod(%22deepEquals%22, Object%5B%5D.class, Object%5B%5D
 .class
+);
 %0A    
-                                    ? Arrays.equals((double%5B%5D) objectA, (double%5B%5D) objectB)%0A                                        : Arrays.deepEquals((Object%5B%5D) objectA, (Object%5B%5D) objectB);
+%7D catch (NoSuchMethodException e) %7B%0A      throw new Error(e);%0A    %7D
 %0A  %7D

refactored areEqualArrays