import japa.parser.ast.body.ModifierSet;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import assessment.evaluator.Evaluation;
import assessment.evaluator.Evaluator;
import assessment.evaluator.Generator;
import misc.Misc;

public class Template extends Evaluator
{
	// Implements Evaluator
	protected List<Evaluation> getEvaluations()
	{
		final List<Evaluation> evaluations = new LinkedList<Evaluation>();

		evaluations.add(new Evaluation("PilaALIsGeneric", "PilaAL", "PilaAL debe tener un parámetro genérico", 0.75));
		evaluations.add(new Evaluation("PilaALImplementsPila", "PilaAL", "PilaAL debe implementar la interfaz Pila<T>", 0.75));
		evaluations.add(new Evaluation("PilaALArrayListField", "PilaAL", "elementos", "PilaAL debe utilizar un atributo (ArrayList<T>) para los elementos de la pila", 0.5));
		evaluations.add(new Evaluation("PilaALConstructor", "PilaAL", "Crear el constructor", 0.5));
		evaluations.add(new Evaluation("PilaALApilarMethod", "PilaAL", "apilar", "T", "Crear el método apilar", 1.0));
		evaluations.add(new Evaluation("PilaALTallaMethod", "PilaAL", "talla", "", "Crear el método talla", 1.0));
		evaluations.add(new Evaluation("PilaALDesapilarMethod", "PilaAL", "desapilar", "", "Crear el método desapilar", 1.5));
		evaluations.add(new Evaluation("PilaALCimaMethod", "PilaAL", "cima", "", "Crear el método cima", 1.5));
		evaluations.add(new Evaluation("PilaALEsVaciaMethod", "PilaAL", "esVacia", "", "Crear el método esVacia", 1.0));
		evaluations.add(new Evaluation("PilaALToStringMethod", "PilaAL", "toString", "", "Crear el método toString", 1.5));

		return evaluations;
	}
	protected List<Generator> getTestCasesToGenerate()
	{
		final int numTestCases = 3;
		final List<Generator> testCasesToGenerate = new LinkedList<Generator>();

//		testCasesToGenerate.add(new Generator("PilaALApilar", "PilaAL", "apilar", new Class<?>[] { Object.class }, void.class, numTestCases, null, null));
//		testCasesToGenerate.add(new Generator("PilaALDesapilar", "PilaAL", "desapilar", new Class<?>[] { }, Object.class, numTestCases, null, null));
//		testCasesToGenerate.add(new Generator("PilaALCima", "PilaAL", "cima", new Class<?>[] { }, Object.class, numTestCases, null, null));
		testCasesToGenerate.add(new Generator("PilaALEsVacia", "PilaAL", "esVacia", new Class<?>[] { }, boolean.class, numTestCases, null, null));
		testCasesToGenerate.add(new Generator("PilaALTalla", "PilaAL", "talla", new Class<?>[] { }, int.class, numTestCases, null, new Object[] { -0.0, 0.0 }));
//		testCasesToGenerate.add(new Generator("PilaALToString", "PilaAL", "toString", new Class<?>[] { }, String.class, numTestCases, null, null));

//		return testCasesToGenerate;
		return null;
	}

	// PilaAL is generic
	public boolean checkPilaALIsGeneric()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		return super.inspector.getGenericParametersSize(pilaALClass) == 1;
	}
	public void solvePilaALIsGeneric()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		super.solver.cleanGenericTypes(pilaALClass);
		super.solver.addGenericType(pilaALClass, "T");
	}

	// PilaAL implements Pila
	public boolean checkPilaALImplementsPila()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		if (super.inspector.getGenericParametersSize(pilaALClass) != 1)
			return false;

		final TypeVariable<?> genericType = super.inspector.getGenericParameter(pilaALClass, 0);
		if (genericType == null)
			return false;

		final Class<?> pilaClass = super.inspector.getClass("Pila");
		if (pilaClass == null)
			return false;

		final Class<?>[] pilaALImplements = super.inspector.getInterfaces(pilaALClass);
		if (pilaALImplements.length != 1)
			return false;

		final Class<?> implementsClass = pilaALImplements[0];
		if (!super.inspector.checkSameClasses(implementsClass, pilaClass))
			return false;

		if (super.inspector.getGenericParametersSize(implementsClass) != 1)
			return false;

		final TypeVariable<?> implementClassGenericType = super.inspector.getGenericParameter(implementsClass, 0);

		return super.inspector.checkSameGenericTypes(implementClassGenericType, genericType);
	}
	public void solvePilaALImplementsPila()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final TypeVariable<?> genericType = super.inspector.getGenericParameter(pilaALClass, 0);
		if (genericType == null)
			return;

		final Class<?> pilaClass = super.inspector.getClass("Pila");
		if (pilaClass == null)
			return;

		super.solver.addImplement(pilaALClass, pilaClass);
		super.solver.addImplementGenericType(pilaALClass, pilaClass, genericType);
	}

	// PilaAL has ArrayList field
	public boolean checkPilaALArrayListField()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		if (super.inspector.getGenericParametersSize(pilaALClass) != 1)
			return false;

		final TypeVariable<?> genericType = super.inspector.getGenericParameter(pilaALClass, 0);
		if (genericType == null)
			return false;

		final Field[] fields = super.inspector.getDeclaredFields(pilaALClass);
		for (Field field : fields)
		{
			if (!super.inspector.checkType(field, ArrayList.class, true))
				continue;

			if (!super.inspector.checkGenericType(field, 0))
				continue;

			final TypeVariable<?> fieldGenericType = super.inspector.getGenericType(field, 0);
			if (super.inspector.checkSameGenericTypes(fieldGenericType, genericType))
				return true;
		}

		return false;
	}
	public void solvePilaALArrayListField()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final int modifiers = ModifierSet.PRIVATE;

		super.solver.addField(pilaALClass, modifiers, ArrayList.class, "elArray");
	}

	// PilaAL has constructor
	public boolean checkPilaALConstructor()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		final Class<?>[] paramTypes = { };

		return super.inspector.checkDeclaredConstructor(pilaALClass, paramTypes, true);
	}
	public boolean testPilaALConstructor()
	{
		final String testCaseName = "Test01";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	public void solvePilaALConstructor()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { };

		super.solver.copyConstructor(pilaALClass, paramTypes);
	}

	// PilaAL apilar method
	public boolean checkPilaALApilarMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		final Class<?>[] paramTypes = { Object.class };

		return super.inspector.checkDeclaredMethod(pilaALClass, "apilar", paramTypes, void.class, true);
	}
	public boolean testPilaALApilarMethod()
	{
		final String testCaseName = "Test02";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	private double testPilaALApilarMethod2()
	{
		final String testCaseName = "PilaALApilar";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

		return Misc.round(passedPercentage, 2);
	}
	public void solvePilaALApilarMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { Object.class };

		super.solver.copyMethod(pilaALClass, "apilar", paramTypes);
	}

	// PilaAL desapilar method
	public boolean checkPilaALDesapilarMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		if (super.inspector.getGenericParametersSize(pilaALClass) != 1)
			return false;

		final TypeVariable<?> genericType = super.inspector.getGenericParameter(pilaALClass, 0);
		if (genericType == null)
			return false;

		final Class<?>[] paramTypes = { };
		final Method desapilarMethod = super.inspector.getDeclaredMethod(pilaALClass, "desapilar", paramTypes, true);
		if (desapilarMethod == null)
			return false;

		final TypeVariable<?> desapilarReturnType = super.inspector.getGenericReturnType(desapilarMethod);
		if (desapilarReturnType == null)
			return false;

		return super.inspector.checkSameGenericTypes(desapilarReturnType, genericType);
	}
	public boolean testPilaALDesapilarMethod()
	{
		final String testCaseName = "Test03";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	private double testPilaALDesapilarMethod2()
	{
		final String testCaseName = "PilaALDesapilar";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

		return Misc.round(passedPercentage, 2);
	}
	public void solvePilaALDesapilarMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { };

		super.solver.copyMethod(pilaALClass, "desapilar", paramTypes);
	}

	// PilaAL cima method
	public boolean checkPilaALCimaMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		if (super.inspector.getGenericParametersSize(pilaALClass) != 1)
			return false;

		final TypeVariable<?> genericType = super.inspector.getGenericParameter(pilaALClass, 0);
		if (genericType == null)
			return false;

		final Class<?>[] paramTypes = { };
		final Method cimaMethod = super.inspector.getDeclaredMethod(pilaALClass, "cima", paramTypes, true);
		if (cimaMethod == null)
			return false;

		final TypeVariable<?> cimaReturnType = super.inspector.getGenericReturnType(cimaMethod);
		if (cimaReturnType == null)
			return false;

		return super.inspector.checkSameGenericTypes(cimaReturnType, genericType);
	}
	public boolean testPilaALCimaMethod()
	{
		final String testCaseName = "Test04";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	private double testPilaALCimaMethod2()
	{
		final String testCaseName = "PilaALCima";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

		return Misc.round(passedPercentage, 2);
	}
	public void solvePilaALCimaMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { };

		super.solver.copyMethod(pilaALClass, "cima", paramTypes);
	}

	// PilaAL esVacia method
	public boolean checkPilaALEsVaciaMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		final Class<?>[] paramTypes = { };

		return super.inspector.checkDeclaredMethod(pilaALClass, "esVacia", paramTypes, boolean.class, true);
	}
	public boolean testPilaALEsVaciaMethod()
	{
		final String testCaseName = "Test05";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	private double testPilaALEsVaciaMethod2()
	{
		final String testCaseName = "PilaALEsVacia";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

		return Misc.round(passedPercentage, 2);
	}
	public void solvePilaALEsVaciaMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { };

		super.solver.copyMethod(pilaALClass, "esVacia", paramTypes);
	}

	// PilaAL talla method
	public boolean checkPilaALTallaMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		final Class<?>[] paramTypes = { };

		return super.inspector.checkDeclaredMethod(pilaALClass, "talla", paramTypes, int.class, true);
	}
	public boolean testPilaALTallaMethod()
	{
		final String testCaseName = "Test06";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	private double testPilaALTallaMethod2()
	{
		final String testCaseName = "PilaALTalla";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

		return Misc.round(passedPercentage, 2);
	}
	public void solvePilaALTallaMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { };

		super.solver.copyMethod(pilaALClass, "talla", paramTypes);
	}

	// PilaAL toString method
	public boolean checkPilaALToStringMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return false;

		final Class<?>[] paramTypes = { };

		return super.inspector.checkDeclaredMethod(pilaALClass, "toString", paramTypes, String.class, true);
	}
	public boolean testPilaALToStringMethod()
	{
		final String testCaseName = "Test07";
		final String testMethodName = "test";
		final Object result = super.test.executeTestCase(testCaseName, testMethodName);

		return result == null ? false : (Boolean) result;
	}
	private double testPilaALToStringMethod2()
	{
		final String testCaseName = "PilaALToString";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

		return Misc.round(passedPercentage, 2);
	}
	public void solvePilaALToStringMethod()
	{
		final Class<?> pilaALClass = super.inspector.getClass("PilaAL");
		if (pilaALClass == null)
			return;

		final Class<?>[] paramTypes = { };

		super.solver.copyMethod(pilaALClass, "toString", paramTypes);
	}
}