package tools.dym.profiles;

import java.util.Arrays;

import com.oracle.truffle.api.utilities.JSONHelper;
import com.oracle.truffle.api.utilities.JSONHelper.JSONArrayBuilder;
import com.oracle.truffle.api.utilities.JSONHelper.JSONObjectBuilder;

import som.interpreter.Types;
import som.interpreter.objectstorage.ClassFactory;


public final class Arguments {

  private final Class<?>[] argJavaTypes;

  // TODO: do we need this, or is the first sufficient?
  // this makes it language specific...
  private final ClassFactory[] argSomTypes;

  Arguments(final Object[] arguments) {
    this.argJavaTypes = getJavaTypes(arguments);
    this.argSomTypes = getSomTypes(arguments);
  }

  private static Class<?>[] getJavaTypes(final Object[] args) {
    // remove the <?> because of checkstyle issue
    return Arrays.stream(args).map(e -> e.getClass()).toArray(Class[]::new);
  }

  private static ClassFactory[] getSomTypes(final Object[] args) {
    return Arrays.stream(args).map(e -> Types.getClassOf(e).getInstanceFactory())
                 .toArray(ClassFactory[]::new);
  }

  @Override
  public boolean equals(final Object obj) {
    if (super.equals(obj)) {
      return true;
    }
    if (!(obj instanceof Arguments)) {
      return false;
    }

    Arguments o = (Arguments) obj;

    return Arrays.equals(argJavaTypes, o.argJavaTypes)
        || Arrays.equals(argSomTypes, o.argSomTypes);
  }

  public boolean argTypeIs(final int idx, final String name) {
    return argSomTypes[idx].getClassName().getString().equals(name);
  }

  public String getArgType(final int idx) {
    return argSomTypes[idx].getClassName().getString();
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + Arrays.hashCode(argJavaTypes);
    result = prime * result + Arrays.hashCode(argSomTypes);
    return result;
  }

  public JSONObjectBuilder toJson() {
    JSONObjectBuilder result = JSONHelper.object();

    JSONArrayBuilder javaTypes = JSONHelper.array();
    for (Class<?> c : argJavaTypes) {
      javaTypes.add(c.getSimpleName());
    }

    result.add("javaTypes", javaTypes);

    JSONArrayBuilder somTypes = JSONHelper.array();
    for (ClassFactory c : argSomTypes) {
      somTypes.add(c.getClassName().getString());
    }
    result.add("somTypes", somTypes);
    return result;
  }

  @Override
  public String toString() {
    String result = "";
    for (ClassFactory c : argSomTypes) {
      if ("".equals(result)) {
        result = c.getClassName().getString();
      } else {
        result += ", " + c.getClassName().getString();
      }
    }
    return result;
  }
}

@@ -801,192 +801,467 @@
     
-return Arrays.stream(args).map(e -%3E e.getClass()).toArray(Class%5B%5D::new);%0A  %7D%0A%0A  private static ClassFactory%5B%5D getSomTypes(final Object%5B%5D args) %7B%0A    return Arrays.stream(args).map(e -%3E
+Class%3C?%3E%5B%5D result = new Class%3C?%3E%5Bargs.length%5D;%0A%0A    for (int i = 0; i %3C args.length; i += 1) %7B%0A      Object e = args%5Bi%5D;%0A      if (e != null) %7B%0A        result%5Bi%5D = e.getClass();%0A      %7D%0A    %7D%0A%0A    return result;%0A  %7D%0A%0A  private static ClassFactory%5B%5D getSomTypes(final Object%5B%5D args) %7B%0A    ClassFactory%5B%5D result = new ClassFactory%5Bargs.length%5D;%0A%0A    for (int i = 0; i %3C args.length; i += 1) %7B%0A      Object e = args%5Bi%5D;%0A      if (e != null) %7B%0A        result%5Bi%5D =
  Typ
@@ -1301,56 +1301,42 @@
 ry()
-)
+;
 %0A      
+%7D%0A
     
+%7D%0A%0A
     
-   .toArray(ClassFactory%5B%5D::new)
+return result
 ;%0A  

Handle null values in argument arrays for profiled operations