package org.eclipselabs.mscript.language.validation;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.validation.Check;
import org.eclipselabs.mscript.language.ast.ArrayElementReference;
import org.eclipselabs.mscript.language.ast.AstPackage;
import org.eclipselabs.mscript.language.ast.BeginExpression;
import org.eclipselabs.mscript.language.ast.EndExpression;
import org.eclipselabs.mscript.language.ast.FunctionDefinition;
import org.eclipselabs.mscript.language.ast.ParameterDeclaration;
import org.eclipselabs.mscript.language.ast.Subscript;
import org.eclipselabs.mscript.language.ast.UnitExpressionNumerator;
import org.eclipselabs.mscript.language.interpreter.FunctorConstructor;
import org.eclipselabs.mscript.language.interpreter.IFunctor;
import org.eclipselabs.mscript.language.interpreter.IInterpreterContext;
import org.eclipselabs.mscript.language.interpreter.Interpreter;
import org.eclipselabs.mscript.language.interpreter.InterpreterContext;
import org.eclipselabs.mscript.language.interpreter.value.AnyValue;
import org.eclipselabs.mscript.language.interpreter.value.INumericValue;
import org.eclipselabs.mscript.language.interpreter.value.IValue;
import org.eclipselabs.mscript.language.interpreter.value.IValueFactory;
import org.eclipselabs.mscript.language.interpreter.value.ValueFactory;
import org.eclipselabs.mscript.typesystem.RealType;
import org.eclipselabs.mscript.typesystem.TypeSystemFactory;
import org.eclipselabs.mscript.typesystem.util.TypeSystemUtil;

public class MscriptJavaValidator extends AbstractMscriptJavaValidator {

	@Check
	public void checkBeginExpressionMustBeInsideArraySubscript(BeginExpression beginExpression) {
		if (!isInsideArraySubscript(beginExpression)) {
			error("'begin' may only appear inside array subscripts", AstPackage.BEGIN_EXPRESSION);
		}
	}

	@Check
	public void checkEndExpressionMustBeInsideArraySubscript(EndExpression endExpression) {
		if (!isInsideArraySubscript(endExpression)) {
			error("'end' may only appear inside array subscripts", AstPackage.END_EXPRESSION);
		}
	}
	
	private boolean isInsideArraySubscript(EObject eObject) {
		EObject container = eObject.eContainer();
		
		while (container != null && !(container instanceof Subscript)) {
			container = container.eContainer();
		}
		
		return container instanceof Subscript && ((Subscript) container).eContainer() instanceof ArrayElementReference;
	}

	@Check
	public void checkUnitExpressionNumeratorMustConsistOfSymbolsOrOne(UnitExpressionNumerator numerator) {
		if (numerator.getFactors().isEmpty() && numerator.getOne() != 1) {
			error("Invalid unit numerator", AstPackage.UNIT_EXPRESSION_NUMERATOR__ONE);
		}
	}
	
	@Check
	public void checkFunctionDefinition(FunctionDefinition functionDefinition) {
		IValueFactory valueFactory = new ValueFactory();
		IInterpreterContext context = new InterpreterContext(getChain(), valueFactory, true);
		List<IValue> templateArguments = new ArrayList<IValue>();
		for (ParameterDeclaration parameterDeclaration : functionDefinition.getTemplateParameters()) {
			// TODO: should be AnyType instead of RealType
			RealType realType = TypeSystemFactory.eINSTANCE.createRealType();
			realType.setUnit(TypeSystemUtil.createUnit());
			templateArguments.add(new AnyValue(realType));
		}
		IFunctor functor = new FunctorConstructor().construct(context, functionDefinition, templateArguments);

		List<IValue> inputValues = new ArrayList<IValue>();
		for (ParameterDeclaration parameterDeclaration : functionDefinition.getInputParameters()) {
			RealType realType = TypeSystemFactory.eINSTANCE.createRealType();
			realType.setUnit(TypeSystemUtil.createUnit());
			inputValues.add(valueFactory.createRealValue(realType, 7));
		}
		for (int i = 0; i < 10; ++i) {
			System.out.print(functionDefinition.getName() + ": ");
			List<IValue> outputValues = new Interpreter().execute(context, functor, inputValues);
			for (IValue value : outputValues) {
				if (value instanceof INumericValue) {
					INumericValue numericValue = (INumericValue) value;
					System.out.print(numericValue.doubleValue() + ", ");
				}
			}
			System.out.println();
		}
		System.out.println();
	}
	
}

@@ -51,60 +51,8 @@
 n;%0A%0A
-import java.util.ArrayList;%0Aimport java.util.List;%0A%0A
 impo
@@ -85,16 +85,16 @@
 Object;%0A
+
 import o
@@ -439,74 +439,8 @@
 on;%0A
-import org.eclipselabs.mscript.language.ast.ParameterDeclaration;%0A
 impo
@@ -603,838 +603,46 @@
 age.
-interpreter.FunctorConstructor;%0Aimport org.eclipselabs.mscript.language.interpreter.IFunctor;%0Aimport org.eclipselabs.mscript.language.interpreter.IInterpreterContext;%0Aimport org.eclipselabs.mscript.language.interpreter.Interpreter;%0Aimport org.eclipselabs.mscript.language.interpreter.InterpreterContext;%0Aimport org.eclipselabs.mscript.language.interpreter.value.AnyValue;%0Aimport org.eclipselabs.mscript.language.interpreter.value.INumericValue;%0Aimport org.eclipselabs.mscript.language.interpreter.value.IValue;%0Aimport org.eclipselabs.mscript.language.interpreter.value.IValueFactory;%0Aimport org.eclipselabs.mscript.language.interpreter.value.ValueFactory;%0Aimport org.eclipselabs.mscript.typesystem.RealType;%0Aimport org.eclipselabs.mscript.typesystem.TypeSystemFactory;%0Aimport org.eclipselabs.mscript.typesystem.util.TypeSystemUtil
+functionmodel.util.FunctionConstructor
 ;%0A%0Ap
@@ -1903,557 +1903,20 @@
 %7B%0A%09%09
-IValueFactory valueFactory = new ValueFactory();%0A%09%09IInterpreterContext context = new InterpreterContext(getChain(), valueFactory, true);%0A%09%09List%3CIValue%3E templateArguments = new ArrayList%3CIValue%3E();%0A%09%09for (ParameterDeclaration parameterDeclaration : functionDefinition.getTemplateParameters()) %7B%0A%09%09%09// TODO: should be AnyType instead of RealType%0A%09%09%09RealType realType = TypeSystemFactory.eINSTANCE.createRealType();%0A%09%09%09realType.setUnit(TypeSystemUtil.createUnit());%0A%09%09%09templateArguments.add(new AnyValue(realType));%0A%09%09%7D%0A%09%09IFunctor functor = new Functor
+new Function
 Cons
@@ -1935,25 +1935,16 @@
 nstruct(
-context, 
 function
@@ -1959,800 +1959,18 @@
 on, 
-templateArguments);%0A%0A%09%09List%3CIValue%3E inputValues = new ArrayList%3CIValue%3E();%0A%09%09for (ParameterDeclaration parameterDeclaration : functionDefinition.getInputParameters()) %7B%0A%09%09%09RealType realType = TypeSystemFactory.eINSTANCE.createRealType();%0A%09%09%09realType.setUnit(TypeSystemUtil.createUnit());%0A%09%09%09inputValues.add(valueFactory.createRealValue(realType, 7));%0A%09%09%7D%0A%09%09for (int i = 0; i %3C 10; ++i) %7B%0A%09%09%09System.out.print(functionDefinition.getName() + %22: %22);%0A%09%09%09List%3CIValue%3E outputValues = new Interpreter().execute(context, functor, inputValues);%0A%09%09%09for (IValue value : outputValues) %7B%0A%09%09%09%09if (value instanceof INumericValue) %7B%0A%09%09%09%09%09INumericValue numericValue = (INumericValue) value;%0A%09%09%09%09%09System.out.print(numericValue.doubleValue() + %22, %22);%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%09System.out.println();%0A%09%09%7D%0A%09%09System.out.println(
+getChain()
 );%0A%09

Test code in Mscript validator removed.