import java.util.Arrays;
/***********************************************
 * This class will represent a single student's grade 
 * in CS139.  It will contain everything to store and 
 * display a final grade roster for the course.
 * This grade is based on the syllabus with one exception:
 * the PA grades will be treated like lab grades.
 *
 * @author - Nancy Harris
 * @version - V1 11/27/2007
 ************************************************/
public class Grade139
{
	// attributes
	private double [] lab;
	private double midterm1;
	private double midterm2;
	private double finalExam;
	private String name;
	
	// constants
	private static final double LAB_PERCENT = .4;
	private static final double MID1_PERCENT = .15;
	private static final double MID2_PERCENT = .20;
	private static final double FINAL_PERCENT = .25;
	
	/******************************************
	 * Constructor to start a Grade139 object with
	 * only the student name
	 *
	 * @param name The name of the student
	 */
	public Grade139(String name)
	{
		this.name = name;
		
		// to avoid future problems, initialize
		// each attribute to a reasonable value
		this.midterm1 = 0;
		this.midterm2 = 0;
		this.finalExam = 0;
		this.lab = new double[0]; // an object of no length		
	}
	/**************************************************
	 * Constructor to start a filled Grade139 object
	 *
	 * @param name The name of the student
	 * @param mid1 The midterm 1 grade
	 * @param mid2 The midterm 2 grade
	 * @param finalExam The final exam grade
	 * @param lab The grade for each lab
	 */
	public Grade139(String name, double mid1, double mid2, double finalExam,
		double... lab)
	{
		// hmmmmm these are simple enough, but what if I add in
		// validation?
		this.name = name;
		this.midterm1 = mid1;
		this.midterm2 = mid2;
		this.finalExam = finalExam;
		
		// to prevent side effects, make a new lab array and fill
		// hmmmmmm I need this same code in set lab....write once 
		// use twice???
		this.lab = new double [lab.length];
		for (int ii = 0; ii < lab.length; ii++)
			this.lab[ii] = lab[ii];
			
	}
	/**********************************************
	 * setLabs will reset the current set of lab
	 * grades with the grades from the parameter
	 *
	 * @param lab The list of lab grades
	 */
	public void setLabs (double [] lab)
	{
		// to prevent side effects, make a new lab array and fill
		this.lab = new double [lab.length];
		for (int ii = 0; ii < lab.length; ii++)
			this.lab[ii] = lab[ii];
	}
	
	/**********************************************
	 * setLabs will add a new lab grade to the current
	 * array of lab grades
	 * 
	 * @param lab The new grade to add
	 */
	public void setLabs (double lab)
	{
		// I will make the assumption that the lab array is built
		// big enough to hold the labs.  So, I need to build
		// my array one bigger to hold this lab.
		
		// preserve the contents of the first lab by making an alias
		double[] tempLab;
		tempLab = this.lab;
		
		// now make a new one.  tempLab is pointing to the original
		this.lab = new double [this.lab.length + 1];
		
		for (int ii = 0; ii < tempLab.length; ii++)
			this.lab[ii] = tempLab[ii];
		
		// finish be saving the incoming lab score
		this.lab[this.lab.length - 1] = lab;

	}
	
	/***********************************************
	 * setFinalExam - sets the value of the final exam
	 *
	 * @param finalExam The final exam value
    */
	public void setFinalExam (double finalExam)
	{
		this.finalExam = finalExam;
	}
	
	/***********************************************
	 * setMidterm1 - sets the value of the first midterm
	 *
	 * @param midterm1 The first midterm exam value
    */
	public void setMidterm1 (double midterm1)
	{
		this.midterm1 = midterm1;
	}
	
	/***********************************************
	 * setMidterm2 - sets the value of the second midterm
	 *
	 * @param midterm1 The second midterm exam value
    */
	public void setMidterm2 (double midterm2)
	{
		this.midterm2 = midterm2;
	}
	
	/***********************************************
	 * setName resets the name of this student
	 *
	 * @param name The name of this student
	 */
	public void setName	(String name)
	{
		this.name = name;
	}
	
	/**********************************************
	 * getGrade calculates and returns the final grade
	 * based on the weightings for this class
	 *
	 * @return The final grade value
	 */
	public double getGrade ()
	{
		double grade;
		
		grade = getLabAve() * LAB_PERCENT;
		grade = grade + (midterm1 * MID1_PERCENT);
		grade = grade + (midterm2 * MID2_PERCENT);
		grade = grade + finalExam * FINAL_PERCENT;
		
		return grade;

	}
	
	/***********************************************
	 * getLabAve calculates the average of all of the labs
	 * This average is modified by removing the two lowest 
	 * grades if we have 3 grades or more
	 *
	 * @return The lab average
	 */
	public double getLabAve ()
	{
		double ave;
		double sum;
		double[] low;
		
		// calculate the sum
		sum = 0;
		for (int ii = 0; ii < lab.length; ii++)
		{
			sum = sum + lab[ii];
		}
		
		if (lab.length >= 3) // enough to drop two
		{
			// create a temp array and use it to sort
			low = new double[lab.length];
			
			for (int ii = 0; ii < lab.length; ii++)
				low[ii] = lab[ii];
		
			Arrays.sort(low);
			
			sum = sum - (low[0] + low[1]);  // take off two lowest
		}
		
		// calcuate the average
		if (lab.length >= 3)
			ave = sum / (lab.length - 2);
		else if (lab.length >0)
			ave = sum / lab.length;
		else
			ave = 0;
			
		return ave;
	}
	
	/*********************************************
	 * toString produces a String representation of
	 * this Grade139 object including name, individual
	 * grades and the final average
	 */
	public String toString()	
	{
		String result;
		result = name;
		
		result = name + " Labs: ";
		
		for (int ii = 0; ii < lab.length; ii++)
			result = result + lab[ii] + "\t";
		
		result = result + "\n\t";
		result = result + "Midterm 1: " + midterm1 + " Midterm 2: " +
			midterm2 + " Final Exam: " + finalExam + "\n\t";
		result = result + "Final Grade: " + getGrade();
		
		return result;
	}
} // class 