import japa.parser.ast.body.ModifierSet;

import java.lang.reflect.Field;
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("PrismaCuadrangularExtendsCuadrado", "PrismaCuadrangular", "PrismaCuadrangular debe heredar de la clase Cuadrado", 1.0));
		evaluations.add(new Evaluation("PrismaCuadrangularImplementsVolumen", "PrismaCuadrangular", "PrismaCuadrangular debe implementar la interfaz Volumen", 1.0));
		evaluations.add(new Evaluation("PrismaCuadrangularAlturaField", "PrismaCuadrangular", "altura", "PrismaCuadrangular debe utilizar un único atributo (double) para la altura", 1.0));
		evaluations.add(new Evaluation("PrismaCuadrangularFirstConstructor", "PrismaCuadrangular", "", "double, double, double, double", "Crear el constructor de la clase PrismaCuadrangular (double, double, double, double)", 1.5));
		evaluations.add(new Evaluation("PrismaCuadrangularSecondConstructor", "PrismaCuadrangular", "", "Cuadrado, double", "Crear el constructor de la clase PrismaCuadrangular (Cuadrado, double)", 1.5));
		evaluations.add(new Evaluation("PrismaCuadrangularVolumenMethod", "PrismaCuadrangular", "volumen", "", "Crear el método volumen de la clase PrismaCuadrangular", 1.0));
		evaluations.add(new Evaluation("GrupoFigurasVolumenMethod", "GrupoFiguras", "volumen", "", "Implementar el método volumen en la clase GrupoFiguras", 3.0));

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

		testCasesToGenerate.add(new Generator("PrismaCuadrangularVolumen", "PrismaCuadrangular", "volumen", new Class<?>[] { }, double.class, numTestCases, null, new Object[] { -0.0, 0.0 }));
		testCasesToGenerate.add(new Generator("GrupoFigurasVolumen", "GrupoFiguras", "volumen", new Class<?>[] { }, double.class, numTestCases, null, new Object[] { -0.0, 0.0 }));

//		return testCasesToGenerate;
		return null;
	}

	// PrismaCuadrangular extends Cuadrado
	public boolean checkPrismaCuadrangularExtendsCuadrado()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		final Class<?> cuadradoClass = super.inspector.getClass("Cuadrado");
		if (prismaCuadrangularClass == null || cuadradoClass == null)
			return false;

		return super.inspector.checkSuperclass(prismaCuadrangularClass, cuadradoClass);
	}
	public void solvePrismaCuadrangularExtendsCuadrado()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		final Class<?> cuadradoClass = super.inspector.getClass("Cuadrado");
		if (prismaCuadrangularClass == null || cuadradoClass == null)
			return;

		super.solver.setSuperClass(prismaCuadrangularClass, cuadradoClass);
	}

	// PrismaCuadrangular implements Volumen
	public boolean checkPrismaCuadrangularImplementsVolumen()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		final Class<?> volumenClass = super.inspector.getClass("Volumen");
		if (prismaCuadrangularClass == null || volumenClass == null)
			return false;

		return super.inspector.getInterfacesSize(prismaCuadrangularClass) == 1 && super.inspector.checkImplements(prismaCuadrangularClass, volumenClass);
	}
	public void solvePrismaCuadrangularImplementsVolumen()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		final Class<?> volumenClass = super.inspector.getClass("Volumen");
		if (prismaCuadrangularClass == null || volumenClass == null)
			return;

		super.solver.addImplement(prismaCuadrangularClass, volumenClass);
	}

	// PrismaCuadrangular field
	public boolean checkPrismaCuadrangularAlturaField()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		if (prismaCuadrangularClass == null)
			return false;

		final Field[] prismaCuadrangularFields = super.inspector.getDeclaredFields(prismaCuadrangularClass);
		if (prismaCuadrangularFields.length != 1)
			return false;

		final Field prismaCuadrangularField = prismaCuadrangularFields[0];

		return super.inspector.checkType(prismaCuadrangularField, double.class, true);
	}
	public void solvePrismaCuadrangularAlturaField()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		if (prismaCuadrangularClass == null)
			return;

		final int modifiers = ModifierSet.PRIVATE;

		super.solver.cleanFields(prismaCuadrangularClass);
		super.solver.addField(prismaCuadrangularClass, modifiers, double.class, "altura");
	}

	// PrismaCuadrangular first constructor
	public boolean checkPrismaCuadrangularFirstConstructor()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		if (prismaCuadrangularClass == null)
			return false;

		final Class<?>[] paramTypesConstructor1 = { double.class, double.class, double.class, double.class };

		return super.inspector.checkDeclaredConstructor(prismaCuadrangularClass, paramTypesConstructor1, true);
	}
	public boolean testPrismaCuadrangularFirstConstructor()
	{
		final String testCaseName = "Test02";
		final String testMethodName = "test";
		final Boolean expectedResult = true;
		final double posX = 12.3;
		final double posY = 56.6;
		final double lado = 415.8;
		final double altura = 922.5;

		final Object[] args = { posX, posY, lado, altura };
		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}
	public void solvePrismaCuadrangularFirstConstructor()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		if (prismaCuadrangularClass == null)
			return;

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

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

	// PrismaCuadrangular second constructor
	public boolean checkPrismaCuadrangularSecondConstructor()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		final Class<?> cuadradoClass = super.inspector.getClass("Cuadrado");
		if (prismaCuadrangularClass == null || cuadradoClass == null)
			return false;

		final Class<?>[] paramTypesConstructor = { cuadradoClass, double.class };

		return super.inspector.checkDeclaredConstructor(prismaCuadrangularClass, paramTypesConstructor, true);
	}
	public boolean testPrismaCuadrangularSecondConstructor()
	{
		final String testCaseName = "Test03";
		final String testMethodName = "test";
		final Boolean expectedResult = true;
		final double posX = 12.3;
		final double posY = 56.6;
		final double lado = 415.8;
		final double altura = 922.5;

		final Object[] args = { posX, posY, lado, altura };
		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}
	public void solvePrismaCuadrangularSecondConstructor()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		final Class<?> cuadradoClass = super.inspector.getClass("Cuadrado");
		if (prismaCuadrangularClass == null || cuadradoClass == null)
			return;

		final Class<?>[] paramTypes = { cuadradoClass, double.class };

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

	// PrismaCuadrangular volumen method
	public boolean checkPrismaCuadrangularVolumenMethod()
	{
		final Class<?> prismaCuadrangularClass = super.inspector.getClass("PrismaCuadrangular");
		if (prismaCuadrangularClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(prismaCuadrangularClass, "volumen", paramTypes, double.class, true);
	}
	public boolean testPrismaCuadrangularVolumenMethod()
	{
		final String testCaseName = "Test01";
		final String testMethodName = "test";
		final Double expectedResult = 45.0;
		final double lado = 3.0;
		final double altura = 5.0;

		final Object[] args = { lado, altura };
		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}
	private double testPrismaCuadrangularVolumenMethod2()
	{
		final String testCaseName = "PrismaCuadrangularVolumen";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

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

		super.solver.copyMethod(prismaCuadrangularClass, "volumen", new Class<?>[] { });
	}

	// GrupoFiguras volumen method
	public boolean checkGrupoFigurasVolumenMethod()
	{
		final Class<?> grupoFigurasClass = super.inspector.getClass("GrupoFiguras");
		if (grupoFigurasClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(grupoFigurasClass, "volumen", paramTypes, double.class, true);
	}
	public boolean testGrupoFigurasVolumenMethod()
	{
		final String testCaseName = "Test04";
		final String testMethodName = "test";
		final Double expectedResult = 137.0;
		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, null);

		return expectedResult.equals(testCaseResult);
	}
	private double testGrupoFigurasVolumenMethod2()
	{
		final String testCaseName = "GrupoFigurasVolumen";
		final double passedPercentage = super.test.executeTestCases(testCaseName);

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

		super.solver.copyMethod(grupoFigurasClass, "volumen", new Class<?>[] { });
	}
}