// astro.hpc -- Some astronomical algorithms -*- C -*-

// Convert an integer to a two-digit string.
// For example:
//	twodigits(3) returns "03"
//	twodigits(12) returns "12"
declare twodigits(x) {
	if (x < 10)
		"0" + \\\-\>STR(x);
	else
		\\\-\>STR(x);
}

// Convert degrees, minutes, seconds to degrees (fractional).
declare dms2d(d, m, s) {
	d + (m + s / 60) / 60;
}

// Convert hours, minutes, seconds to degrees (fractional).
declare hms2d(h, m, s) {
	(h + (m + s / 60) / 60) * 15;
}

// Format degrees to string.
// For example, d2s(10.5) returns "10°30'00""
declare d2s(x) : d(0), m(0), s(0) {
	d = twodigits(IP(x));
	x = 60*FP(x);
	m = twodigits(IP(x));
	x = 60*FP(x);
	s = twodigits(RND(x, 0));

	d + "\\^o" + m + "'" + s + CHR(34);	// Return value
}

// Format hours to string.
// For example, h2s(9.25) returns "09h15m00s"
declare h2s(x) : h(0), m(0), s(0) {
	h = twodigits(IP(x));
	x = 60*FP(x);
	m = twodigits(IP(x));
	x = 60*FP(x);
	s = twodigits(RND(x, 0));

	h + "h" + m + "m" + s + "s";	// Return value
}

// Format degrees to string.
// For example, dms2s(10, 2, 5) returns "10°02'05""
declare dms2s(d, m, s) {
	d2s(dms2d(d, m, s));
}

// Format hours to string.
// For example, hms2s(10, 2, 5) returns "10h02m05s"
declare hms2s(h, m, s) {
	h2s(dms2d(h, m, s));
}

// Calculate the date of Easter Sunday in the Gregorian calendar
// (hence valid from the year 1583 on).
// Algorithm by Spencer Jones, General Astronomy, 1922.
// Returns:
//	1: number of the month (1 = January, 2 = February, ...)
//	2: day of that month upon which Easter Sunday falls
declare easter(year) : a(0), b(0), c(0), d(0), e(0), f(0), g(0), h(0),
    		       j(0), k(0), l(0), m(0), n(0), p(0) {
	a = year % 19;
	b = IP(year / 100);
	c = year % 100;
	d = IP(b / 4);
	e = b % 4;
	f = IP((b + 8) / 25);
	g = IP((b - f + 1) / 3);
	h = (19*a + b - d - g + 15) % 30;
	j = IP(c / 4);
	k = c % 4;
	l = (32 + 2*e + 2*j - h - k) % 7;
	m = IP((a + 11*h + 22*l) / 451);
	n = IP((h + l - 7*m + 114) / 31);
	p = (h + l - 7*m + 114) % 31;
	n;		// Return month
	p + 1;		// Return day
}

// Calculate the date of Easter Sunday in the Julian calendar.
// Returns:
//	1: number of the month (1 = January, 2 = February, ...)
//	2: day of that month upon which Easter Sunday falls
declare jeaster(year) : a(0), b(0), c(0), d(0), e(0), f(0), g(0) {
	a = year % 4;
	b = year % 7;
	c = year % 19;
	d = (19*c + 15) % 30;
	e = (2*a + 4*b - d + 34) % 7;
	f = IP((d + e + 114) / 31);
	g = (d + e + 114) % 31;
	f;		// Return month
	g + 1;		// Return day
}
