/**
 * generated by Xtext
 */
package javamm.validation;

import static org.eclipse.xtext.xbase.lib.IterableExtensions.exists;
import static org.eclipse.xtext.xbase.lib.IterableExtensions.map;
import static org.eclipse.xtext.xbase.typesystem.util.Multimaps2.newLinkedHashListMultimap;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.validation.Check;
import org.eclipse.xtext.xbase.XBlockExpression;
import org.eclipse.xtext.xbase.typesystem.override.IResolvedOperation;
import org.eclipse.xtext.xbase.typesystem.override.OverrideHelper;

import com.google.common.collect.ListMultimap;
import com.google.inject.Inject;

import javamm.javamm.JavammMethod;
import javamm.javamm.JavammPackage;
import javamm.javamm.JavammProgram;
import javamm.javamm.Main;
import javamm.util.JavammModelUtil;

/**
 * Custom validation rules.
 * 
 * see http://www.eclipse.org/Xtext/documentation.html#validation
 */
public class JavammValidator extends AbstractJavammValidator {
	public static final String PREFIX = "javamm.";

	public static final String DUPLICATE_METHOD = (JavammValidator.PREFIX + "DuplicateMethod");

	@Inject
	private JavammModelUtil javammModelUtil;

	@Inject
	private OverrideHelper overrideHelper;

	@Check
	public void checkDuplicateMethods(final JavammProgram p) {
		final JvmGenericType javaClass = javammModelUtil.getInferredJavaClass(p);
		final List<IResolvedOperation> methods = overrideHelper.getResolvedFeatures(javaClass)
				.getDeclaredOperations();
		final ListMultimap<String, JvmOperation> map = duplicatesMultimap();
		for (final IResolvedOperation d : methods) {
			map.put(d.getResolvedErasureSignature(), d.getDeclaration());
		}
		for (final Map.Entry<String, Collection<JvmOperation>> entry : map.asMap().entrySet()) {
			final Collection<JvmOperation> duplicates = entry.getValue();
			if (duplicates.size() > 1) {
				final Iterable<EObject> originalSources = map(duplicates,
						it -> javammModelUtil.getOriginalSource(it));
				final Iterator<EObject> sources = originalSources.iterator();
				if (exists(originalSources, Main.class::isInstance)) {
					for (final JvmOperation d : duplicates) {
						final EObject source = sources.next();
						if (!(source instanceof Main)) {
							error(entry.getKey() + " is a reserved method",
								source,
								JavammPackage.eINSTANCE.getJavammMethod_Name(),
								JavammValidator.DUPLICATE_METHOD);
						}
					}
				} else {
					for (final JvmOperation d : duplicates) {
							final EObject source = sources.next();
							error("Duplicate definition \'" + d.getSimpleName() + "\'",
								source, JavammPackage.eINSTANCE.getJavammMethod_Name(),
								JavammValidator.DUPLICATE_METHOD);
					}
				}
			}
		}
	}

	@Check
	public void checkMain(final Main m) {
		checkVariableInitialization(m);
	}

	@Check
	public void checkMethod(final JavammMethod method) {
		final XBlockExpression body = ((XBlockExpression) method.getBody());
		checkVariableInitialization(body);
		checkMissingReturn(body);
	}

	private <K extends Object, T extends Object> ListMultimap<K, T> duplicatesMultimap() {
		return newLinkedHashListMultimap();
	}
}

@@ -2301,38 +2301,41 @@
 e)) %7B%0A%09%09%09%09%09for (
-final 
+Iterator%3C
 JvmOperation d :
@@ -2326,39 +2326,95 @@
 JvmOperation
- d : duplicates
+%3E iterator = duplicates.iterator(); iterator.hasNext(); iterator.next()
 ) %7B%0A%09%09%09%09%09%09fi

use iterator