package edu.mit.streamjit.impl.compiler;

import static com.google.common.base.Preconditions.*;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

/**
 * MethodType represents the type of a method, including the types of its
 * parameters and its return type, which must all be RegularTypes.
 * @author Jeffrey Bosboom <jeffreybosboom@gmail.com>
 * @since 3/6/2013
 */
public class MethodType extends Type {
	private final RegularType returnType;
	private final ImmutableList<RegularType> parameterTypes;
	private MethodType(RegularType returnType, ImmutableList<RegularType> parameterTypes) {
		this.returnType = checkNotNull(returnType);
		this.parameterTypes = parameterTypes;
	}
	public static MethodType of(RegularType returnType, RegularType... parameterTypes) {
		return new MethodType(returnType, ImmutableList.copyOf(parameterTypes));
	}
	public static MethodType of(RegularType returnType, List<RegularType> parameterTypes) {
		return new MethodType(returnType, ImmutableList.copyOf(parameterTypes));
	}
	/**
	 * Creates a MethodType from a JVM method descriptor.  The descriptor does
	 * not contain implicit this parameters (see JVMS 4.3.3), so if the method
	 * is an instance method, the given receiver type must be provided and will
	 * be prepended to the parameters from the descriptor; if the method is
	 * static, pass null.
	 * @param descriptor a JVM method descriptor
	 * @param receiverType the receiver type, or null if the method is static
	 * @return a MethodType
	 */
	public static MethodType fromDescriptor(String descriptor, RegularType receiverType) {
		java.lang.invoke.MethodType mt = java.lang.invoke.MethodType.fromMethodDescriptorString(descriptor, null);
		RegularType returnType = RegularType.of(mt.returnType());
		ImmutableList.Builder<RegularType> builder = ImmutableList.builder();
		if (receiverType != null)
			builder.add(receiverType);
		for (Class<?> c : mt.parameterList())
			builder.add(RegularType.of(c));
		RegularType[] argumentTypes = new RegularType[mt.parameterCount() + (receiverType != null ? 1 : 0)];
		int i = 0;
		if (receiverType != null)
			argumentTypes[++i] = receiverType;
		System.arraycopy(mt.parameterArray(), 0, argumentTypes, i, mt.parameterCount());
		return MethodType.of(returnType, argumentTypes);
	}

	public RegularType getReturnType() {
		return returnType;
	}

	public ImmutableList<RegularType> getParameterTypes() {
		return parameterTypes;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final MethodType other = (MethodType)obj;
		if (!Objects.equals(this.returnType, other.returnType))
			return false;
		if (!Objects.equals(this.parameterTypes, other.parameterTypes))
			return false;
		return true;
	}

	@Override
	public int hashCode() {
		int hash = 3;
		hash = 23 * hash + Objects.hashCode(this.returnType);
		hash = 23 * hash + Objects.hashCode(this.parameterTypes);
		return hash;
	}

	@Override
	public String toString() {
		return returnType.toString() + '(' + Joiner.on(", ").join(parameterTypes) + ')';
	}
}

@@ -1894,23 +1894,29 @@
 arType%3E 
-builder
+argumentTypes
  = Immut
@@ -1962,31 +1962,37 @@
 != null)%0A%09%09%09
-builder
+argumentTypes
 .add(receive
@@ -2046,56 +2046,8 @@
 %0A%09%09%09
-builder.add(RegularType.of(c));%0A%09%09RegularType%5B%5D 
 argu
@@ -2059,15 +2059,13 @@
 ypes
- = new 
+.add(
 Regu
@@ -2075,222 +2075,13 @@
 Type
-%5Bmt.parameterCount() + (receiverType != null ? 1 : 0)%5D;%0A%09%09int i = 0;%0A%09%09if (receiverType != null)%0A%09%09%09argumentTypes%5B++i%5D = receiverType;%0A%09%09System.arraycopy(mt.parameterArray(), 0, argumentTypes, i, mt.parameterCount(
+.of(c
 ));%0A
@@ -2124,24 +2124,32 @@
 rgumentTypes
+.build()
 );%0A%09%7D%0A%0A%09publ

Fix MethodType.fromDescriptor (duh)