import japa.parser.ast.body.ModifierSet;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Hashtable;
import java.util.List;
import java.util.LinkedList;

import codeassess.javassessment.Assessor;
import codeassess.misc.Misc;

public class Template extends Assessor
{
	public Map<String, String> getConfig()
	{
		final Map<String, String> config = new Hashtable<String, String>();

		config.put("Language", "Java");
		config.put("Extensions", ".java");
		config.put("AssessmentMode", "SemiAutomatic");

		return config;
	}
	public List<Object[]> getProperties()
	{
		final List<Object[]> properties = new LinkedList<Object[]>();
         
        // Existen las clases y las interfaces
		properties.add(new Object[]{ "ExisteClaseFigura", "Functionality", "Figura.java", "Comprueba que has llamado a la clase \"Figura\"", "Debe existir la clase abstracta Figura", 0.5 });
		properties.add(new Object[]{ "ExisteClaseRectangulo", "Functionality", "Rectangulo.java", "Comprueba que has llamado a la clase \"Rectangulo\"", "Debe existir la clase Rectangulo", 0.25 });
		properties.add(new Object[]{ "ExisteClaseTriangulo", "Functionality", "Triangulo.java", "Comprueba que has llamado a la clase \"Triangulo\"", "Debe existir la clase Triangulo", 0.25 });
		properties.add(new Object[]{ "ExisteClaseCirculo", "Functionality", "Circulo.java", "Comprueba que has llamado a la clase \"Circulo\"", "Debe existir la clase Circulo", 0.25 });
		properties.add(new Object[]{ "ExisteInterfazVolumen", "Functionality", "Volumen.java", "Comprueba que has llamado a la interfaz \"Volumen\"", "Debe existir la interfaz Volumen", 0.5 });				
		properties.add(new Object[]{ "ExisteClaseCilindro", "Functionality", "Cilindro.java", "Comprueba que has llamado a la clase \"Cilindro\"", "Debe existir la clase Cilindro", 0.25 });
		properties.add(new Object[]{ "ExisteClaseGrupoFiguras", "Functionality", "GrupoFiguras.java", "Comprueba que has llamado a la clase \"GrupoFiguras\"", "Debe existir la clase GrupoFiguras", 0.5 });

        // La herencia es correcta
		properties.add(new Object[]{ "CirculoExtendsFigura", "Functionality", "Circulo.java", "Debes utilizar \"extends\"", "Circulo debe heredar de la clase Figura", 0.5 });
		properties.add(new Object[]{ "TrianguloExtendsFigura", "Functionality", "Triangulo.java", "Debes utilizar \"extends\"", "Triangulo debe heredar de la clase Figura", 0.5 });
		properties.add(new Object[]{ "RectanguloExtendsFigura", "Functionality", "Rectangulo.java", "Debes utilizar \"extends\"", "Rectangulo debe heredar de la clase Figura", 0.5 });
		properties.add(new Object[]{ "CilindroExtendsCirculo", "Functionality", "Cilindro.java", "Debes utilizar \"extends\"", "Cilindro debe heredar de la clase Circulo", 0.5 });

        // Se implementan las interfaces que deben implementarse
		properties.add(new Object[]{ "CilindroImplementsVolumen", "Functionality", "Cilindro.java", "Debes utilizar \"implements\"", "Cilindro debe implementar la interfaz Volumen", 0.5 });
		        										
        // Los atributos y métodos de las clases son los correctos
        // Cilindro
		properties.add(new Object[]{ "CilindroAlturaField", "Functionality", "Cilindro.java", "Comprueba que el atributo es de tipo double", "Cilindro debe utilizar un único atributo (double) para la altura", 0.5 });
		properties.add(new Object[]{ "CilindroFirstConstructor", "Functionality", "Cilindro.java", "Comprueba el nombre del constructor y el tipo de los argumentos", "Crear el constructor de la clase Cilindro (double, double, double, double)", 0.5 });
		properties.add(new Object[]{ "CilindroSecondConstructor", "Functionality", "Cilindro.java", "Comprueba el nombre del constructor y el tipo de los argumentos", "Crear el constructor de la clase Cilindro (Circulo, double)", 0.5 });
		properties.add(new Object[]{ "CilindroVolumenMethod", "Functionality", "Cilindro.java", "Comprueba el código del método", "Crear el método volumen de la clase Cilindro", 0.5 });
		properties.add(new Object[]{ "CilindroSuperficieMethod", "Functionality", "Cilindro.java", "Comprueba el código del método", "Crear el método superficie de la clase Cilindro", 0.5 });
        // GrupoFiguras
		properties.add(new Object[]{ "GrupoFigurasVolumenMethod", "Functionality", "GrupoFiguras.java", "Comprueba el nombre del método y el tipo de los argumentos", "Implementar el método volumen en la clase GrupoFiguras", 0.5 });
        // Metodo equals
		properties.add(new Object[]{ "CirculoEqualsMethod", "Functionality", "Circulo.java", "Comprueba el nombre del método y el tipo de los argumentos", "Crear el método equals de la clase Circulo", 0.5 });
		properties.add(new Object[]{ "RectanguloEqualsMethod", "Functionality", "Rectangulo.java", "Comprueba el nombre del método y el tipo de los argumentos", "Crear el método equals de la clase Rectangulo", 0.5 });
		properties.add(new Object[]{ "TrianguloEqualsMethod", "Functionality", "Triangulo.java", "Comprueba el nombre del método y el tipo de los argumentos", "Crear el método equals de la clase Triangulo", 0.5 });
		properties.add(new Object[]{ "GrupoFigurasEqualsMethod", "Functionality", "GrupoFiguras.java", "Comprueba el nombre del método y el tipo de los argumentos", "Crear el método equals de la clase GrupoFiguras", 0.5 });        
        
		return properties;
	}

	// Existe la clase Figura
	public boolean checkExisteClaseFigura()
	{
		return super.introspector.checkClassExists("Figura");
	}
	public boolean solveExisteClaseFigura()
	{
		return false;
	}
	public boolean testExisteClaseFigura()
	{
		return true;
	}

	// Existe la clase Triangulo
	public boolean checkExisteClaseTriangulo()
	{
		return super.introspector.checkClassExists("Triangulo");
	}
	public boolean solveExisteClaseTriangulo()
	{
		return false;
	}
	public boolean testExisteClaseTriangulo()
	{
		return true;
	}

	// Existe la clase Rectangulo
	public boolean checkExisteClaseRectangulo()
	{
		return super.introspector.checkClassExists("Rectangulo");
	}
	public boolean solveExisteClaseRectangulo()
	{
		return false;
	}
	public boolean testExisteClaseRectangulo()
	{
		return true;
	}

	// Existe la clase Circulo
	public boolean checkExisteClaseCirculo()
	{
		return super.introspector.checkClassExists("Circulo");
	}
	public boolean solveExisteClaseCirculo()
	{
		return false;
	}
	public boolean testExisteClaseCirculo()
	{
		return true;
	}

	// Existe la clase Cilindro
	public boolean checkExisteClaseCilindro()
	{
		return super.introspector.checkClassExists("Cilindro");
	}
	public boolean solveExisteClaseCilindro()
	{
		return false;
	}
	public boolean testExisteClaseCilindro()
	{
		return true;
	}

	// Existe la clase GrupoFiguras
	public boolean checkExisteClaseGrupoFiguras()
	{
		return super.introspector.checkClassExists("GrupoFiguras");
	}
	public boolean solveExisteClaseGrupoFiguras()
	{
		return false;
	}
	public boolean testExisteClaseGrupoFiguras()
	{
		return true;
	}

	// Existe la interfaz Volumen
	public boolean checkExisteInterfazVolumen()
	{
		return super.introspector.checkClassExists("Volumen");
	}
	public boolean solveExisteInterfazVolumen()
	{
		return false;
	}
	public boolean testExisteInterfazVolumen()
	{
		return true;
	}

	// Existe la interfaz Volumen
	public boolean checkExisteClaseVolumen()
	{
		return super.introspector.checkClassExists("Volumen");
	}
	public boolean solveExisteClaseVolumen()
	{
		return false;
	}
	public boolean testExisteClaseVolumen()
	{
		return true;
	}

	// Circulo extends Figura
	public boolean checkCirculoExtendsFigura()
	{
		final Class<?> circuloClass = super.introspector.getClass("Circulo");
		final Class<?> figuraClass = super.introspector.getClass("Figura");
		if (circuloClass == null || figuraClass == null)
			return false;

		return super.introspector.checkSuperclass(circuloClass, figuraClass);
	}
	public boolean solveCirculoExtendsFigura()
	{
		return false;
	}
	public boolean testCirculoExtendsFigura()
	{
		return true;
	}

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

		return super.introspector.checkSuperclass(trianguloClass, figuraClass);
	}
	public boolean solveTrianguloExtendsFigura()
	{
		return false;
	}
	public boolean testTrianguloExtendsFigura()
	{
		return true;
	}

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

		return super.introspector.checkSuperclass(rectanguloClass, figuraClass);
	}
	public boolean solveRectanguloExtendsFigura()
	{
		return false;
	}
	public boolean testRectanguloExtendsFigura()
	{
		return true;
	}

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

		return super.introspector.checkSuperclass(cilindroClass, circuloClass);
	}
	public boolean solveCilindroExtendsCirculo()
	{
		return false;
	}
	public boolean testCilindroExtendsCirculo()
	{
		return true;
	}

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

		return super.introspector.getInterfaceCount(cilindroClass) == 1 && super.introspector.checkImplements(cilindroClass, volumenClass);
	}
	public boolean solveCilindroImplementsVolumen()
	{
		return false;
	}
	public boolean testCilindroImplementsVolumen()
	{
		return true;
	}

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

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

		final Field cilindroField = cilindroFields[0];

		return super.introspector.checkClass(cilindroField, double.class, true);
	}
	public boolean solveCilindroAlturaField()
	{
		return false;
	}
	public boolean testCilindroAlturaField()
	{
		return true;
	}

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

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

		return super.introspector.checkDeclaredConstructor(cilindroClass, paramTypesConstructor1, true);
	}
	public boolean solveCilindroFirstConstructor()
	{
		return false;
	}
	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.tester.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}

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

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

		return super.introspector.checkDeclaredConstructor(cilindroClass, paramTypesConstructor, true);
	}
	public boolean solveCilindroSecondConstructor()
	{
		return false;
	}
	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.tester.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}

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

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

		return super.introspector.checkDeclaredMethod(cilindroClass, "volumen", paramTypes, double.class, true);
	}
	public boolean solveCilindroVolumenMethod()
	{
		return false;
	}
	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.tester.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}

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

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

		return super.introspector.checkDeclaredMethod(cilindroClass, "superficie", paramTypes, double.class, true);
	}
	public boolean solveCilindroSuperficieMethod()
	{
		return false;
	}
	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.tester.executeTestCase(testCaseName, testMethodName, args);

		return expectedResult.equals(testCaseResult);
	}

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

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

		return super.introspector.checkDeclaredMethod(grupoFigurasClass, "volumen", paramTypes, double.class, true);
	}
	public boolean solveGrupoFigurasVolumenMethod()
	{
		return false;
	}
	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.tester.executeTestCase(testCaseName, testMethodName);

		return expectedResult.equals(testCaseResult);
	}


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

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

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

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

		return expectedResult.equals(testCaseResult);
	}

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

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

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

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

		return expectedResult.equals(testCaseResult);
	}

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

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

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

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

		return expectedResult.equals(testCaseResult);
	}

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

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

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

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

		return expectedResult.equals(testCaseResult);
	}

}