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
{

	@Override
	protected List<Generator> getTestCasesToGenerate() {
		// TODO Auto-generated method stub
		return null;
	}
	
	// Implements Evaluator
	protected List<Evaluation> getEvaluations()
	{
		final List<Evaluation> evaluations = new LinkedList<Evaluation>();
         
        // Existen las clases y las interfaces
		evaluations.add(new Evaluation("ExisteClaseFigura", "Figura", "Debe existir la clase abstracta Figura", 0.5));
		evaluations.add(new Evaluation("ExisteClaseRectangulo", "Rectangulo", "Debe existir la clase Rectangulo", 0.25));
		evaluations.add(new Evaluation("ExisteClaseTriangulo", "Triangulo", "Debe existir la clase Triangulo", 0.25));
		evaluations.add(new Evaluation("ExisteClaseCirculo", "Circulo", "Debe existir la clase Circulo", 0.25));
		evaluations.add(new Evaluation("ExisteInterfazVolumen", "Volumen", "Debe existir la interfaz Volumen", 0.5));				
		evaluations.add(new Evaluation("ExisteClaseCilindro", "Cilindro", "Debe existir la clase Cilindro", 0.25));
		evaluations.add(new Evaluation("ExisteClaseGrupoFiguras", "GrupoFiguras", "Debe existir la clase GrupoFiguras", 0.5));

        // La herencia es correcta
		evaluations.add(new Evaluation("CirculoExtendsFigura", "Circulo", "Circulo debe heredar de la clase Figura", 0.5));
		evaluations.add(new Evaluation("TrianguloExtendsFigura", "Triangulo", "Triangulo debe heredar de la clase Figura", 0.5));
		evaluations.add(new Evaluation("RectanguloExtendsFigura", "Rectangulo", "Rectangulo debe heredar de la clase Figura", 0.5));
		evaluations.add(new Evaluation("CilindroExtendsCirculo", "Cilindro", "Cilindro debe heredar de la clase Circulo", 0.5));

        // Se implementan las interfaces que deben implementarse
		evaluations.add(new Evaluation("CilindroImplementsVolumen", "Cilindro", "Cilindro debe implementar la interfaz Volumen", 0.5));
		        										
        // Los atributos y métodos de las clases son los correctos
        // Cilindro
		evaluations.add(new Evaluation("CilindroAlturaField", "Cilindro", "Cilindro debe utilizar un único atributo (double) para la altura", 0.5));
		evaluations.add(new Evaluation("CilindroFirstConstructor", "Cilindro", "Crear el constructor de la clase Cilindro (double, double, double, double)", 0.5));
		evaluations.add(new Evaluation("CilindroSecondConstructor", "Cilindro", "Crear el constructor de la clase Cilindro (Circulo, double)", 0.5));
		evaluations.add(new Evaluation("CilindroVolumenMethod", "Cilindro", "Crear el método volumen de la clase Cilindro", 0.5));
		evaluations.add(new Evaluation("CilindroSuperficieMethod", "Cilindro", "Crear el método volumen de la clase Cilindro", 0.5));
        // GrupoFiguras
		evaluations.add(new Evaluation("GrupoFigurasVolumenMethod", "GrupoFiguras", "Implementar el método volumen en la clase GrupoFiguras", 0.5));
        // Metodo equals
		evaluations.add(new Evaluation("CirculoEqualsMethod", "Circulo", "Crear el método equals de la clase Circulo", 0.5));
		evaluations.add(new Evaluation("RectanguloEqualsMethod", "Rectangulo", "Crear el método equals de la clase Rectangulo", 0.5));
		evaluations.add(new Evaluation("TrianguloEqualsMethod", "Triangulo", "Crear el método equals de la clase Triangulo", 0.5));
		evaluations.add(new Evaluation("GrupoFigurasEqualsMethod", "GrupoFiguras", "Crear el método equals de la clase GrupoFiguras", 0.5));        
        
		return evaluations;
	}

	// Existe la clase Figura
	public boolean checkExisteClaseFigura()
	{
		return super.inspector.checkClassExists("Figura");
	}

	// Existe la clase Triangulo
	public boolean checkExisteClaseTriangulo()
	{
		return super.inspector.checkClassExists("Triangulo");
	}
	
	// Existe la clase Rectangulo
	public boolean checkExisteClaseRectangulo()
	{
		return super.inspector.checkClassExists("Rectangulo");
	}

	// Existe la clase Circulo
	public boolean checkExisteClaseCirculo()
	{
		return super.inspector.checkClassExists("Circulo");
	}

	// Existe la clase Cilindro
	public boolean checkExisteClaseCilindro()
	{
		return super.inspector.checkClassExists("Cilindro");
	}

	// Existe la clase GrupoFiguras
	public boolean checkExisteClaseGrupoFiguras()
	{
		return super.inspector.checkClassExists("GrupoFiguras");
	}

	// Existe la interfaz Volumen
	public boolean checkExisteInterfazVolumen()
	{
		return super.inspector.checkClassExists("Volumen");
	}

	// Existe la interfaz Volumen
	public boolean checkExisteClaseVolumen()
	{
		return super.inspector.checkClassExists("Volumen");
	}
				
	// Circulo extends Figura
	public boolean checkCirculoExtendsFigura()
	{
		final Class<?> circuloClass = super.inspector.getClass("Circulo");
		final Class<?> figuraClass = super.inspector.getClass("Figura");
		if (circuloClass == null || figuraClass == null)
			return false;

		return super.inspector.checkSuperclass(circuloClass, figuraClass);
	}

	// Triangulo extends Figura
	public boolean checkTrianguloExtendsFigura()
	{
		final Class<?> trianguloClass = super.inspector.getClass("Triangulo");
		final Class<?> figuraClass = super.inspector.getClass("Figura");
		if (trianguloClass == null || figuraClass == null)
			return false;

		return super.inspector.checkSuperclass(trianguloClass, figuraClass);
	}

	// Rectangulo extends Figura
	public boolean checkRectanguloExtendsFigura()
	{
		final Class<?> rectanguloClass = super.inspector.getClass("Rectangulo");
		final Class<?> figuraClass = super.inspector.getClass("Figura");
		if (rectanguloClass == null || figuraClass == null)
			return false;

		return super.inspector.checkSuperclass(rectanguloClass, figuraClass);
	}

	// Cilindro extends Circulo
	public boolean checkCilindroExtendsCirculo()
	{
		final Class<?> cilindroClass = super.inspector.getClass("Cilindro");
		final Class<?> circuloClass = super.inspector.getClass("Circulo");
		if (circuloClass == null || cilindroClass == null)
			return false;

		return super.inspector.checkSuperclass(cilindroClass, circuloClass);
	}
	
	// Cilindro implements Volumen
	public boolean checkCilindroImplementsVolumen()
	{
		final Class<?> cilindroClass = super.inspector.getClass("Cilindro");
		final Class<?> volumenClass = super.inspector.getClass("Volumen");
		if (cilindroClass == null || volumenClass == null)
			return false;

		return super.inspector.getInterfacesSize(cilindroClass) == 1 && super.inspector.checkImplements(cilindroClass, volumenClass);
	}

	// La clase Cilindro tiene un unico atributo (double) para la altura
	public boolean checkCilindroAlturaField()
	{
		final Class<?> cilindroClass = super.inspector.getClass("Cilindro");
		if (cilindroClass == null)
			return false;

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

		final Field cilindroField = cilindroFields[0];

		return super.inspector.checkType(cilindroField, double.class, true);
	}

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

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

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

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

		return expectedResult.equals(testCaseResult);
	}

	// Cilindro second constructor
	public boolean checkCilindroSecondConstructor()
	{
		final Class<?> cilindroClass = super.inspector.getClass("Cilindro");
		final Class<?> circuloClass = super.inspector.getClass("Circulo");
		if (cilindroClass == null || circuloClass == null)
			return false;

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

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

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

		return expectedResult.equals(testCaseResult);
	}

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

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

		return super.inspector.checkDeclaredMethod(cilindroClass, "volumen", paramTypes, double.class, true);
	}
	public boolean testCilindroVolumenMethod()
	{
		final String testCaseName = "Test01";
		final String testMethodName = "test";
		final double radio = 3.0;
		final double altura = 5.0;
		final Double expectedResult = Math.PI*radio*radio*altura;


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

		return expectedResult.equals(testCaseResult);
	}

	// Cilindro superficie method
	public boolean checkCilindroSuperficieMethod()
	{
		final Class<?> cilindroClass = super.inspector.getClass("Cilindro");
		if (cilindroClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(cilindroClass, "superficie", paramTypes, double.class, true);
	}
	public boolean testCilindroSuperficieMethod()
	{
		final String testCaseName = "Test05";
		final String testMethodName = "test";
		final double radio = 3.0;
		final double altura = 5.0;
		final Double expectedResult = ((2 * Math.PI * radio)*altura)+(2*(Math.PI*radio*radio));

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

		return expectedResult.equals(testCaseResult);
	}

	// 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 radio = 3.0;
		final double altura = 5.0;
		final Double expectedResult = Math.PI*radio*radio*altura;

		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, null);

		return expectedResult.equals(testCaseResult);
	}


	// Circulo equals method
	public boolean checkCirculoEqualsMethod()
	{
		final Class<?> CirculoClass = super.inspector.getClass("Circulo");
		final Class<?> ObjectClass = super.inspector.getClass("java.lang.Object");
		if (CirculoClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(CirculoClass, "equals", paramTypes, boolean.class, true);
	}
	public boolean testCirculoEqualsMethod()
	{
		final String testCaseName = "Test06";
		final String testMethodName = "test";
		final Boolean expectedResult = true;

		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, null);

		return expectedResult.equals(testCaseResult);
	}

	// Rectangulo equals method
	public boolean checkRectanguloEqualsMethod()
	{
		final Class<?> RectanguloClass = super.inspector.getClass("Rectangulo");
		final Class<?> ObjectClass = super.inspector.getClass("java.lang.Object");
		if (RectanguloClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(RectanguloClass, "equals", paramTypes, boolean.class, true);
	}
	public boolean testRectanguloEqualsMethod()
	{
		final String testCaseName = "Test07";
		final String testMethodName = "test";
		final Boolean expectedResult = true;

		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, null);

		return expectedResult.equals(testCaseResult);
	}

	// Triangulo equals method
	public boolean checkTrianguloEqualsMethod()
	{
		final Class<?> TrianguloClass = super.inspector.getClass("Triangulo");
		final Class<?> ObjectClass = super.inspector.getClass("java.lang.Object");
		if (TrianguloClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(TrianguloClass, "equals", paramTypes, boolean.class, true);
	}
	public boolean testTrianguloEqualsMethod()
	{
		final String testCaseName = "Test08";
		final String testMethodName = "test";
		final Boolean expectedResult = true;

		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, null);

		return expectedResult.equals(testCaseResult);
	}

	// GrupoFiguras equals method
	public boolean checkGrupoFigurasEqualsMethod()
	{
		final Class<?> GrupoFigurasClass = super.inspector.getClass("GrupoFiguras");
		final Class<?> ObjectClass = super.inspector.getClass("java.lang.Object");
		if (GrupoFigurasClass == null)
			return false;

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

		return super.inspector.checkDeclaredMethod(GrupoFigurasClass, "equals", paramTypes, boolean.class, true);
	}
	public boolean testGrupoFigurasEqualsMethod()
	{
		final String testCaseName = "Test09";
		final String testMethodName = "test";
		final Boolean expectedResult = true;

		final Object testCaseResult = super.test.executeTestCase(testCaseName, testMethodName, null);

		return expectedResult.equals(testCaseResult);
	}

}