package pp.s1184725.boppi;

import java.util.*;
import java.util.stream.Collectors;

/**
 * The n-tuple type. Takes exactly {@link #size()} types. The element indices in
 * the tuple are 0-based.
 */
public class TupleType extends AbstractList<Type> implements Type {
	/**
	 * The empty tuple. Can be used in places where {@link SimpleType#VOID}
	 * cannot.
	 */
	public static TupleType UNIT = new TupleType(new ArrayList<>());
	private List<Type> parameters;

	/**
	 * Creates an n-tuple of the given types.
	 * 
	 * @param parameterTypes
	 */
	public TupleType(List<Type> parameterTypes) {
		parameters = new ArrayList<>(parameterTypes);
	}

	/**
	 * Returns the offset (in bytes) of the type at index {@code n}.
	 * 
	 * @param paramIndex
	 *            the index of the tuple element
	 * @return the offset in bytes
	 */
	public int getOffset(int paramIndex) {
		return parameters.stream().limit(paramIndex).collect(Collectors.summingInt(Type::getSize));
	}

	@Override
	public int getSize() {
		return parameters.stream().collect(Collectors.summingInt(Type::getSize));
	}

	@Override
	public boolean equals(Object other) {
		if (other instanceof TupleType)
			return parameters.equals(((TupleType) other).parameters);

		return false;
		//
		// switch (parameters.size()) {
		// case 0:
		// return SimpleType.VOID.equals(other);
		// case 1:
		// return parameters.get(0).equals(other);
		// default:
		// return false;
		// }
	}

	@Override
	public String toString() {
		return parameters.stream().map(Type::toString).collect(Collectors.joining(",", "(", ")"));
	}

	@Override
	public Type get(int index) {
		return parameters.get(index);
	}

	@Override
	public int size() {
		return parameters.size();
	}
}
