/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2007 Approximatrix, LLC
 *  http://www.approximatrix.com
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.approximatrix.draco.math;

public class CalculateHistogram {

	private String[] bins = null;
	private int[] frequency = null;
	private int first_outliers = 0;
	private int last_outliers = 0;
	
	public CalculateHistogram(double[] values, double first, double last, double bin_size) {
		
		if(first > last) {
			double temp = first;
			first = last;
			last = temp;
		}
		
		int number_of_bins = (int)Math.round(Math.abs(last-first)/bin_size)+1;
		if(number_of_bins <= 1)
			number_of_bins = 2;
		
		
		// Create the bins
		bins = new String[number_of_bins];
		Double[] bin_threshhold = new Double[number_of_bins];
		frequency = new int[number_of_bins];
		
		bin_threshhold[0] = new Double(first);
		bins[0] = bin_threshhold[0].toString();
		for(int i=1;i<number_of_bins;i++) {
			bin_threshhold[i] = significance_check(bin_threshhold[i-1].doubleValue()+bin_size,bin_size);
			bins[i] = bin_threshhold[i].toString();
			frequency[i] = 0;
		}
		
		first_outliers = 0;
		last_outliers = 0;
		
		// Sort the data into bins
		for(int i=0;i<values.length;i++) {
			int bin_counter = 0;
			while(values[i]>=bin_threshhold[bin_counter].doubleValue()) {
				bin_counter++;
				if(bin_counter >= number_of_bins) break;
			}
			bin_counter--;
			
			// Count outliers
			if(values[i] > last)
				last_outliers++;
			else if(values[i] < first)
				first_outliers++;
			else
				frequency[bin_counter]++;
		}
		
	}
	
	public String[] getBins() {
		return bins;
	}
	
	public int[] getFrequency() {
		return frequency;
	}
	
	public int getOutliersCount() {
		return last_outliers+first_outliers;
	}
	
	public int getHighOutliersCount() {
		return last_outliers;
	}
	
	public int getLowOutliersCount() {
		return first_outliers;
	}
	
	private Double significance_check(double value, double significance_baseline) {
		if(significance_baseline > value) return new Double(value);
		if(significance_baseline == 0.0) return new Double(value);
		if(significance_baseline % 1.0 != 0.0) {
			int counter = 0;
			double temp_base = Math.abs(significance_baseline);
			while(temp_base > Math.floor(temp_base)) {
				counter++;
				temp_base = temp_base*10.0;
			}
			
			double return_val = value;
			for(int i=0;i<=counter;i++) {
				return_val = return_val*10.0;
			}
			return_val = Math.round(return_val);
			for(int i=0;i<=counter;i++) {
				return_val = return_val/10.0;
			}
			return new Double(return_val);
		} else {
			return new Double(value);
		}
		
	}
}
