/* MoonRise.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Original (C) Mike Henderson <mghenderson@lanl.gov>.
 *
 * I've converted Mike Henderson's original file to glib types, 
 * removed unused variables, and piped the whole thing through indent.
 *
 * (C) 1999-2003 josh buhl <jbuhl@users.sourceforge.net> 
 *
 */

#include "Moon.h"
#include "MoonRise.h"

static gint
Interp(gdouble ym, gdouble y0, gdouble yp, gdouble * xe, gdouble * ye,
       gdouble * z1, gdouble * z2, gint * nz)
{

	gdouble a, b, c, d, dx;

	*nz = 0;
	a = 0.5 * (ym + yp) - y0;
	b = 0.5 * (yp - ym);
	c = y0;
	*xe = -b / (2.0 * a);
	*ye = (a * (*xe) + b) * (*xe) + c;
	d = b * b - 4.0 * a * c;

	if (d >= 0) {
		dx = 0.5 * sqrt(d) / fabs(a);
		*z1 = *xe - dx;
		*z2 = *xe + dx;
		if (fabs(*z1) <= 1.0)
			*nz += 1;
		if (fabs(*z2) <= 1.0)
			*nz += 1;
		if (*z1 < -1.0)
			*z1 = *z2;
	}

	return (0);
}


static gdouble 
SinH(CTrans * c, gdouble UT)
{

	gdouble TU, TU2, TU3, LambdaMoon, BetaMoon, R, AGE, frac(), jd();
	gdouble RA_Moon, DEC_Moon, gmst, lmst, Tau, epsilon, Moon();
	gdouble angle2pi();

	TU = (jd(c->year, c->month, c->day, UT) - 2451545.0) / 36525.0;

	/* this is more accurate, but expensive. */
	TU2 = TU * TU;
	TU3 = TU2 * TU;
	Moon(TU, &LambdaMoon, &BetaMoon, &R, &AGE);
	LambdaMoon *= RadPerDeg;
	BetaMoon *= RadPerDeg;
	epsilon =
	    (23.43929167 - 0.013004166 * TU - 1.6666667e-7 * TU2 -
	     5.0277777778e-7 * TU3) * RadPerDeg;
	RA_Moon =
	    angle2pi(atan2
		     (sin(LambdaMoon) * cos(epsilon) -
		      tan(BetaMoon) * sin(epsilon), cos(LambdaMoon)));
	DEC_Moon =
	    asin(sin(BetaMoon) * cos(epsilon) +
		 cos(BetaMoon) * sin(epsilon) * sin(LambdaMoon));


	/* This is less accurate, but computationally less expensive */
/*      MiniMoon(TU, &RA_Moon, &DEC_Moon); */
/*      RA_Moon *= 15.0*RadPerDeg; */
/*      DEC_Moon *= RadPerDeg; */

	/*
	 *  Compute Greenwich Mean Sidereal Time (gmst)
	 */
	UT = 24.0 * frac(UT / 24.0);
	/* this is for the ephemeris meridian??? 
	   gmst = 6.697374558 + 1.0027379093*UT + (8640184.812866+(0.093104-6.2e-6*TU)*TU)*TU/3600.0;
	 */
	gmst =
	    UT + 6.697374558 + (8640184.812866 +
				(0.093104 -
				 6.2e-6 * TU) * TU) * TU / 3600.0;
	lmst = 24.0 * frac((gmst - c->Glon / 15.0) / 24.0);

	Tau = 15.0 * lmst * RadPerDeg - RA_Moon;

	return (c->SinGlat * sin(DEC_Moon) +
		c->CosGlat * cos(DEC_Moon) * cos(Tau));
}


void MoonRise(CTrans * c, gdouble * UTRise, gdouble * UTSet)
{

	gdouble UT, ym, y0, yp, SinH0;
	gdouble xe, ye, z1, z2;
	gint Rise, Set, nz, TimeZone;

	SinH0 = sin(8.0 / 60.0 * RadPerDeg);

	/* report rise and set times in GMT */
	/*      TimeZone = c->UT - c->LST; */
	TimeZone = 0;

	UT = 1.0 + TimeZone;
	UT = 1.0;
	*UTRise = -999.0;
	*UTSet = -999.0;
	Rise = Set = 0;

	ym = SinH(c, UT - 1.0) - SinH0;

	while ((UT <= 24.0 + TimeZone)) {

		y0 = SinH(c, UT) - SinH0;
		yp = SinH(c, UT + 1.0) - SinH0;

		Interp(ym, y0, yp, &xe, &ye, &z1, &z2, &nz);

		switch (nz) {

		case 0:
			break;
		case 1:
			if (ym < 0.0) {
				*UTRise = UT + z1;
				Rise = 1;
			} else {
				*UTSet = UT + z1;
				Set = 1;
			}
			break;
		case 2:
			if (ye < 0.0) {
				*UTRise = UT + z2;
				*UTSet = UT + z1;
			} else {
				*UTRise = UT + z1;
				*UTSet = UT + z2;
			}
			Rise = 1;
			Set = 1;
			break;
		}
		ym = yp;
		UT += 2.0;

	}

	if (Rise) {
		*UTRise -= TimeZone;
		*UTRise = hour24(*UTRise);
	} else {
		*UTRise = -999.0;
	}

	if (Set) {
		*UTSet -= TimeZone;
		*UTSet = hour24(*UTSet);
	} else {
		*UTSet = -999.0;
	}

}


syntax highlighted by Code2HTML, v. 0.9.1