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


// This is an abstract class for coordinate systems that are fixed (except perhaps a precession)
// w.r.t the distant stars (quasars)...
public abstract class CelestialCoordinates extends SphericalCoordinates {

	public CelestialCoordinates() { super(); }
	
	public CelestialCoordinates(String text) { super(text); }
	
	public CelestialCoordinates(double lon, double lat) { super(lon, lat); }
	
	public CelestialCoordinates(CelestialCoordinates from) {
		convert(from, this);
	}
	

	
	public abstract EquatorialCoordinates getEquatorialPole();
	
	public abstract double getZeroLongitude();
	
	public EquatorialCoordinates toEquatorial() {
		EquatorialCoordinates equatorial = new EquatorialCoordinates();
		toEquatorial(equatorial);
		return equatorial;
	}
	
	public void toEquatorial(EquatorialCoordinates equatorial) {
		SphericalCoordinates.inverseTransform(this, getEquatorialPole(), getZeroLongitude(), equatorial);
	}
	
	public void fromEquatorial(EquatorialCoordinates equatorial) {
		SphericalCoordinates.transform(equatorial, getEquatorialPole(), getZeroLongitude(), this);
	}
	
	public void convertFrom(CelestialCoordinates other) {
		convert(other, this);
	}
	
	public void convertTo(CelestialCoordinates other) {
		convert(this, other);
	}
	
	/*
	public void toEcliptic(EclipticCoordinates ecliptic) { convertTo(ecliptic); }
	
	public void toGalactic(GalacticCoordinates galactic) { convertTo(galactic); }
	
	public void toSuperGalactic(SuperGalacticCoordinates supergal) { convertTo(supergal); }
	
	public EclipticCoordinates toEcliptic() {
		EclipticCoordinates ecliptic = new EclipticCoordinates();
		convertTo(ecliptic);
		return ecliptic;
	}
	
	public GalacticCoordinates toGalactic() {
		GalacticCoordinates galactic = new GalacticCoordinates();
		convertTo(galactic);
		return galactic;
	}
		
	public SuperGalacticCoordinates toSuperGalactic() {
		SuperGalacticCoordinates supergal = new SuperGalacticCoordinates();
		convertTo(supergal);
		return supergal;
	}
	*/
	
	private static EquatorialCoordinates reuseEquatorial = new EquatorialCoordinates();
	public static void convert(CelestialCoordinates from, CelestialCoordinates to) {
		
		if(from.getClass().equals(to.getClass())) {
			if(from instanceof Precessing) {
				CoordinateEpoch toEpoch = ((Precessing) to).getEpoch();
				to.copy(from);
				((Precessing) to).precess(toEpoch);
			}
			else to.copy(from);
		}
		
		if(from instanceof EquatorialCoordinates) reuseEquatorial = (EquatorialCoordinates) from;
		else from.toEquatorial(reuseEquatorial);
		
		if(to instanceof EquatorialCoordinates) {
			if(!reuseEquatorial.epoch.equals(((EquatorialCoordinates) to).epoch)) reuseEquatorial.precess(((EquatorialCoordinates) to).epoch);
			to.copy(reuseEquatorial);
		}
		else to.fromEquatorial(reuseEquatorial);
	}
	
	
	public static EquatorialCoordinates getPole(double inclination, double risingRA) {
		return new EquatorialCoordinates(risingRA - quarterTurn, quarterTurn - inclination);
	}

	public static EquatorialCoordinates getPole(CelestialCoordinates referenceSystem, double inclination, double risingLON) {
		referenceSystem.setCanonical(risingLON - quarterTurn, quarterTurn - inclination);
		return referenceSystem.toEquatorial();
	}
	
	public static double getZeroLongitude(CelestialCoordinates from, CelestialCoordinates to) {
		EquatorialCoordinates equatorialZero = from.toEquatorial();
    	to.fromEquatorial(equatorialZero);
    	return to.longitude();		
	}
	
	
}
