package crushtools;
/*******************************************************************************
 * Copyright (c) 2014 Attila Kovacs <attila[AT]sigmyne.com>.
 * All rights reserved. 
 * 
 * This file is part of crushtools.
 * 
 *     crushtools 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.
 * 
 *     crushtools 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 crushtools.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Attila Kovacs <attila[AT]sigmyne.com> - initial API and implementation
 ******************************************************************************/

import java.io.*;
import java.util.*;

import jnum.Unit;
import jnum.Util;


public class HistogramTool {
	static double binres = 1.0;
	static String type = "s2n";
	static String fileName;

	public static void main(String[] args) {
		versionInfo();
		if(args.length == 0) usage();

		SkyMap map = null;
		
		try { map = new SkyMap(args[args.length-1]); }
		catch(Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		
		ImageTool.image = map;
		
		for(int k=0; k < args.length-1; k++) option(args[k]);

		try {		
			double binningWidth = binres;
			double[][] image = map.s2n;			
			
			if(type.equalsIgnoreCase("flux")) { image = map.signal; binres *= map.nativeUnit.value(); }
			else if(type.equalsIgnoreCase("s2n")) {}
			else if(type.equalsIgnoreCase("rms")) { image = map.rms; binres *= map.nativeUnit.value(); }
			else if(type.equalsIgnoreCase("weight")) { image = map.weight; binres /= map.nativeUnit.value() * map.nativeUnit.value(); }
			else if(type.equalsIgnoreCase("time")) { image = map.count; binres *= Unit.s; }
			
			int zeroBin = (int) Math.ceil(-map.getMin(image) / binres);
			int bins = 1 + zeroBin + (int) Math.ceil(map.getMax(image) / binres);

			int[] count = new int[bins];

			for(int i=0; i<map.sizeX; i++) for(int j=0; j<map.sizeY; j++) if(map.flag[i][j] == 0) {
				int bin = zeroBin + (int) Math.round(image[i][j] / binres);		
				count[bin]++;
			}

			if(fileName == null) fileName = SkyMap.workPath + "histogram-" + type + "." + map.sourceName + ".dat"; 

			PrintWriter out = new PrintWriter(new BufferedOutputStream(new FileOutputStream(fileName)));

			out.println("# histogram for " + map.fileName);
			out.println("# bin resolution is " + binningWidth + " (in default units)");
			out.println("# bin\t" + type + "\tcount");
			out.println("# ----\t-----\t------");

			for(int i=0; i<bins; i++) out.println((i+1) + "\t" + Util.e5.format((i-zeroBin)*binningWidth) + "\t" + count[i]);

			out.close();
			
			// Report Gaussianity...
			System.out.println("Gaussianity of residuals: " + Util.f3.format(map.getGaussianity(binningWidth)) + ".");
			
			System.out.println("Written histogram to " + fileName);
		}
		catch(Exception e) { e.printStackTrace(); }	
	}

	public static boolean option(String optionString) {
		StringTokenizer tokens = new StringTokenizer(optionString, "=");

		String key = tokens.nextToken();

		if(key.equalsIgnoreCase("-bin")) binres = Double.parseDouble(tokens.nextToken());
		else if(key.equalsIgnoreCase("-image")) type = tokens.nextToken(); 
		else if(key.equalsIgnoreCase("-out")) fileName = Util.getSystemPath(tokens.nextToken());
		else if(key.equalsIgnoreCase("-help")) usage();
		else return ImageTool.option(optionString);
	
		return true;    
	}

	public static void versionInfo() {
		System.out.println("histogram -- Histogram Generation Utility for CRUSH maps and more.");
		System.out.println("             Author: Attila Kovacs <attila[AT]sigmyne.com>");
		System.out.println("             Version: " + SkyMap.version);
		System.out.println();
	}

	public static void usage() {
		System.out.println("Usage: histogram [options] <filename>");
		System.out.println();
		System.out.println("Options:");
		System.out.println();
		System.out.println("  All options of 'imagetool' are available. Additionally, 'histogram' defines");
		System.out.println("  the following options:");
		System.out.println();
		System.out.println("    -bin=      Set the bin size in the units of the image plane. (" + binres + ")");
		System.out.println("    -image=    Select which image to use for the histogram");
		System.out.println("               (image name is one of: flux,s2n,rms,weight,time)");
		System.out.println("    -out=      Set the output file's name.");	
		System.out.println("    -help      Provides this help screen.");
		System.out.println();

		System.exit(0);
	}
}
