// (C)2007 Attila Kovacs <attila@submm.caltech.edu>


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

public abstract class CoordinateEpoch implements Cloneable, Comparable<CoordinateEpoch> {
	public double year;

	public CoordinateEpoch() {}

	public CoordinateEpoch(double epoch) { year = epoch; }

	public Object clone() {
		try { return super.clone(); }
		catch(CloneNotSupportedException e) { return null; }		
	}
	
	public boolean equals(Object o) {
		if(!(o instanceof CoordinateEpoch)) return false;
		CoordinateEpoch epoch = (CoordinateEpoch) o;
		return Math.abs(epoch.getJulianYear() - getJulianYear()) < precision;
	}
	
	public int compareTo(CoordinateEpoch epoch) {
		double y1 = getJulianYear();
		double y2 = epoch.getJulianYear();
		if(Math.abs(y1 - y2) < precision) return 0;
		else return y1 < y2 ? -1 : 1;
	}
	
	public abstract double getJulianYear();

	public abstract double getBesselianYear();
	
	public abstract void setMJD(double MJD);
	
	public abstract double getMJD();
	
	public void forJulianDate(double JD) { setMJD(JD - 2400000.5); }
	
	public double getJulianDate() { return getMJD() + 2400000.5; }
	
	
	public void edit(Cursor cursor) throws HeaderCardException { edit(cursor, ""); }
	
	public void edit(Cursor cursor, String alt) throws HeaderCardException {
		cursor.add(new HeaderCard("EQUINOX" + alt, year, "The epoch of the quoted coordinates"));
	}
	
	public void parse(Header header) { parse(header, ""); }

	public void parse(Header header, String alt) {
		year = header.getDoubleValue("EQUINOX" + alt, this instanceof BesselianEpoch ? 1950.0 : 2000.0);
	}
	

	public static CoordinateEpoch forString(String text) throws NumberFormatException {
		if(text.charAt(0) == 'B') return new BesselianEpoch(Double.parseDouble(text.substring(1)));
		else if(text.charAt(0) == 'J') return new JulianEpoch(Double.parseDouble(text.substring(1)));
		else {
			double year = Double.parseDouble(text);
			if(year < 1984.0) return new BesselianEpoch(year);
			else return new JulianEpoch(year);
		}
	}
	
	protected final static double besselianYear = 365.242198781;
	protected final static double julianYear = 365.25;
	protected final static double mjdB2000 = 2451544.5334;
	protected final static double mjdJ2000 = 2451545.0;

	public final static BesselianEpoch B1900 = new BesselianEpoch(1900.0);
	public final static BesselianEpoch B1950 = new BesselianEpoch(1950.0);
	public final static JulianEpoch J2000 = new JulianEpoch(2000.0);
	
	//  B = 1900.0 + (JD - 2415020.31352) / 365.242198781
    //  J = 2000.0 + (JD - 2451545.0) / 365.25
    //  -> B2000.0 = 2451544.5334
    //  J2000.0-B2000.0 = 0.466601900291
    //  2451545.0 JD = 1 January 2000, 11:58:55.816 UT, or 11:59:27.816 TAI
	
	// The precision to which to epochs must match to be considered equal...
	public final static double precision = 1e-3;
}
