import nom.tam.fits.*;
import nom.tam.util.*;

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

public class CalibrationTool {
    public static String version = "8 March 2004";
    public static String fileName = Crush.workPath + "calibration.dat";

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

	    ReducedData reduced = new ReducedData();

	    for(int i=0; i<args.length; i++) {
		if(isOption(args[i])) option(args[i]);
		else reduced.read(args[i]);
	    }

	    final double arcsec = Unit.ArcSECOND;

	    reduced.clip(-45.0*arcsec, -45.0*arcsec, 45.0*arcsec, 45.0*arcsec);	    

	    PointingData pointing = reduced.getPointingData();
	    double measuredFWHM = pointing.FWHM.value;
	    double reduceFWHM = Math.sqrt(measuredFWHM*measuredFWHM - reduced.effectiveResolution*reduced.effectiveResolution);
	    double correctionFactor = reduced.getSourceCorrectionFactorFor(Math.max(reduceFWHM, reduced.beamFWHM));

	    reduced.scale(correctionFactor);
	    pointing.flux.scale(correctionFactor);
	    pointing.extFlux.scale(correctionFactor);
	    
	    reduced.convolveTo(9.0 * Unit.ArcSECOND);
	    
	    int[] index = reduced.indexOfMax(reduced.s2n);
	    DataPoint flux9 = new DataPoint();
	    flux9.value = reduced.clean[index[0]][index[1]] / reduced.janskyPerBeam.value;
	    flux9.rms = reduced.rms[index[0]][index[1]] / reduced.janskyPerBeam.value;

	    DecimalFormat pf = new DecimalFormat("0.0");
	    DecimalFormat df = new DecimalFormat("0.00E0");
	    DecimalFormat ef = new DecimalFormat("0E0");
	    DecimalFormat f3 = new DecimalFormat("0.000");
	    DecimalFormat f2 = new DecimalFormat("0.00");
	    DecimalFormat i2 = new DecimalFormat("00");

	    File file = new File(fileName);
	    boolean isNew = !file.exists();
	    RandomAccessFile outFile = new RandomAccessFile(file, "rw");

	    if(isNew) {
		String header = "Name\t\tScanNo\tdate       UT\ttau    AZ,EL    \t" +
		    "Tamb\tTx\tFocus X,Y,Z (mm)\tFAZO,FZAO\tFWHM\t" +
		    "Iflux (Jy)\tEFlux (Jy)\t9\"Flux (Jy/bm)"; 
		
		outFile.writeBytes("! SHARC2 Calibration File\n");
		outFile.writeBytes("! Created by Crush " + Crush.version + "\n");
		outFile.writeBytes("!\n");
		outFile.writeBytes("! " + header + "\n");
	    }
	    
	    outFile.seek(outFile.length());

	    SharcScan scan = reduced.scan[0];

	    StringTokenizer dateTokens = new StringTokenizer(scan.date, "-:T");

	    int year = Integer.parseInt(dateTokens.nextToken());
	    int month = Integer.parseInt(dateTokens.nextToken());
	    int day = Integer.parseInt(dateTokens.nextToken());
	    int hour = Integer.parseInt(dateTokens.nextToken());
	    int min = Integer.parseInt(dateTokens.nextToken());
	    double sec = Double.parseDouble(dateTokens.nextToken());
	    
	    String info = 
		scan.sourceName + (scan.sourceName.length() <= 7 ? "\t\t" : "\t") +
		scan.serialNo + "\t" +

		year + "-" +
		i2.format(month) + "-" +		
		i2.format(day) + " " +

		pf.format(hour + min/60.0) + "\t" +

		f3.format(ReductionTool.getTau("225GHz", scan.tau)) + "  " +

		pf.format(scan.AZ / Unit.DEGREE) + "," +		

		pf.format(scan.EL / Unit.DEGREE) + "\t" +
		
		pf.format(scan.temperature) + "\t" +

		f2.format(scan.excessLoadT) + "\t" +

		f2.format(scan.focusX) + "." + f2.format(scan.focusY) + "," + f2.format(scan.focusZ) + "\t" +

		(reduced.altaz ? pf.format(pointing.FAZO.value / Unit.ArcSECOND) : "---") + "," +
		
		(reduced.altaz ? pf.format(pointing.FZAO.value / Unit.ArcSECOND) : "---   ") + "\t" +	      

		pf.format(pointing.FWHM.value / Unit.ArcSECOND) + "\t" +

		df.format(pointing.flux.value) + ":" +
		
		ef.format(pointing.flux.rms) + "\t" +

		df.format(pointing.extFlux.value) + ":" +

		ef.format(pointing.extFlux.rms) + "\t" +

		df.format(flux9.value) + ":" +
		
		ef.format(flux9.rms) + "\t" +

		"\n";

	    outFile.writeBytes(info);
	    outFile.close();
	}
	   
	      
	catch(Exception e) { e.printStackTrace(); }
    }

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

	String key = tokens.nextToken();

	//options.add(optionString);
	
	if(key.equalsIgnoreCase("-out")) fileName = tokens.nextToken();

	else if(key.equalsIgnoreCase("-help")) usage();

	else System.out.println("WARNING! Unrecognized option: " + key);
    
    }

    public static boolean isOption(String argument) {
	return argument.charAt(0) == '-';
    }
    
    public static void versionInfo() {
	System.out.println("calibrate -- Flux Calibration Tool for SHARC2");
	System.out.println("             Author: Attila Kovacs <attila@submm.caltech.edu>");
	System.out.println("             Version: " + version);
	System.out.println();
    }
    
    public static void usage() {
	Crush.versionInfo();
	System.out.println("usage: calibrate [options] <image>");
	System.out.println();
	System.out.println("    Appends calibration data from the image to \'" + fileName + "\'.");
	System.out.println("    If the file does not exist, it will be created.");
	System.out.println();
	System.out.println("options:");
	System.out.println();
	System.out.println("    <image>    The FITS image file of the calibration source.");
	System.out.println("               Should be reduced in Alt/Az mode in crush.");
	System.out.println("    -out=      The output file name (" + fileName + ")");
	System.out.println("    -help      Shows this help screen.");
	
			   
	System.out.println();
	
	System.exit(0);
    }
    
}


