//import cs1.Keyboard;
import java.text.*;

/**
GradeBook class asks the user to supply the number of grades,
uses that number to initialize a GradeBook object, and
collects grades from the user (keyboard) then
computes and displays statistics about the grades
*/

public class GradeBook
{
	int numElements;
	private double[] scores;


	//if we pass a whole array (created in GPACalc4), this parametrized
	//constructor-1 will be in charge.
	//(-------------------- Run program from GPACalc4_use).

	public GradeBook(double[] grades)	//parametrized constructor-1
	{
		scores = grades; //parameter passed is array 'grades', but in the
					//methods below we work with array 'scores'.
					//With this assignment statement the program
					//will assume that 'scores' is alias to 'grades'
	}

	//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

	//This part will work if we do not pass a whole array, but
	//only a number of elements in array. In this case, the array of
	//grades will be filled using the fillScores() method.
	//(--------------------- Run program from GradeBook_use).

	/**Creates a GradeBook object and initializes the internal
	array to the number of elements specified by the user.*/

	public GradeBook(int numElements)	//parametrized constructor-2
	{
		this.numElements = numElements;
	}


	public void fillScores()
	{
		scores = new double[numElements];			//scores.length

		for (int i=0; i<=numElements-1; i++)
		{
			System.out.print ("Grade for class " + (i+1) + ":\t");
			scores[i] = Keyboard.readDouble();	////////// fill array scores

			while (scores[i] < 0 || scores[i] > 4)
			{
				System.out.println ("Invalid grade");
				System.out.print ("Grade for class " + (i+1) + ": \t");
				scores[i] = Keyboard.readDouble();
			}
			//System.out.println ("Element " +i+ " -- " +scores[i]+ "\n");
		}
	}
	//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


	/** Performs a linear search for the minimum value in the array. Return the minimum value */

	public double findMinimum()
	{
		double min = scores[0];

		for (int i=0; i<=scores.length-1; i++)
		{
			if (scores[i] < min)
			{
				min = scores[i];
			}
		}
		return min;
	}


	/** Performs a linear search for the maximum value in the array. Return the maximum value */

	public double findMaximum()
	{
		double max = 0;

		for (int i=0; i<=scores.length-1; i++)
		{
			if (scores[i] > max)
			{
				max = scores[i];
			}
		}
		return max;
	}


	/** Sums the grades and calculates the mean (average). Return the mean */

	public double calcMean()
	{
		double total_score = 0;
		double mean =0 ;

		for (int i=0; i<scores.length; i++)
		{
			total_score = total_score + scores[i];
			mean = total_score / scores.length;
		}
		return mean;
	}


	/** Find # grades above average */

	public int countGoodGrades()
	{
		int count_goods=0;					//grades above average
		for (int i=0; i<scores.length; i++)
		{
			if (scores[i] > calcMean())
			{
				count_goods++;
			}
		}
		return count_goods;
	}


	/** Sums the squares of the variance of each grade from mean,
	divides by the count, and takes the square root of the result
	(result is the square root of the total variance) which is the StdDev
	Returns the Standard deviation. */

	public double calcStdDev()
	{
		double sumVarianceSq = 0;
		double variance;
		double stdDeviation = 0;

		for (int i=0; i<scores.length; i++)
		{
			variance = scores[i] - calcMean();
			sumVarianceSq = sumVarianceSq + (variance*variance);
		}
		stdDeviation = Math.sqrt(sumVarianceSq / scores.length);
		return stdDeviation;
	}

/*
	public double calcStdDev()
	{
		double sumGradeSq = 0;
		double stdDeviation = 0;

		for (int i=0; i<scores.length; i++)
		{
			sumGradeSq = sumGradeSq + scores[i]*scores[i];
		}
		stdDeviation=Math.sqrt(sumGradeSq/scores.length - calcMean()*calcMean());
		return stdDeviation;
	}

*/

	/** Finds the median grade where ½ the grades are less and ½ are greater
	It sorts the data first by calling a private sort method based on the
	BubbleSort Algorithm. Returns the median value */

	public double findMedian()
	{
		double median = 0;

		sort();

		if (scores.length % 2 != 0)
		{
			median = scores[(scores.length/2)];
		}
		else
		{
			//find the average of the two middle elements
			median = (
					  scores[(scores.length/2)] +
					  scores[(scores.length/2)-1]
					  ) / 2;
		}
		return median;
	}



	/** Sorts the array using the Bubblesort Algorithm. */

	//Bubble sort goes through all elements of array and swap
  	//adjacent values until a whole list is sorted.

	public void sort()
	{
		int i, n;

		for(i=0; i<scores.length; i++)
		{
		   for(n=1; n<(scores.length-i); n++)
		   {
			  if( scores[n-1]>scores[n] )	//if previous grade is more then next
			  {							//swap them
				  double temp = scores[n];
				  scores[n] = scores[n-1];
				  scores[n-1] = temp;
			  }
		   }
	    }
	}


	public void DisplayStatistics()
	{
		DecimalFormat df = new DecimalFormat("0.00");

		System.out.println("\n-------------------------");
		System.out.println("Grade Statistics:");
		System.out.println("-------------------------");
		System.out.println("Minimum: \t" + df.format(findMinimum()));
		System.out.println("Maximum: \t" + df.format(findMaximum()));
		System.out.println("Median: \t"  + df.format(findMedian()));
		System.out.println("Average: \t" + df.format(calcMean()));
		System.out.println("# grades above average: " + countGoodGrades());
		System.out.println("Standard Deviation: " + df.format(calcStdDev()));
		System.out.println();
	}


	/** Converts the array contents into a String for display
	Returns a string representing the contents of the grade book object. */

	public String toString()
	{
		String gradesStr = "";
		return gradesStr;
	}
}