
/** 
 * Program to grade student's lab4 submission as described at http://fricke.co.uk/Teaching/CS251/lab4. 
 * The lab4 assignment tests knowledge of inheritance and interfaces in Java.
 * @author      Matthew Fricke <matthew @ fricke.co.uk>
 * @version     1.0
 * @date        2012-09-13
 */

class shapegrader
{
    /**
     * Tests whether the shape.getName() method returns the same name that was passed into the shape's constructor even after downcasting,
     * i.e. whether inheritance from the Shape class was implemented.
     * @param reference name used to create the object
     * @param the shape we are testing
     * @return a grade based on the test result
     */
    public static int testExtends( String ref_shape_name, Shape shape )
    {
	int grade = 0;
	String result = shape.getName();
	System.out.print("Testing " + ref_shape_name + " getName() method: ");
	if (result.equals(ref_shape_name)) 
	    {
		System.out.print("PASSED");
		grade = 5;
	    }
	else System.out.print("FAILED: " + ref_shape_name + " != " + result);
	System.out.println();

	return grade;
    }

    /**
     * Tests whether the two values are within epsilon of each other. This method is intended
     * to be used to test whether getVolume() and getArea() are properly implemented.
     * @param a string labeling the test
     * @param the student's value
     * @param the reference value
     * @return a grade based on the test result
     */
    public static int testImplements( String testname, double submission, double reference)
    {
	float epsilon = 0.1f;
	int grade = 0;
	System.out.print("Testing " + testname + ": ");
	if ( Math.abs( submission-reference ) < epsilon ) 
	    {
		System.out.print("PASSED");
		grade = 5;
	    }
	else
	    {
		System.out.print("FAILED (Delta=" + Math.abs( submission-reference )+ ")");
	    }
	
	System.out.println();
	
	return grade;
    } 
    
    /**
     * Entry point for the program. Take two arguments (side length and radius), use them to create some shapes and then run the 
     * test methods on those shapes and then print the student's grade.
     * @param String[] args
     * Always returns 0 to the OS.
     */
    public static void main(String[] args)
    {
	// Check that two arguments were passed in
	if ( args.length != 2 )
	    {
		System.out.println("usage: java shapegrader <side> <radius>"); 
	    }
	
	// Store a radius and side length
	double ref_radius = new Double(args[0]);
	double ref_side = new Double(args[1]);
	
	// Create some shape names
	String square_name = "Square";
	String circle_name = "Circle";
	String sphere_name = "Sphere";
	String cube_name = "Cube";
	String cylinder_name = "Cylinder";
	String glome_name = "Glome";

	// Create some shapes using the radius and side length given by the user
	Square square = new Square( ref_side, square_name );
	Circle circle = new Circle( ref_radius, circle_name );
	Cube cube = new Cube( ref_side, cube_name );
	Sphere sphere = new Sphere( ref_radius, sphere_name );
	Cylinder cylinder = new Cylinder( ref_side, ref_radius, cylinder_name ); // use side length as the cylinder height
	Glome glome = new Glome( ref_radius, glome_name );
	
	// Give the student 15 points just for getting the program to compile and run
	int grade = 15;
	
	// Store the shapes we created in a Shape array
	Shape[] shapes = {square, circle, cube, sphere, cylinder, glome};

	// Store the shape names in an array
	String[] names = {square_name, circle_name, cube_name, sphere_name, cylinder_name, glome_name };
	
	// Iterate over the the arrays and test that inheritance was implemented properly
	for ( int i = 0; i < 6; i++ ) grade += testExtends( names[i], shapes[i] );	
	
	// Compare the values the student's program generates for volume and area of various shapes with reference values.
	grade += testImplements( "Square Area", square.getArea(), Math.pow(ref_side, 2) );
	grade += testImplements( "Circle Area", circle.getArea(), Math.PI*Math.pow(ref_radius, 2) );
	grade += testImplements( "Cube Volume", cube.getVolume(), Math.pow(ref_side,3));
	grade += testImplements( "Sphere Volume", sphere.getVolume(), (4.0/3.0)*Math.PI*Math.pow(ref_radius, 3) );
	grade += testImplements( "Cylinder Volume", cylinder.getVolume(), Math.PI*Math.pow(ref_radius, 2)*ref_side );
	grade += testImplements( "Glome Volume", glome.getVolume(), 0.5*Math.pow(Math.PI, 2)*Math.pow(ref_radius, 4) );
	
	System.out.println("Grade: " + grade + "/75" );	
	    	
    }
}    
    
