var DToR = Math.PI/180.0;

NEWMOON     =0;
FIRSTQUARTER=1;
FULLMOON    =2;
LASTQUARTER =3;

SinTab = new Array(3);
CosTab = new Array(3);

for(i=0; i<3;i++)
{
  SinTab[i] = new Array(5);
  CosTab[i] = new Array(5); 
}

MoonPhaseData = new Array(5);
for (i=0; i<MoonPhaseData.length; i++)
	MoonPhaseData[i] = new Array(5);

MoonPhaseData[0][0] =2451550.09765; 
MoonPhaseData[0][1] =     29.530588853; 
MoonPhaseData[0][2] =      0.0001337; 
MoonPhaseData[0][3] =      0.000000150; 
MoonPhaseData[0][4] =      0.00000000073;
MoonPhaseData[1][0] =      2.5534 ; 
MoonPhaseData[1][1] =     29.10535669; 
MoonPhaseData[1][2] =     -0.0000218; 
MoonPhaseData[1][3] =     -0.00000011; 
MoonPhaseData[1][4] =      0;
MoonPhaseData[2][0] =    201.5643; 
MoonPhaseData[2][1] =    385.81693528; 
MoonPhaseData[2][2] =      0.0107438; 
MoonPhaseData[2][3] =      0.00001239; 
MoonPhaseData[2][4] =     -0.000000058;
MoonPhaseData[3][0] =    160.7108; 
MoonPhaseData[3][1] =    390.67050274; 
MoonPhaseData[3][2] =     -0.0016341; 
MoonPhaseData[3][3] =     -0.00000227; 
MoonPhaseData[3][4] =      0.000000011;
MoonPhaseData[4][0] =    124.7746; 
MoonPhaseData[4][1] =     -1.56375580; 
MoonPhaseData[4][2] =      0.0020691; 
MoonPhaseData[4][3] =      0.00000215; 
MoonPhaseData[4][4] =      0;



/*****************************************************************************/
/* Name:    modpi2                                                           */
/* Type:    function                                                         */
/* Purpose: reduce an angle to the interval (0, 2pi).                        */
/*****************************************************************************/

function modpi2(x)
{
  var pi2 = 2.0 * Math.PI;
  return (x - Math.floor (x / pi2) * pi2);
}


/*****************************************************************************/
/* Name:    EvalMoonPhaseData                                                */
/* Typ:     Unterstuetzende Funktion                                         */
/* Zweck:   Bewertet die speziellen bei der Berechnung der Mondphase         */
/*      benutzten 'Polynome'                                                 */
/* Argumente:                                                                */
/*   n : Index in MoonPhaseData                                              */
/*   k : Nummer der Lunation (since J2000)                                   */
/*   T : Zahl der Jahrhunderte seit J2000                                    */
/* Ausgabe:                                                                  */
/*   Funktionswert des Polynoms.                                             */
/*****************************************************************************/

function EvalMoonPhaseData(n, k, T)
{
  var Sum=0.0;

  Sum =MoonPhaseData[n][0] + k*MoonPhaseData[n][1];
  Sum+=T*T*(MoonPhaseData[n][2]+T*(MoonPhaseData[n][3]+T*MoonPhaseData[n][4]));
  return Sum;
}


/*****************************************************************************/
/* Name:    CalcSinCosTab                                                    */
/* Typ:     Procedure                                                        */
/* Zweck:   Berechnet eine Tabelle von Sinus und Kosinus Werten.             */
/* Arguments:                                                                */
/*   X : der Basiswinkel                                                     */
/*   Degree : hoechste Koeffizient des Basiswinkels                          */
/*                                                                           */
/* Anmerkung: Degree darf hoechstens 6 sein                                  */
/*****************************************************************************/

function CalcSinCosTab(X, Degree, SinTab, CosTab)
{
  var SinVal, CosVal, i;

  SinVal = Math.sin(X);
  SinTab[1] = SinVal;
  CosVal = Math.cos(X);
  CosTab[1] = CosVal;
  for (i = 2 ; i <= Degree ; i++) 
  {
    SinTab[i] = SinTab[i - 1] * CosVal + CosTab[i - 1]*SinVal;
    CosTab[i] = CosTab[i - 1] * CosVal - SinTab[i - 1]*SinVal;
  }
}


/*****************************************************************************/
/* Name:    NextMoonPhase                                                    */
/* Typ:     Function                                                         */
/* Zweck:   Zeitpunkte der ersfolgender Mondphase.                           */
/* Argumente:                                                                */
/*   JD : Julianischer Tag                                                   */
/*   Event : NEWMOON, FIRSTQUARTER, FULLMOON or LASTQUARTER                  */
/* Ausgabe:                                                                  */
/*   der Julianische Tag, an dem das gesuchte Ereignis stattfindet           */
/*****************************************************************************/

function NextMoonPhase(JD, Event)
{
  var T, k, JDE0;
  var M, Md, F, Om;
  var i, j, l, n, flag, sign;
  var sum, SinVal, CosVal, tmp, A, W;
  
  E = new Array(3);

  SinTab = new Array(3);
  CosTab = new Array(3);
  
  for(i=0; i<SinTab.length; i++)
  {
  	SinTab[i] = new Array(5);
  	CosTab[i] = new Array(5);
  }
  
  MoonPhaseCoeffTab = new Array(25)
  for (i=0; i<MoonPhaseCoeffTab.length; i++)      
  	MoonPhaseCoeffTab[i] = new Array(3);    
      
  MoonPhaseCoeffTab[ 0][0] = -0.40720; 
  MoonPhaseCoeffTab[ 0][1] = -0.40614; 
  MoonPhaseCoeffTab[ 0][2] = -0.62801;
  MoonPhaseCoeffTab[ 1][0] =  0.17241; 
  MoonPhaseCoeffTab[ 1][1] =  0.17302; 
  MoonPhaseCoeffTab[ 1][2] =  0.17172;
  MoonPhaseCoeffTab[ 2][0] =  0.01608; 
  MoonPhaseCoeffTab[ 2][1] =  0.01614; 
  MoonPhaseCoeffTab[ 2][2] =  0.00862;
  MoonPhaseCoeffTab[ 3][0] =  0.01039; 
  MoonPhaseCoeffTab[ 3][1] =  0.01043; 
  MoonPhaseCoeffTab[ 3][2] =  0.00804;
  MoonPhaseCoeffTab[ 4][0] =  0.00739; 
  MoonPhaseCoeffTab[ 4][1] =  0.00734; 
  MoonPhaseCoeffTab[ 4][2] =  0.00454;
  MoonPhaseCoeffTab[ 5][0] = -0.00514; 
  MoonPhaseCoeffTab[ 5][1] = -0.00515; 
  MoonPhaseCoeffTab[ 5][2] = -0.01183;
  MoonPhaseCoeffTab[ 6][0] =  0.00208; 
  MoonPhaseCoeffTab[ 6][1] =  0.00209; 
  MoonPhaseCoeffTab[ 6][2] =  0.00204;
  MoonPhaseCoeffTab[ 7][0] = -0.00111; 
  MoonPhaseCoeffTab[ 7][1] = -0.00111; 
  MoonPhaseCoeffTab[ 7][2] = -0.00180;
  MoonPhaseCoeffTab[ 8][0] = -0.00057; 
  MoonPhaseCoeffTab[ 8][1] = -0.00057; 
  MoonPhaseCoeffTab[ 8][2] = -0.00070;
  MoonPhaseCoeffTab[ 9][0] =  0.00056; 
  MoonPhaseCoeffTab[ 9][1] =  0.00056; 
  MoonPhaseCoeffTab[ 9][2] =  0.00027;
  MoonPhaseCoeffTab[10][0] = -0.00042; 
  MoonPhaseCoeffTab[10][1] =  0.00042; 
  MoonPhaseCoeffTab[10][2] = -0.00040;
  MoonPhaseCoeffTab[11][0] =  0.00042; 
  MoonPhaseCoeffTab[11][1] =  0.00042; 
  MoonPhaseCoeffTab[11][2] =  0.00032;
  MoonPhaseCoeffTab[12][0] =  0.00038; 
  MoonPhaseCoeffTab[12][1] =  0.00038; 
  MoonPhaseCoeffTab[12][2] =  0.00032;
  MoonPhaseCoeffTab[13][0] = -0.00024; 
  MoonPhaseCoeffTab[13][1] = -0.00024; 
  MoonPhaseCoeffTab[13][2] = -0.00034;
  MoonPhaseCoeffTab[14][0] = -0.00007; 
  MoonPhaseCoeffTab[14][1] = -0.00007; 
  MoonPhaseCoeffTab[14][2] = -0.00028;
  MoonPhaseCoeffTab[15][0] =  0.00004; 
  MoonPhaseCoeffTab[15][1] =  0.00004; 
  MoonPhaseCoeffTab[15][2] =  0.00002;
  MoonPhaseCoeffTab[16][0] =  0.00004; 
  MoonPhaseCoeffTab[16][1] =  0.00004; 
  MoonPhaseCoeffTab[16][2] =  0.00003;
  MoonPhaseCoeffTab[17][0] =  0.00003; 
  MoonPhaseCoeffTab[17][1] =  0.00003; 
  MoonPhaseCoeffTab[17][2] =  0.00003;
  MoonPhaseCoeffTab[18][0] =  0.00003; 
  MoonPhaseCoeffTab[18][1] =  0.00003; 
  MoonPhaseCoeffTab[18][2] =  0.00004;
  MoonPhaseCoeffTab[19][0] = -0.00003; 
  MoonPhaseCoeffTab[19][1] = -0.00003; 
  MoonPhaseCoeffTab[19][2] = -0.00004;
  MoonPhaseCoeffTab[20][0] =  0.00003; 
  MoonPhaseCoeffTab[20][1] =  0.00003; 
  MoonPhaseCoeffTab[20][2] =  0.00002;
  MoonPhaseCoeffTab[21][0] = -0.00002; 
  MoonPhaseCoeffTab[21][1] = -0.00002; 
  MoonPhaseCoeffTab[21][2] = -0.00005;
  MoonPhaseCoeffTab[22][0] = -0.00002; 
  MoonPhaseCoeffTab[22][1] = -0.00002; 
  MoonPhaseCoeffTab[22][2] = -0.00002;
  MoonPhaseCoeffTab[23][0] =  0.00002; 
  MoonPhaseCoeffTab[23][1] =  0.00002; 
  MoonPhaseCoeffTab[23][2] =  0      ;
  MoonPhaseCoeffTab[24][0] =  0      ; 
  MoonPhaseCoeffTab[24][1] =  0      ; 
  MoonPhaseCoeffTab[24][2] =  0.00004;
  
  
  MoonPhaseAngleTab = new Array(25)
  for (i=0; i<MoonPhaseAngleTab.length; i++)      
  	MoonPhaseAngleTab[i] = new Array(4);

  MoonPhaseAngleTab[ 0][0] = 0;
  MoonPhaseAngleTab[ 0][1] = 1;
  MoonPhaseAngleTab[ 0][2] = 0;
  MoonPhaseAngleTab[ 0][3] = 0; 
  MoonPhaseAngleTab[ 1][0] = 1;
  MoonPhaseAngleTab[ 1][1] = 0;
  MoonPhaseAngleTab[ 1][2] = 0;
  MoonPhaseAngleTab[ 1][3] = 1;
  MoonPhaseAngleTab[ 2][0] = 0;
  MoonPhaseAngleTab[ 2][1] = 2;
  MoonPhaseAngleTab[ 2][2] = 0;
  MoonPhaseAngleTab[ 2][3] = 0; 
  MoonPhaseAngleTab[ 3][0] = 0;
  MoonPhaseAngleTab[ 3][1] = 0;
  MoonPhaseAngleTab[ 3][2] = 2;
  MoonPhaseAngleTab[ 3][3] = 0;
  MoonPhaseAngleTab[ 4][0] =-1;
  MoonPhaseAngleTab[ 4][1] = 1;
  MoonPhaseAngleTab[ 4][2] = 0;
  MoonPhaseAngleTab[ 4][3] = 1; 
  MoonPhaseAngleTab[ 5][0] = 1;
  MoonPhaseAngleTab[ 5][1] = 1;
  MoonPhaseAngleTab[ 5][2] = 0;
  MoonPhaseAngleTab[ 5][3] = 1; 
  MoonPhaseAngleTab[ 6][0] = 2;
  MoonPhaseAngleTab[ 6][1] = 0;
  MoonPhaseAngleTab[ 6][2] = 0;
  MoonPhaseAngleTab[ 6][3] = 2; 
  MoonPhaseAngleTab[ 7][0] = 0;
  MoonPhaseAngleTab[ 7][1] = 1;
  MoonPhaseAngleTab[ 7][2] =-2;
  MoonPhaseAngleTab[ 7][3] = 0;
  MoonPhaseAngleTab[ 8][0] = 0;
  MoonPhaseAngleTab[ 8][1] = 1;
  MoonPhaseAngleTab[ 8][2] = 2;
  MoonPhaseAngleTab[ 8][3] = 0; 
  MoonPhaseAngleTab[ 9][0] = 1;
  MoonPhaseAngleTab[ 9][1] = 2;
  MoonPhaseAngleTab[ 9][2] = 0;
  MoonPhaseAngleTab[ 9][3] = 1; 
  MoonPhaseAngleTab[10][0] = 0;
  MoonPhaseAngleTab[10][1] = 3;
  MoonPhaseAngleTab[10][2] = 0;
  MoonPhaseAngleTab[10][3] = 0; 
  MoonPhaseAngleTab[11][0] = 1;
  MoonPhaseAngleTab[11][1] = 0;
  MoonPhaseAngleTab[11][2] = 2;
  MoonPhaseAngleTab[11][3] = 1;
  MoonPhaseAngleTab[12][0] = 1;
  MoonPhaseAngleTab[12][1] = 0;
  MoonPhaseAngleTab[12][2] =-2;
  MoonPhaseAngleTab[12][3] = 1; 
  MoonPhaseAngleTab[13][0] =-1;
  MoonPhaseAngleTab[13][1] = 2;
  MoonPhaseAngleTab[13][2] = 0;
  MoonPhaseAngleTab[13][3] = 1; 
  MoonPhaseAngleTab[14][0] = 2;
  MoonPhaseAngleTab[14][1] = 1;
  MoonPhaseAngleTab[14][2] = 0;
  MoonPhaseAngleTab[14][3] = 0; 
  MoonPhaseAngleTab[15][0] = 0;
  MoonPhaseAngleTab[15][1] = 2;
  MoonPhaseAngleTab[15][2] =-2;
  MoonPhaseAngleTab[15][3] = 0;
  MoonPhaseAngleTab[16][0] = 3;
  MoonPhaseAngleTab[16][1] = 0;
  MoonPhaseAngleTab[16][2] = 0;
  MoonPhaseAngleTab[16][3] = 0; 
  MoonPhaseAngleTab[17][0] = 1;
  MoonPhaseAngleTab[17][1] = 1;
  MoonPhaseAngleTab[17][2] =-2;
  MoonPhaseAngleTab[17][3] = 0; 
  MoonPhaseAngleTab[18][0] = 0;
  MoonPhaseAngleTab[18][1] = 2;
  MoonPhaseAngleTab[18][2] = 2;
  MoonPhaseAngleTab[18][3] = 0; 
  MoonPhaseAngleTab[19][0] = 1;
  MoonPhaseAngleTab[19][1] = 1;
  MoonPhaseAngleTab[19][2] = 2;
  MoonPhaseAngleTab[19][3] = 0;
  MoonPhaseAngleTab[20][0] =-1;
  MoonPhaseAngleTab[20][1] = 1;
  MoonPhaseAngleTab[20][2] = 2;
  MoonPhaseAngleTab[20][3] = 1; 
  MoonPhaseAngleTab[21][0] =-1;
  MoonPhaseAngleTab[21][1] = 1;
  MoonPhaseAngleTab[21][2] =-2;
  MoonPhaseAngleTab[21][3] = 0; 
  MoonPhaseAngleTab[22][0] = 1;
  MoonPhaseAngleTab[22][1] = 3;
  MoonPhaseAngleTab[22][2] = 0;
  MoonPhaseAngleTab[22][3] = 0; 
  MoonPhaseAngleTab[23][0] = 0;
  MoonPhaseAngleTab[23][1] = 4;
  MoonPhaseAngleTab[23][2] = 0;
  MoonPhaseAngleTab[23][3] = 0;
  MoonPhaseAngleTab[24][0] =-2;
  MoonPhaseAngleTab[24][1] = 1;
  MoonPhaseAngleTab[24][2] = 0;
  MoonPhaseAngleTab[24][3] = 0;  

  MoonPhaseExtra = new Array(14)                          
  for (i=0; i<MoonPhaseExtra.length; i++)                 
  	MoonPhaseExtra[i] = new Array(3);               
  
  MoonPhaseExtra[ 0][0] =299.77;
  MoonPhaseExtra[ 0][1] =  0.107408;
  MoonPhaseExtra[ 0][2] =  0.000325;
  MoonPhaseExtra[ 1][0] =251.88;
  MoonPhaseExtra[ 1][1] =  0.016321;
  MoonPhaseExtra[ 1][2] =  0.000056;
  MoonPhaseExtra[ 2][0] =251.83;
  MoonPhaseExtra[ 2][1] = 26.651886;
  MoonPhaseExtra[ 2][2] =  0.000165;
  MoonPhaseExtra[ 3][0] =349.42;
  MoonPhaseExtra[ 3][1] = 36.412478;
  MoonPhaseExtra[ 3][2] =  0.000047;
  MoonPhaseExtra[ 4][0] = 84.66;
  MoonPhaseExtra[ 4][1] = 18.206239;
  MoonPhaseExtra[ 4][2] =  0.000164;
  MoonPhaseExtra[ 5][0] =141.74;
  MoonPhaseExtra[ 5][1] = 53.303771;
  MoonPhaseExtra[ 5][2] =  0.000042;
  MoonPhaseExtra[ 6][0] =207.14;
  MoonPhaseExtra[ 6][1] =  2.453732;
  MoonPhaseExtra[ 6][2] =  0.000126;
  MoonPhaseExtra[ 7][0] =154.84;
  MoonPhaseExtra[ 7][1] =  7.306860;
  MoonPhaseExtra[ 7][2] =  0.000040;
  MoonPhaseExtra[ 8][0] = 34.52;
  MoonPhaseExtra[ 8][1] = 27.261239;
  MoonPhaseExtra[ 8][2] =  0.000110;
  MoonPhaseExtra[ 9][0] =207.19;
  MoonPhaseExtra[ 9][1] =  0.121824;
  MoonPhaseExtra[ 9][2] =  0.000037;
  MoonPhaseExtra[10][0] =291.34;
  MoonPhaseExtra[10][1] =  1.844379;
  MoonPhaseExtra[10][2] =  0.000062;
  MoonPhaseExtra[11][0] =161.72;
  MoonPhaseExtra[11][1] = 24.198154;
  MoonPhaseExtra[11][2] =  0.000035;
  MoonPhaseExtra[12][0] =239.56;
  MoonPhaseExtra[12][1] = 25.513099;
  MoonPhaseExtra[12][2] =  0.000060;
  MoonPhaseExtra[13][0] =331.55;
  MoonPhaseExtra[13][1] =  3.592518;
  MoonPhaseExtra[13][2] =  0.000023;

  k = Math.floor ((JD + 1 - MoonPhaseData[0][0]) / MoonPhaseData[0][1]) + 0.25 * Event;

  if (Event == NEWMOON)
  k++;
  T = k / 1236.85;
  JDE0 = EvalMoonPhaseData (0, k, T);
  M    = modpi2 (EvalMoonPhaseData (1, k, T) * DToR);
  Md   = modpi2 (EvalMoonPhaseData (2, k, T) * DToR);
  F    = modpi2 (EvalMoonPhaseData (3, k, T) * DToR);
  Om   = modpi2 (EvalMoonPhaseData (4, k, T) * DToR);


  CalcSinCosTab (M,  3, SinTab[0], CosTab[0]);
  CalcSinCosTab (Md, 4, SinTab[1], CosTab[1]);
  CalcSinCosTab (F,  2, SinTab[2], CosTab[2]);


  JDE0 -= 0.00017 * Math.sin (Om);

  E[1] = 1 - T * (0.002516 + T * 0.0000074);
  E[2] = E[1] * E[1];
  if (Event == NEWMOON)
    l = 0;
  else
    if (Event == FULLMOON)
      l = 1;
    else
      l = 2;
      
  sum = 0.0;
  for (i = 0 ; i < 25 ; i++) 
  {
    flag = 0;
    for (j = 0 ; j < 3 ; j++) 
    {
      n = MoonPhaseAngleTab[i][j];

      if (n)
      {
  	if (n < 0)
        {
          n = -n;
          sign = -1;
        }
        else
          sign = 1;
  	if (!flag)
        {
          flag = 1;

          SinVal = SinTab[j][n] * sign;
          CosVal = CosTab[j][n];
        }
        else
        {
    	  tmp    = CosVal * CosTab[j][n] - SinVal * sign * SinTab[j][n];
          SinVal = SinVal * CosTab[j][n] + CosVal * sign * SinTab[j][n];
          CosVal = tmp;
        }
      }
    }

    n = MoonPhaseAngleTab[i][3];
    if (n)
      SinVal = SinVal * E[n];
      		
    sum += SinVal * MoonPhaseCoeffTab[i][l] ;
  }

  JDE0 += sum;  //sum = ???


  if ((Event == FIRSTQUARTER) || (Event == LASTQUARTER)) 
  {
    W = 0.00306 - 0.00038*E[1]*Math.cos(M) + 0.00026*Math.cos(Md) - 0.00002*Math.cos(Md - M) + 0.00002*Math.cos(Md + M) + 0.00002*Math.cos(2 * F);
    if (Event == FIRSTQUARTER)
      JDE0 += W;
    else
      JDE0 -= W;
  }

  for (i = 0 ; i < 14 ; i++) 
  {
    A = MoonPhaseExtra[i][0] + k * MoonPhaseExtra[i][1];
    if (i == 1)
      A -= 0.009173 * T * T;
    JDE0 += MoonPhaseExtra[i][2] * Math.sin(A * DToR);
  }

  return JDE0;
}

