import java.util.*;

public class Lake {
	private String name;		// Lake name
	private double depth;		// Depth in m
	private double area;		// Area in km^2
	private Observation[] data;	// (Depth, temperature, oxygen concentration)

	private static int nbrLakes = 0;	// Number of lakes in program
	public static final double MIN_OXYGEN = 5;	// Min allowable level (mg/L)

	public Lake(String n, double a, double d, Observation[] dd) {
		name = n;
		area = a;
		depth = d;
		data = dd;
		nbrLakes++;		// Increment number of lakes each time constructor run
	}
	
	public static int getNbrLakes() {
		return nbrLakes;
	}

	public double getArea() {
		return area;
	}

	public double getDepth() {
		return depth;
	}

	public String getName() {
		return name;
	}

	public ArrayList getThermocline() {
		double maxTempChange = 0;
		int topOfThermocline = -1;
		int bottomOfThermocline = -1;
		
		// Loop thru temperatures, find biggest change between adjacent data
		for (int i = 1; i < data.length; i++) {
			double tempChange = data[i-1].temp - data[i].temp;
			if (tempChange >= maxTempChange) {
				maxTempChange = tempChange;
				topOfThermocline = i-1;
				bottomOfThermocline = i;
			}
		}
		// Starting from bottom of biggest change, see if equal or nearly equal
		// (within 1 degree) changes continue below it. If so, expand cline
		for (int i = bottomOfThermocline + 1; i < data.length; i++) {
			double tempChange = data[i-1].temp - data[i].temp;
			if (tempChange > maxTempChange - 1)
				bottomOfThermocline = i;
			else
				break;
		}
		
		// Starting from top of biggest change, see if equal or nearly equal 
		// (within 1 degree) changes continue above it. If so, expand cline
		for (int i = topOfThermocline; i >= 0; i--) {
			double tempChange = data[i-1].temp - data[i].temp;
			if (tempChange > maxTempChange - 1)
				topOfThermocline = i-1;
			else
				break;
		}
		
		// Output will be array list of top depth, bottom depth, temperature change
		// Put these three values in ArrayList. Look up depth from data array
		// at the indexes for the top and bottom of the thermocline
		ArrayList result = new ArrayList();
		result.add(new Double(data[topOfThermocline].depth));
		result.add(new Double(data[bottomOfThermocline].depth));
		double tempDiff= data[topOfThermocline].temp - data[bottomOfThermocline].temp;
		result.add(new Double(tempDiff));
		return result;
	}
	
	// Static method must get data array as argument; it has no access to it
	// in the object
	public static double getMinTemp(Observation[] d) {
		double minTemp = 9999;
		
		for (int i = 0; i < d.length; i++) {
			if (d[i].temp < minTemp)
				minTemp = d[i].temp;
		}
		return minTemp;
	}

	public static double getMaxTemp(Observation[] d) {
		double maxTemp = -9999;
		for (int i = 0; i < d.length; i++) {
			if (d[i].temp > maxTemp)
				maxTemp = d[i].temp;
		}
		return maxTemp;
	}
	public double[] getAvgOxygen() {
		// Run method to get thermocline; can't assume it's been run
		ArrayList cline = getThermocline();
		// Get the top and bottom depths of the cline
		double topZ = ((Double) cline.get(0)).intValue();
		double bottomZ = ((Double) cline.get(1)).intValue();

		// Find the indices in the data array of the top and bottom of cline
		int topOfThermocline= -1, bottomOfThermocline= -1;		
		for (int i=0; i < data.length; i++){
			if (data[i].depth == topZ) topOfThermocline= i;
			if (data[i].depth == bottomZ) bottomOfThermocline= i;
		}
		// Compute avg oxygen concentration above cline
		double sumOxyAbove = 0, sumOxyBelow = 0;		
		for (int i = 0; i < topOfThermocline; i++)
			sumOxyAbove += data[i].oxygen;
		double avgOxyAbove = sumOxyAbove / topOfThermocline;

		// Compute avg oxygen concentration below cline
		for (int i = bottomOfThermocline + 1; i < data.length; i++)
			sumOxyBelow += data[i].oxygen;
		double avgOxyBelow = sumOxyBelow / (data.length - bottomOfThermocline-1);
		
		// Place results into array, which is return value
		double[] result= new double[2];
		result[0]= avgOxyAbove;
		result[1]= avgOxyBelow;
		return result;
	}
	
	public boolean isOxyBelowOK() {
		// Compute oxygen levels first (which in turn compute cline)
		double[] oxygen= getAvgOxygen();
		double oxyBelow= oxygen[1];		// Bottom oxy concentration
		return (oxyBelow > MIN_OXYGEN);
	}
}
