// Datei Astro.js

var P2 = Math.PI*2;
var toRad = Math.PI/180;
var toDec = 180/Math.PI;

// Objekt-Konstanten
var SONNE = 0;
var MOND = 1;

// sin/cos Ekliptik
var CosEps = 0.91748;
var SinEps = 0.39778;

// Position Object
function CPosition(RA,DEC){
	this.RA = RA;
	this.DEC = DEC;
	}
	
// Mondphase in Grad und %
function CMoonPhase(Angle,Part){
	this.Angle = Angle;
	this.Part = Part;
}

// EkliticPosition Object
function CePos(Lambda, Beta){
	this.Lambda = Lambda;
	this.Beta = Beta;
	}
	
// Auf/Untergangszeiten
function CTimes(UTRise,UTSet,Sichtbar){
	// Zeit negativ==> nicht gültig
	// Sichtbar: -1 immer unsichtbar, 0=Daten gültig, 1=immer sichtbar
	this.UTRise = UTRise;
	this.UTSet = UTSet;
	this.Sichtbar = Sichtbar;
	}
	
// Objekt für Ergebnis von Quad
function CQuadData(XE,YE,ZERO1,ZERO2,NZ){
	this.XE=0;
	this.YE=0;
	this.ZERO1=0;
	this.ZERO2=0;
	this.NZ=0;
	}
	
function Frac(Num) {
	var x=0;
	if (Num<0){
		x=Num-Math.ceil(Num);
		}
	else{
		x=Num-Math.floor(Num);
		}
	return x;
	}

function ConvertToEcliptic(Pos) {

	//  convert RA / Dec to radian
	var alpha = Pos.RA * 15 * toRad;
	var delta = Pos.DEC * toRad;

	var ePos = new CePos(0,0);
	var sinB = Math.sin(delta)*CosEps - Math.cos(delta)*SinEps*Math.sin(alpha);

	ePos.Beta = Math.asin(sinB)*toDec;

	var y = Math.sin(alpha)*CosEps + Math.tan(delta)*SinEps;
	var x = Math.cos(alpha);
	
	var l=0;
	if (x == 0) l = 0;
	else        l = Math.atan(y/x) * toDec;

	if ( x>0 && y>0) ePos.Lambda = l;
	if ( x<0 && y>0) ePos.Lambda = l + 180;
	if ( x<0 && y<0) ePos.Lambda = l + 180;
	if ( x>0 && y<0) ePos.Lambda = l + 360;	

	ePos.Lambda /= 15;
//	alert("RA: " + Pos.RA +"\nDec: " + Pos.DEC + "\n\nl: " + ePos.Lambda + "\nb: " + ePos.Beta);

	return ePos;
	}
	
function GetSunPos(JD) {
	var T = (JD-2451545)/36525;
	
	var M = P2*Frac(0.993133+99.997361*T);
	var DL = 6893*Math.sin(M) + 72*Math.sin(2*M);
	var L = P2*Frac(0.7859453 + M/P2 + (6191.2*T+DL)/1296e3);
	var SL=Math.sin(L);
	var x=Math.cos(L);
	var y=CosEps*SL;
	var z=SinEps*SL;
	var RHO=Math.sqrt(1-z*z);
	var Pos = new CPosition(0,0);
	Pos.DEC = (360/P2)*Math.atan(z/RHO);
	Pos.RA =  ( 48/P2)*Math.atan(y/(x+RHO));
	if (Pos.RA <0) Pos.RA += 24;
	return Pos;
	}
	
function GetMoonPos(JD) {
	var T = (JD-2451545)/36525;
	var Arc = 206264.8062;
	var LO =    Frac(0.606433+1336.855225*T);
	var L  = P2*Frac(0.374897+1325.552410*T);
	var LS = P2*Frac(0.993133+  99.997361*T);
	var D  = P2*Frac(0.827361+1236.853086*T);
	var F  = P2*Frac(0.259086+1342.227825*T);
	var DL = 22640*Math.sin(L) - 4586*Math.sin(L-2*D) + 2370*Math.sin(2*D) + 769*Math.sin(2*L);
		DL += -668*Math.sin(LS) - 412*Math.sin(2*F) - 212*Math.sin(2*L-2*D) - 206*Math.sin(L+LS-2*D);
		DL += 192*Math.sin(L+2*D) - 165*Math.sin(LS-2*D) - 125*Math.sin(D) - 110*Math.sin(L+LS);
		DL += 148*Math.sin(L-LS) - 55*Math.sin(2*F-2*D);
	var S  = F + (DL+412*Math.sin(2*F)+541*Math.sin(LS))/Arc;
	var H  = F-2*D;
	var N  = -526*Math.sin(H) + 44*Math.sin(L+H) - 31*Math.sin(-L+H) - 23*Math.sin(LS+H);
	    N += 11*Math.sin(-LS+H) - 25*Math.sin(-2*L+F) + 21*Math.sin(-L+F);
	var L_Moon = P2*Frac(LO + DL/1296E3);
	var B_Moon = (18520*Math.sin(S) + N) / Arc;
	
	var CB = Math.cos(B_Moon);
	var X = CB*Math.cos(L_Moon);
	var V = CB*Math.sin(L_Moon);
	var W = Math.sin(B_Moon);
	var Y = CosEps*V-SinEps*W;
	var Z = SinEps*V+CosEps*W;
	var RHO = Math.sqrt(1-Z*Z);
	var Pos = new CPosition(0,0);
	Pos.DEC = (360/P2)*Math.atan(Z/RHO);
	Pos.RA  = ( 48/P2)*Math.atan(Y/(X+RHO));
	if (Pos.RA<0) Pos.RA += 24;
	return Pos;
}

function GetMoonPhase(Datum){
// liefert Mondphase in Grad (0°...360°)
	var MoonPhase = new CMoonPhase(0,0);
	
	var JD = Get_JD(Datum);
	var SunPos  = ConvertToEcliptic(GetSunPos(JD));
	var MoonPos = ConvertToEcliptic(GetMoonPos(JD));

	var Diff = MoonPos.Lambda - SunPos.Lambda; // Lambda in h min sec
	if (Diff < 0)
		Diff += 24;
	MoonPhase.Angle = Diff * 15;
	MoonPhase.Part  = Math.round( 0.5*(1-Math.cos(MoonPhase.Angle * toRad)) * 1000)/10; // in %
	
	return MoonPhase;
}

function GetMoonAge(Datum){
// Vmond = (24h / 27.322 Tage) = 0.878413h/Tag
// oder: Vsonne = 24h / 365.2422Tage = 0.0657098h/Tag
// Diff = (Vsonne-Vmond)*Tage ==> Tage = Diff/(Vsonne-Vmond)

// synodisch: 29.53, sider 27.322

	var JD = Get_JD(Datum);
	var SunPos  = ConvertToEcliptic(GetSunPos(JD));
	var MoonPos = ConvertToEcliptic(GetMoonPos(JD));

	var Diff = MoonPos.Lambda - SunPos.Lambda; // Lambda in h min sec
	if (Diff < 0)
		Diff += 24;

//	var Age = Math.round((Diff/0.81270318)*10)/10;
	var Age = Diff/0.81270318;
	var Age0 = Age;


// 1. Korrekturschritt
	var KorrAge = 1;
	var Diff2;
	var i=0;
        
        do{
		   var MoonPos2 =  ConvertToEcliptic(GetMoonPos(JD-Age));
		   var SunPos2  =  ConvertToEcliptic(GetSunPos(JD-Age));

		   Diff2 = MoonPos2.Lambda - SunPos2.Lambda;
		   if (Diff2 < 0)
              Diff2 += 24;
		   KorrAge = Diff2/0.81270318;
		   if (KorrAge < Age){
		      Age += KorrAge;
			   }
		   else{
			  KorrAge = 29.53 - KorrAge;
	          Age -= KorrAge;
              }
	       i += 1;

//	alert("Sonne: " + ToHourMinSec(SunPos.Lambda) + "\nMond: " + ToHourMinSec(MoonPos.Lambda) + "\nDiff: "  
//         + ToHourMinSec(Diff) + "\nAge0: " + Age0 + "\n\nKorrAge: " + KorrAge 
//         + "\nSunPos2.Lambda: " + ToHourMinSec(SunPos2.Lambda) + "\nMoonPos2.Lambda: " + ToHourMinSec(MoonPos2.Lambda) 
//         + "\nSchritte: " + i);

        }
        while (KorrAge > 0.01 && i < 10);



//	alert("Sonne: " + ToHourMinSec(SunPos.RA) + "\nMond: " + ToHourMinSec(MoonPos.RA) + "\nDiff: "
//           + ToHourMinSec(Diff) + "\n\nAge: " + Age + "\nMoonPos2.RA: " + ToHourMinSec(MoonPos2.RA) 
//           + "\nSchritte: " + i);

	return (Math.round(Age*100)/100);
}


function Quad(yMinus,y0,yPlus){
	var Erg = new CQuadData(0,0,0,0,0);
	var a = 0.5*(yPlus + yMinus)- y0;
	var b = 0.5*(yPlus - yMinus);
	var c = y0;
	
	Erg.XE = -b/2/a;
	Erg.YE = (a*Erg.XE + b)*Erg.XE + c;
	var DIS = b*b-4*a*c;
	if (DIS >= 0){
		var DX = 0.5*Math.sqrt(DIS)/Math.abs(a);
		Erg.ZERO1 = Erg.XE-DX;
		Erg.ZERO2 = Erg.XE+DX;
		if (Math.abs(Erg.ZERO1) <= 1) Erg.NZ += 1;
		if (Math.abs(Erg.ZERO2) <= 1) Erg.NZ += 1;
		if (Erg.ZERO1<-1) Erg.ZERO1=Erg.ZERO2;
		}
	return Erg;
}


function SIN_ALT(Obj, JD, Laenge, Sphi, Cphi) {
	var Pos = new CPosition(0,0);

	switch(Obj){
		case SONNE:
			Pos = GetSunPos(JD);
			break;
		case MOND:
			Pos = GetMoonPos(JD);
			break;
		default:
			alert("Falsches Objekt");
			break;
	}
	var MST = Get_MST(JD, Laenge);
	var	Tau = 15*(MST-Pos.RA);
	return Sphi*Math.sin(Pos.DEC*toRad) + Cphi*Math.cos(Pos.DEC*toRad)*Math.cos(Tau*toRad); 
	}




function GetRiseTimes(Object,Datum,Laenge,Breite){
	// Object: 0=Sonne, 1=Mond
	var SPHI = Math.sin(Breite*toRad);
	var CPHI = Math.cos(Breite*toRad);

	var JD0 = Get_JD0(Datum);
	var y0, yPlus, yMinus;
	var Above,Rise, Set;
	var Erg, JD;
	// Korrekturen wegen Refraktion und Objektgrösse
	var Korr;
	switch(Object){
		case SONNE:
			Korr = Math.sin(-50/60*toRad); // Höhe bei -50'
			break;
		case MOND:
			Korr = Math.sin(8/60*toRad); // Höhe bei +8'
			break;
		default:
			Korr = Math.sin(-34/60*toRad); // Höhe bei -34'
			break;
	}

	var h = 1;
	JD = JD0 + (h-1)/24;
	yMinus = SIN_ALT(Object,JD,Laenge,SPHI,CPHI) - Korr;
	Above = (yMinus>0);
	Rise = false;
	Set = false;
	var UTRise, UTSet;
	do {
		JD = JD0 + h/24;
		y0    = SIN_ALT(Object,JD,Laenge,SPHI,CPHI) - Korr;
		JD = JD0 + (h+1)/24;
		yPlus = SIN_ALT(Object,JD,Laenge,SPHI,CPHI) - Korr;
		Erg = Quad(yMinus,y0,yPlus);
		switch (Erg.NZ){
			case 0:
				break;
			case 1:
				if (yMinus<0){
					UTRise = h+Erg.ZERO1;
					Rise = true;
				}
				else{
					UTSet = h+Erg.ZERO1;
					Set = true;
				}
				break;
			case 2:
				if (Erg.YE<0){
					UTRise = h+Erg.ZERO2;
					UTSet  = h+Erg.ZERO1;
				}
				else{
					UTRise = h+Erg.ZERO1;
					UTSet  = h+Erg.ZERO2;
				}
				Set = true;
				Rise = true;
				break;
			}
		yMinus = yPlus;
		h += 2;
		}
		while (h!=25 && !(Rise && Set));

	var Times = new CTimes(-1,-1,0);
	if (Rise || Set){
		if (Rise)Times.UTRise = UTRise;
			else Times.UTRise = -1;
		if (Set) Times.UTSet  = UTSet;
			else Times.UTSet  = -1;
		Times.Sichtbar = 0;
	}
	else{
		if (Above){
			Times.UTRise = -1;
			Times.UTSet  = -1;
			Times.Sichtbar = 1;
		}
		else{
			Times.UTRise = -1;
			Times.UTSet  = -1;
			Times.Sichtbar = -1;
		}
	}
	return Times;
}
