// Javascript-Routinen zur Kalenderberechnung
// nach Jean Meeus, Astronomical Algorithms, 2nd Edition
// Arndt Brünner, 17.9.2001
// Version: 12.5.2003

helperdate=new Date_(0,0,0,0,0,0,2);
var DMN=new Array("Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember");

function Date_(j,m,t,h,n,s,typ)
{
this.j=j*1;this.m=m*1;this.t=t*1;this.h=h*1;
this.n=n*1;this.s=s*1;
this.typ=typ*1; //0=auto; 1=julianisch, 2=gregorianisch
if(this.typ==0) this.typ=((this.j<1582)||((this.j==1582)&((this.m<10)||((this.m==10)&&(this.t<15))))) ? 1 : 2;
this.jd=new Function("","return GetJulianDay(this);");
this.SetTyp=new Function("t","this.typ=t;GetDateFromJD(this.jd,this);");
this.SetToOstern=new Function("","Ostern(this.j,this);");
this.DayOfYear=new Function("","return GetDayOfYear(this);");
this.Weekday=new Function("","return GetWeekday(this);");
this.dateStr=new Function("","return this.t+'. '+DMN[this.m-1]+' '+this.j;");
this.dateStr_=new Function("","return this.t+'. '+this.m+'. '+this.j;");
this.timeStr=new Function("","return this.h+':'+this.n+':'+this.s;");
return this;
}

function GetHMS(d,date)
{
	d-=Math.floor(d);
	date.s = d * 86400.0;
	date.h = Math.floor(date.s / 3600 );
	date.n = Math.floor(date.s / 60 + 0.0001)-date.h*60;
	date.s -= date.n * 60.0 + date.h * 3600.0;
}

function GetDateFromJD(jd,date)
{
	jd+=0.5;
	var z=Math.floor(jd);
	var f=jd-z;
	var a=0.0;
	if (date.typ==1)
		a= z; 
	else if ((z>=2299161.0)&&(date.typ==2))
	{
		var aa=Math.floor((z-1867216.25)/36524.25);
		a=z+1.0+aa-Math.floor(aa/4.0);
	}
	else 
	{
		date.j=0;date.m=0;date.t=0;date.h=-1;date.min=-1;date.s=-1.0;
		return;
	}
	var b=a+1524.0;
	var c=Math.floor((b-122.1)/365.25);
	var d=Math.floor(365.25*c);
	var e=Math.floor((b-d)/30.6001);
	if(e<14)date.m=e-1; else date.m=e-13;
	if(date.m>2)date.j=c-4716; else date.j=(c-4715);
	var tt=b-d-Math.floor(30.6001*e)+f;
	date.t=Math.floor(tt);
	GetHMS(tt,date);
}

function GetDayFrac(date)
{
	return (date.t+date.h/24.0+date.n/1440.0+date.s/86400.0);
}

function GetJulianDay(date)
{
	var tt=GetDayFrac(date);
	with(date)
	{
	if (m<3){j--;m+=12;}
	var b=0;
	if (typ==2)
	{
		if((j<1582)||((j==1582)&&(m<10))||((j==1582)&&(m==10)&&(t<15))) return 0.0;
		var a=Math.floor(j/100);if(a<0)a++;
		b=2-a+Math.floor(a/4);
	}
	//var jd=Math.floor(365.25*(j+4716.0))+Math.floor(30.6001*(m+1))+tt+b-1524.5;
	var jd=Math.floor(365.25*j)+Math.floor(30.6001*(m+1))+tt+b+1720994.5;
	if (m>12){j++;m-=12;}
	return jd;
	}
}

function GregorToJulian(date)
{
	with(date)
	{
	//if(typ!=2) return;
	jd=GetJulianDay(date);
	if(jd==0.0)
	{
		j=0;m=0;t=0;h=-1;n=-1;s=-1.0;
		return;
	}
	date.typ=1;
	GetDateFromJD(jd,date);
	}
}
function JulianToGregor(date)
{
//	if (date.typ !=2) return;
	jd=GetJulianDay(date);
	date.typ=2;
	GetDateFromJD(jd,date);
}

function Ostern(J,date)
{
	var a,b,c,d,e,f,g,h,i,k,l,m,n,p;
	if (date.typ==1)
		// Julianischer Kalender
	{
		a=J%4;
		b=J%7;
		c=J%19;
		d=(19*c+15)%30;
		e=(a+a+b+b+b+b-d+34)%7;
		ff=d+e+114;
		g=ff%31;
		f=(ff-g)/31;
		date.j=J;
		date.m=f; date.t=g+1;
	}
	else if ((date.typ==2)&&(J>1582))
		// Gregorianischer Kalender
	{
		a=J%19;
		b=Math.floor(J/100);
		c=J%100;
		d=Math.floor(b/4);
		e=b%4;
		f=Math.floor((b+8)/25);
		g=Math.floor((b-f+1)/3);
		h=(19*a+b-d-g+15)%30;
		i=Math.floor(c/4);
		k=c-i*4;
		l=(32+e+e+i+i-h-k)%7;
		m=Math.floor((a+11*h+22*l)/451);
		nn=(h+l-7*m+114);
		n=Math.floor(nn/31);
		p=nn%31;
		date.j=J;
		date.m=n; date.t=p+1;
	}
	else
	{
		date.m=0;date.t=0;
	}
}

function test()
{
	var t="";
	for(var i=1583;i<3001;i++){Ostern(i,helperdate);t+=GetWeekday(helperdate);}
	alert(t);
}

function GetWeekday(date)
{
	with(date){
	if((typ==2)&&(((j<1582)||((j==1582)&&(m<10))||((j==1582)&&(m=10)&&(t<15)))))
		return -1;
	}
/*	if(date.typ==1)
	{
		var d=new Date_(date.j,date.m,date.t,date.h,date.n,date.s,1);
		JulianToGregor(d);
		return (new Date(d.j,d.m-1,d.t,0,0,0)).getDay();
	}
	return (new Date(date.j,date.m-1,date.t,0,0,0)).getDay();*/
	return (Math.floor(GetJulianDay(date)+1.5)) % 7 ;
}

function IsSchaltjahr(j,typ)
{
	switch(typ)
	{
	case 1:
		if(j%4==0) return -1;
		return 0;
	case 2:
		if(j%400==0) return -1;
		if(j%100==0) return 0;
		if(j%4==0) return -1;
		return 0;
	default:
		return 0;
	}
}
	
function GetDayOfYear(date)
{
	var k=2+IsSchaltjahr(date.j,date.typ);
	return Math.floor(275*date.m/9) - k*Math.floor((date.m+9)/12)+date.t-30;
}

function GetDateFromDayOfYear(n,date)
{ 
	//var k=2+IsSchaltjahr(date.j,date.typ);
	//date.m = (n<32) ? 1 : (9.0*(k+n)/275.0+0.98);
	date.m=1;date.t=1;date.h=12;date.n=0;date.s=0;
	var jd=GetJulianDay(date)+n-1;
	GetDateFromJD(jd,date);
}

function setDateByString(date,t)
{
	var x=t.replace(/ /g,"").split(".");
	if(x.length!=3){return (1==0);}
	date.t=Number(x[0]);date.m=Number(x[1]);date.j=Number(x[2]);
	return (1==1);
}

function parseDate(t,d)
{
	t=t.replace(/\./g,". ").replace(/ +/g," ");
	while(t.charAt(0)==" ")t=t.substr(1,t.length);
	while(t.charAt(t.length-1)==" ")t=t.substr(0,t.length-1);
	var x=t.split(" "); if(x.length!=3)return false;
	var i=0;
	for(i=0;i<12;i++)if(x[1].toLowerCase()==DMN[i].toLowerCase()){x[1]=i+1;break;}
	if((i==12)&&(!isNaN(x[1])==0))return false;	
	d.t=Number(x[0]);d.m=Number(x[1]);d.j=Number(x[2]);	
	return true;
}

function getDateStrFromJD(jd,typ)
{
	helperdate.typ=typ;
	GetDateFromJD(jd,helperdate);
	return helperdate.dateStr();
}

function GetMondphasenDatumJD(ph,b,jd,genau)
{
	GetDateFromJD(jd,helperdate);
//	alert(helperdate.t+"."+helperdate.m+"."+helperdate.j);
	GetMondphasenDatum(ph,b,helperdate,genau);
	return GetJulianDay(helperdate);
}

function GetMondphasenDatum(ph,b,date,genau)
{
	gdf=GetDayFrac(date);
	gdf-=Math.floor(gdf);
	var jj=date.j + (GetDayOfYear(date)+gdf-1)/(365-IsSchaltjahr(date.j,date.typ));
	var k=(jj-2000.01643835616)*12.3685-ph/4.0;
	k=Math.floor(k+(b*1.0+1.0)/2.0)+ph/4.0;
	var t=k/1236.85;
	var t2=t*t,t3=t2*t,t4=t3*t;
	var e,m,mm,f,o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,w;
	var jde=2451550.09766+29.530588861*k+0.00015437*t2-0.00000015*t3+0.00000000073*t4;
	if (genau!=0)
	{
		e=1-t*(0.002516-0.0000074*t);
		m=2.5534+29.10535670*k-0.0000014*t2-0.00000011*t3;
		mm=201.5643+385.81693528*k+0.0107582*t2+0.00001238*t3-0.000000058*t4;
		f=160.7108+390.67050284*k-0.0016118*t2-0.00000227*t3+0.000000011*t4;
		o=124.7746-1.56375588*k+0.0020672*t2+0.00000215*t3;
		m=normWinkel(m);mm=normWinkel(mm);f=normWinkel(f);o=normWinkel(o);
		a1=299.77+0.107408*k-0.009173*t2;
		a2=251.88+0.016321*k;
		a3=251.83+26.651886*k;
		a4=349.42+36.412478*k;
		a5=84.66+18.206239*k;
		a6=141.74+53.303771*k;
		a7=207.14+2.453732*k;
		a8=154.84+7.306860*k;
		a9=34.52+27.261239*k;
		a10=207.19+0.121824*k;
		a11=291.34+1.844379*k;
		a12=161.72+24.198154*k;
		a13=239.56+25.513099*k;
		a14=331.55+3.592518*k;
		w=0.0;
		if (ph%2==1) w=0.00306-0.00038*e*Math.cos(m)+0.00026*Math.cos(mm)-0.00002*Math.cos(mm-m)+0.00002*Math.cos(mm+m)+0.00002*Math.cos(f+f);
		switch (ph)
		{
		case 0:jde+=mooncorr1(-0.4072 ,0.17241,0.01608,0.01039,0.00739,-0.00514,0.00208,-0.00111,-0.00057,0.00056,-0.00042,0.00042,0.00038,-0.00024,-0.00017,-0.00007,0.00004,0.00004,0.00003,0.00003,-0.00003,0.00003,-0.00002,-0.00002,0.00002,m,mm,f,o,e);break;
		case 1:jde+=mooncorr2(-0.62801,0.17172,-0.01183,0.00862,0.00804,0.00454,0.00204,-0.0018,-0.0007,-0.0004,-0.00034,0.00032,0.00032,-0.00028,0.00027,-0.00017,-0.00005,0.00004,-0.00004,0.00004,0.00003,0.00003,0.00002,0.00002,-0.00002,m,mm,f,o,e)+w; break;
		case 2:jde+=mooncorr1(-0.40614,0.17302,0.01614,0.01043,0.00734,-0.00515,0.00209,-0.00111,-0.00057,0.00056,-0.00042,0.00042,0.00038,-0.00024,-0.00017,-0.00007,0.00004,0.00004,0.00003,0.00003,-0.00003,0.00003,-0.00002,-0.00002,0.00002,m,mm,f,o,e);break;
		case 3:jde+=mooncorr2(-0.62801,0.17172,-0.01183,0.00862,0.00804,0.00454,0.00204,-0.0018,-0.0007,-0.0004,-0.00034,0.00032,0.00032,-0.00028,0.00027,-0.00017,-0.00005,0.00004,-0.00004,0.00004,0.00003,0.00003,0.00002,0.00002,-0.00002,m,mm,f,o,e)-w; break;
		default: return;
		}
		jde+=0.000325 *Math.sin(a1)+0.000165 *Math.sin(a2)+0.000164 *Math.sin(a3)+0.000126 *Math.sin(a4)+0.000110 *Math.sin(a5);
		jde+=0.000062 *Math.sin(a6)+0.000060 *Math.sin(a7)+0.000056 *Math.sin(a8)+0.000046 *Math.sin(a9)+0.000042 *Math.sin(a10);
		jde+=0.000040 *Math.sin(a11)+0.000037 *Math.sin(a12)+0.000035 *Math.sin(a13)+0.000023 *Math.sin(a14);
	}
	GetDateFromJD(jde,date);
}

function GetMondphase(d)
{
	var jd=GetJulianDay(d),j0=jd-50,j1=j0,i=0;
	j1=j0=GetMondphasenDatumJD(i,1,j0,1);
	while(j1<=jd){i=(i+1)%4;j0=j1;j1=GetMondphasenDatumJD(i,1,j0);}
	var q=((jd-j0)/(j1-j0)+((i+3)%4));
	return q;
}

function mooncorr1(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,mm,mmm,ff,oo,ee)
{
var z= a*Math.sin(mmm);
z+=	b*ee*Math.sin(mm);
z+=	c*Math.sin(mmm+mmm);
z+=	d*Math.sin(ff+ff);
z+=	e*ee*Math.sin(mmm-mm);
z+=	f*ee*Math.sin(mmm+mm);
z+=	g*ee*ee*Math.sin(mm+mm);
z+=	h*Math.sin(mmm-ff-ff);
z+=	i*Math.sin(mmm+ff+ff);
z+=	j*ee*Math.sin(mmm+mmm+mm);
z+=	k*Math.sin(mmm+mmm+mmm);
z+=	l*ee*Math.sin(mm+ff+ff);
z+=	m*ee*Math.sin(mm-ff-ff);
z+=	n*ee*Math.sin(mmm+mmm-mm);
z+=	o*Math.sin(oo);
z+=	p*Math.sin(mmm+mm+mm);
z+=	q*Math.sin(mmm+mmm-ff-ff);
z+=	r*Math.sin(mm+mm+mm);
z+=	s*Math.sin(mmm+mm-ff-ff);
z+=	t*Math.sin(mmm+mmm+ff+ff);
z+=	u*Math.sin(mmm+mm+ff+ff);
z+=	v*Math.sin(mmm-mm+ff+ff);
z+=	w*Math.sin(mmm-mm-ff-ff);
z+=	x*Math.sin(mmm+mmm+mmm+mm);
z+=	y*Math.sin(mmm+mmm+mmm+mmm);
return z;
}

function mooncorr2(a , b, c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,mm,mmm,ff,oo,ee)
{
var z=a*Math.sin(mmm)+b*ee*Math.sin(mm)+c*ee*Math.sin(mmm+mm)+d*Math.sin(mmm+mmm);
z+=e*Math.sin(ff+ff)+f*ee*Math.sin(mmm-mm)+g*ee*ee*Math.sin(mm+mm);
z+=h*Math.sin(mmm-ff-ff)+i*Math.sin(mmm+ff+ff)+j*Math.sin(mmm+mmm+mmm);
z+=k*ee*Math.sin(mmm+mmm-mm)+l*ee*Math.sin(mm+ff+ff)+m*ee*Math.sin(mm-ff-ff);
z+=n*ee*ee*Math.sin(mmm+mm+mm)+o*ee*Math.sin(mmm+mmm+mm)+p*Math.sin(oo);
z+=q*Math.sin(mmm-mm-ff-ff)+r*Math.sin(mmm+ff)+s*Math.sin(mmm+mm+ff+ff);
z+=t*Math.sin(mmm-mm-mm)+u*Math.sin(mmm+mm-ff-ff)+v*Math.sin(mm+mm+mm);
z+=w*Math.sin(mmm+mmm-ff-ff)+x*Math.sin(mmm-mm+ff+ff)+y*Math.sin(mmm+mmm+mmm+mm);
return z;
}

function normWinkel(w)
{
	if(w<0)
	{
		while(w<=-360.0) w+=360;
	}
	{
		while(w>=360.0)w-=360;
	}
	return w*Math.PI/180.0;
}
