package crushtools;
/*******************************************************************************
 * Copyright (c) 2019 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.util.*;

import jnum.Unit;

//noise-peaks
//N_beam * Q = N_max -- limiting the number of false detections
//Q = N_max / N_beam

public class SourceExtractor {
	static double significance = 4.0;
	static boolean isOneSided = true;
	static SkyMap image;

	public static void main(String[] arg) {
		versionInfo();
		

		if(arg.length == 0) usage();

		try {
			ImageTool.image = new SkyMap(arg[arg.length-1]);
			image = ImageTool.image;
	
			image.displayUnit = image.getUnit("Jy/beam");

	        boolean beamSmooth = true;
	        for(int i=1; i<arg.length-1; i++) {
	            String option = arg[i].toLowerCase();
	            if(option.startsWith("-smooth")) {
	                beamSmooth = false;
	                break;
	            }
	        }
			
	        // Make sure map is convolved at least to beam
	        if(beamSmooth) image.convolveTo(image.instrumentFWHM);
	        
			// Apply any other imagetool options...
			for(int i=1; i<arg.length-1; i++) {
				String option = arg[i];
				StringTokenizer tokens = new StringTokenizer(option, ":=");
				String key = tokens.nextToken();
				
				// Explicit smoothing requested. Do not beam-smooth.
				if(key.equalsIgnoreCase("-smooth")) beamSmooth = false;
				
				if(option.equalsIgnoreCase("-symmetric")) isOneSided = false;
				else if(option.equalsIgnoreCase("-gaussian")) image.gaussianStats = true;
				else if(option.equalsIgnoreCase("-dynamic")) image.iterateNoise = true;
				else if(key.equalsIgnoreCase("-area")) image.assumedArea = Double.parseDouble(tokens.nextToken()) * Unit.arcmin2; 
				else ImageTool.option(option);
				
			}
			
			//image.extFilterFWHM = Double.NaN;
			
			image.clearRegions();
			
			extract(image, arg[0]);
			
				
			image.fileName = SkyMap.workPath + image.sourceName + ".residual.fits";
			
			image.write();
			
			image.writeSources();
		}
		catch(Exception e) { e.printStackTrace(); }
	}

	public static boolean extract(SkyMap image, String optionString) {
		StringTokenizer tokens = new StringTokenizer(optionString, "=");

		String key = tokens.nextToken();

		if(key.equalsIgnoreCase("confidence")) {
			image.extract(SkyMap.DETECTION_CONFIDENCE, Double.parseDouble(tokens.nextToken()), isOneSided);
		}
		else if(key.equalsIgnoreCase("s2n")) {
			image.extract(SkyMap.SIGNAL_TO_NOISE, Double.parseDouble(tokens.nextToken()), isOneSided);
		}
		else if(key.equalsIgnoreCase("nofalse")) {
			image.extract(SkyMap.FALSE_DETECTION_CHANCE, 1.0 - Double.parseDouble(tokens.nextToken()), isOneSided);
		}
		else if(key.equalsIgnoreCase("false")) {
			image.extract(SkyMap.MAX_FALSE_DETECTIONS, Double.parseDouble(tokens.nextToken()), isOneSided);
		}
		else if(key.equalsIgnoreCase("-help")) usage();
		else return false;

		return true;    
	}

	public static void versionInfo() {
		System.out.println("detect -- Source Detection 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: detect criterion [-options] <filename>");
		System.out.println();
		System.out.println("Criteria:");
		System.out.println();
		System.out.println("    confidence=  Minimum confidence level for each detection.");
		System.out.println("    s2n=         S/N level for detections. (" + significance + ")");
		System.out.println("    nofalse=     The confidence level that there are no false detections.");
		System.out.println("    false=       The expected number of false detections.");
		System.out.println("    help         Provides this help screen.");
		System.out.println();
		System.out.println("Options:");
		System.out.println();
		System.out.println("  All options of 'imagetool' are available. Additionally, 'detect' defines the");
		System.out.println("  following options:");
		System.out.println();
		System.out.println("    -area=       Specify the extraction area (in sq-armin) if it is different");
		System.out.println("                 from the area of the supplied map.");
		System.out.println("    -dynamic     Re-estimate the noise with every extraction round.");
		System.out.println("    -gaussian    Use strictly Gaussian statistics for calculating cumulative");
		System.out.println("                 false detections and confidence levels.");
		System.out.println("    -symmetric   Always use symmetric noise estimates (default is one-sided).");
		System.out.println();
		
		//ImageTool.optionsSummary();
		
		System.exit(0);
	}

}
