<!-- Hide from non-JavaScript browsers

// Javascript code for the Hitchhiker's Guide to the Moon,
// http://www.shallowsky.com/moon
// Copyright 1998-2003,2006 by Akkana Peck.
// You are welcome to use any portion of this code
// under the terms of the GNU General Public License (GPL).

function charSub(oldstr, oldchar, newchar)
{
    var str = new String(oldstr);
    // Replace all the '+'s with spaces:
    var idx = str.indexOf(oldchar);
    if (idx == -1)
	return str;
    var newdatestr = str.substring(0, idx);
    while (1) {
	var oldidx = idx;
	idx = str.indexOf(oldchar, idx+1);
	if (idx == -1)
	    return newdatestr + newchar + str.substring(oldidx+1);
	newdatestr = newdatestr + newchar + str.substring(oldidx+1, idx);
    }
    return 0;	// should never get here
}

function readUserDate()
{
    var datestr = new String(document.location);
    var idx = datestr.indexOf("?");
    if (idx == -1)
	return "";
    idx = datestr.indexOf("date=", idx);
    if (idx == -1)
	return "";
    var idx2 = datestr.indexOf("&");
    if (idx2 != -1)
        datestr = datestr.substr(idx + 5, idx2);
    else
        datestr = datestr.substr(idx + 5);

    return charSub(datestr, "+", " ");
}

// Global variable: curdate. 
// Read from document.location or set to current date.
var newdate = readUserDate();
var curdate;
if (newdate != "")
    curdate = new Date(newdate);
else
    curdate = new Date();

// Last chart in each line:
var chartLines = new Array(7, 16, 27, 38, 49, 60, 69, 76);

// and information about how many spaces to leave blank on each line:
var blanks = new Array(2, 1, 0, 0, 0, 0, 1, 2);

// eastern longitude limits of each chart:
var ll = new Array (-90, -50, -30, -10, 30, 70, 80, 90,
                    -50, -40, -20, -10, 0, 20, 40, 70, 90,
                    -60, -50, -30, -20, -10, 0, 10, 30, 40, 70, 90,
                    -60, -40, -30, -20, -10, 0, 10, 20, 40, 50, 90,
                    -60, -40, -30, -20, -10, 0, 10, 20, 40, 50, 90,
                    -60, -50, -30, -20, -10, 0, 10, 30, 40, 70, 90,
                    -50, -40, -20, -10, 0, 20, 40, 70, 90,
                    -50, -30, -10, 30, 70, 80, 90);

function getLunotineSize(chartno)
{
    var width=24;
    var height=28;

    if (typeof(chartno) == "number") {
        var modulo;
        if (chartno < 8)
            modulo = chartno + 2;
        else if (chartno < 17)
            modulo = chartno - 7;
        else if (chartno > 69)
            modulo = chartno - 68;
        else if (chartno > 60)
            modulo = chartno - 60;
        else
            modulo = (chartno - 17) % 11;
        if (modulo < 3) width = 24;
        else if (modulo < 5) width = 21;
        else if (modulo < 7) width = 21;
        else if (modulo < 10) width = 17;
        else width = 16;
    }
    else if (chartno == "I" || chartno == "VIII"
             || chartno == "VII" || chartno == "VI")
        width = 24;
    else if (chartno == "II" || chartno == "V")
        width = 17;
    else width = 16;

    return "width=" + width + " height=" + height;
}

function showNum(chartno)
{
    window.status = "Chart #" + chartno;
}

function hideNum(chartno)
{
    //window.status = location.search;
    window.status = "Out " + chartno;
}

function printchart(chartno, colorstring, moonEphem)
{
    if (colorstring == "")
        colorstring = "light";
    var extension;
    if (typeof(chartno) == "number")
        extension = ".jpg";
    else
        extension = ".gif";

    document.write("<td>");
    // Eventually we might want to do some mouseover effects:
    //document.write("<td name=\"cell" + chartno);
    //document.write(" onMouseOver=\"showNum('" + chartno
    //                + "')\" onMouseOut=\"hideNum('" + chartno + "')
    //document.write(\">");

    if (typeof(chartno) == "number" && chartno < 10)
        document.write("<a href=\"rukl0");
    else
        document.write("<a href=\"rukl");

    document.write(chartno + ".html\" target=\"_top\"" );
    //document.write(" onMouseOver=\"showNum(111)\");
    document.write(">" );

    document.write("<img alt=\"" + chartno + "\" src=\"lunotine/"
                   + colorstring + "/lunotine-"
    		   + chartno + extension + "\" border=1 "
		   + getLunotineSize(chartno)
		   + ">");

    document.write("</a>\n</td>\n");
}

function isLit(chart, moonEphem)
{
    if (typeof (chart) != "number")
	return false;

    var eastof = (ll[chart] >= moonEphem.terminator);
    if (moonEphem.phaseAngle >= 0 && moonEphem.phaseAngle <= 180)
        return eastof;
    else
        return !eastof;
}

function findLib(chart, moonEphem)
{
    switch(chart) {
      case "I":
        return libColor(moonEphem.libNorth, -moonEphem.libEast);
      case "II":
        return libColor(moonEphem.libNorth, moonEphem.libEast);
      case "III":
        return libColor(moonEphem.libEast, moonEphem.libNorth);
      case "IV":
        return libColor(moonEphem.libEast, -moonEphem.libNorth);
      case "V":
        return libColor(-moonEphem.libNorth, -moonEphem.libEast);
      case "VI":
        return libColor(-moonEphem.libNorth, moonEphem.libEast);
      case "VII":
        return libColor(-moonEphem.libEast, -moonEphem.libNorth);
      case "VIII":
        return libColor(-moonEphem.libEast, moonEphem.libNorth);
    }
    // Shouldn't ever get here, but just in case:
    return "dark";
}

function libColor(majorlib, minorlib)
{
    var lib = 3*majorlib + minorlib;
    //document.write(" " + lib + ": ");
    if (lib > 17)
	return "biglib";
    else if (lib > 5.5)
	return "lib";
    else
	return "dark";
}

// Update the existing static moon table
// with the appropriate colors
function updateMoonTbl(date)
{
    var moonEphem = new MoonEphem(date);
    var terminator = moonEphem.terminator;

    // Update the text description:
    printWhatsUp(date, moonEphem);

    // First, get the moon table:
    var moontbl = document.getElementById("MoonTable")
    if (!moontbl) return;

    var cells = moontbl.getElementsByTagName("td");
    for (var i=0; i<cells.length; ++i)
    {
        var atags = cells[i].getElementsByTagName("a");
        if (atags.length == 0) continue;
        var href = atags[0].getAttribute("href");
	var ruklindex = href.indexOf("rukl");
	if (ruklindex < 0) ruklindex = 0;
        var imgtags = atags[0].getElementsByTagName("img");
        if (imgtags.length == 0) continue;
        var chartno = parseInt(href.substring(ruklindex+4), 10);
	if (i == 0) alert("About to check for NaN");
        if (isNaN(chartno)) {   // It's a libration chart
	    //alert("It's a libration chart");
            chartno = href.substring(ruklindex+4);
            var dot = chartno.indexOf(".");
            chartno = chartno.substring(0, dot);
            var libcolor = findLib(chartno, moonEphem);
            imgtags[0].setAttribute("src", "lunotine/" + libcolor + "/lunotine-" + chartno + ".gif");
        }
        else if (isLit(chartno, moonEphem))
            imgtags[0].setAttribute("src", "lunotine/light/lunotine-" + chartno + ".jpg");
        else
            imgtags[0].setAttribute("src", "lunotine/dark/lunotine-" + chartno + ".jpg");
    }
}

function textFieldKeyPress(e)
{
  // IE doesn't see the event argument passed in, so get it this way:
  if (window.event) e = window.event;
  var key=e.keyCode || e.which;
  if (key==13) setDate();
}

var DEG2RAD = Math.PI / 180;
var TwoPi = Math.PI * 2;

// convert degrees to a valid angle in radians:
function angle(deg)
{
    while (deg >= 360.)
        deg -= 360.;
    while (deg < 0.)
        deg += 360.;
    return deg * DEG2RAD;
}

function modrad(rad)
{
    while (rad > TwoPi)
        rad -= TwoPi;
    while (rad < 0)
        rad += TwoPi;
    return rad;
}

function decimalYears(date)
{
    return date.getTime() / 365.242191 / (24*60*60*1000);
}

// Get the current colongitude, librations and other data:
function MoonEphem(date)
{
    // Time measured in Julian centuries from epoch J2000.0:
    // This used to be 10:35 (why?) but it gives better numbers
    // with this value.
    // I really need to figure out where I got that date ...
    //var Tepoch = new Date("2000 January 1 22:35 GMT");
    // Used to specify the date like this:
    //var Tepoch = new Date("2000 January 1 10:35 GMT");
    // but iCab can't handle it (though every other browser can)
    // so for iCab we specify it like this:
    var Tepoch = new Date("January 1, 2000 10:35 GMT");

    var T = (decimalYears(date) - decimalYears(Tepoch)) / 100.;
//    document.writeln("Tepoch1: " + Tepoch1.getTime() + ", Tepoch: "
//		     + Tepoch.getTime() + "\n");
//    document.writeln("seconds different: "
//		     + ((date.getTime() - Tepoch.getTime())/1000) + "\n");
    var T2 = T*T;
    var T3 = T2*T;
    var T4 = T3*T;

    // Mean elongation of the moon:
    var D = angle
	( 297.8502042
	 + 445267.1115168 * T
	 - 0.0016300 * T2
	 + T3 / 545868
	 + T4 / 113065000 );
    // Sun's mean anomaly:
    var M = angle
	( 357.5291092
	 + 35999.0502909 * T
	 - 0.0001536 * T2
	 + T3 / 24490000 );
    // Moon's mean anomaly:
    var Mprime = angle
	( 134.9634114
	 + 477198.8676313 * T
	 + 0.0089970 * T2
	 - T3 / 3536000
	 + T4 / 14712000 );

    this.phaseAngle = ( 180 - (D/DEG2RAD)
		    - 6.289 * Math.sin(Mprime)
		    + 2.100 * Math.sin(M)
		    - 1.274 * Math.sin(2*D - Mprime)
		    - 0.658 * Math.sin(2*D)
		    - 0.214 * Math.sin(2*Mprime)
		    - 0.110 * Math.sin(D) );

    // Get the selenographic longitude of the terminator
    // if phase is between 0 and 180,
    // it's waxing and we want the sunrise terminator:
    if (this.phaseAngle >= 0 && this.phaseAngle <= 180)
	this.terminator = this.phaseAngle - 90;
    else if (this.phaseAngle > 180)
	this.terminator = this.phaseAngle - 270;
    else
	this.terminator = this.phaseAngle + 90;

    // Done getting the phase angle; now calculate the position
    // and librations:

    // Moon's mean longitude:
    var Lprime = angle(218.3164591 + 481267.88134236 * T
                       - .0013268 * T2 + T3 / 538841 - T4 / 65194000);

    // Moon's argument of latitude (mean distance from ascending node):
    var F = angle(93.2720993 + 483202.0175273 * T
                  - .0034029 * T2 - T3 / 3526000 + T4 / 863310000);

    // Now, the fearsome neverending tables!
    var DcA = new Array(0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0,
                    4, 0, 4, 2, 2, 1, 1, 2, 2, 4, 2, 0, 2, 2, 1, 2,
                    0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0,
                    4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, 2);
    var McA = new Array(0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0,
                    0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, -2,
                    1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0,
                    0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0, 0);
    var MpcA = new Array(1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1,
                     1, -1, 3, -2, -1, 0, -1, 0, 1, 2, 0, -3, -2,
                     -1, -2, 1, 0,
                     2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0,
                     1, 4, 0, -2, 0, 2, 1, -2, -3, 2, 1, -1, 3, -1);
    var FcA = new Array(0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
                    0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0,
                    0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2);
    var ScA = new Array(6288774, 1274027, 658314, 213618, -185116, -114332,
                    58793, 57066, 53322, 45758, -40923, -34720, -30383,
                    15327, -12528, 10980, 10675, 10034, 8548, -7888,
                    -6766, -5163, 4987, 4036, 3994, 3861, 3665, -2689,
                    -2602, 2390, -2348, 2236,
                    -2120, -2069, 2048, -1773, -1595, 1215, -1110, -892,
                    -810, 759, -713, -700, 691, 596, 549, 537, 520,
                    -487, -399, -381, 351, -340, 330, 327, -323, 299, 294);

    var DcB = new Array(0, 0, 0, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0,
                    4, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 4,
                    0, 4, 2, 2, 2, 2, 0, 2, 2, 2, 2, 4, 2, 2, 0, 2, 1, 1,
                    0, 2, 1, 2, 0, 4, 4, 1, 4, 1, 4, 2);
    var McB = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, -1, -1, -1,
                    1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0,
                    0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 1, 0, -1, -2, 0, 1, 1,
                    1, 1, 1, 0, -1, 1, 0, -1, 0, 0, 0, -1, -2);
    var MpcB = new Array(0, 1, 1, 0, -1, -1, 0, 2, 1, 2, 0, -2, 1, 0, -1, 0,
                     -1, -1, -1, 0, 0, -1, 0, 1, 1, 0, 0, 3, 0, -1,
                     1, -2, 0, 2, 1, -2, 3, 2, -3, -1, 0, 0, 1, 0, 1, 1, 0,
                     0, -2, -1, 1, -2, 2, -2, -1, 1, 1, -1, 0, 0);
    var FcB = new Array(1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1,
                    1, -1, -1, -1, 1, 3, 1, 1, 1, -1, -1, -1, 1, -1, 1,
                    -3, 1, -3, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 3, -1,
                    -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1);
    var ScB = new Array(5128122, 280602, 277693, 173237, 55413, 46271, 32573,
                    17198, 9266, 8822, 8216, 4324, 4200, -3359, 2463, 2211,
                    2065, -1870, 1828, -1794, -1749, -1565, -1492, -1475,
                    -1410, -1344, -1335, 1107, 1021, 833,
                    777, 671, 607, 596, 491, -451, 439, 422, 421, -366,
                    -351, 331, 315, 302, -283, -229, 223, 223, -220, -220,
                    -185, 181, -177, 176, 166, -164, 132, -119, 115, 107);

    // term involving the decreasing eccentricity of the earth's orbit:
    var E = 1 - .002516 * T - .0000074 * T2;
    var E2 = E*E;

    var sigma_l = 0.;
    var sigma_b = 0.;
    var ME;
    var i;
    for (i=0; i < ScA.length; ++i)
    {
        ME = 1;
        if (MpcA[i] == 1 || MpcA[i] == -1)
            ME = E;
        else if (MpcA[i] == 2 || MpcA[i] == -2)
            ME = E2;
        sigma_l += ScA[i] *
            Math.sin(DcA[i] * D + McA[i] * ME * M + MpcA[i] * Mprime
                     + FcA[i] * F);
    }
    for (i=0; i < ScB.length; ++i)
    {
        ME = 1;
        if (MpcB[i] == 1 || MpcB[i] == -1)
            ME = E;
        else if (MpcB[i] == 2 || MpcB[i] == -2)
            ME = E2;
        sigma_b += ScB[i] *
            Math.sin(DcB[i] * D + McB[i] * ME * M + MpcB[i] * Mprime
                     + FcB[i] * F);
    }

    // Three intermediate arguments, in radians:
    var A1 = angle(119.75 + 131.849*T);        // effect of Venus
    var A2 = angle(53.09 + 479264.29*T);       // effect of Jupiter
    var A3 = angle(313.45 + 481266*T);         // ??

    sigma_l += 3958 * Math.sin(A1) + 1962 * Math.sin(Lprime - F)
        + 318 * Math.sin(A2);
    sigma_b += 382 * Math.sin(A3) - 2235 * Math.sin(Lprime)
        + 175 * Math.sin(A1 - F) + 175 * Math.sin(A1 + F)
        + 127 * Math.sin(Lprime-Mprime) - 115 * Math.sin(Lprime+Mprime);
    // Note: sigmas are still in DEGREES (actually millions of degrees)

    // Finally, we can calculate the coordinates of the moon (in radians):
    this.lambda = modrad(Lprime + angle(sigma_l / 1000000));
    this.beta = angle(sigma_b / 1000000);
    // don't calculate delta, 'cause I didn't type in the coefficients

    var I = angle(1.5424167);      // inclination of lunar equator

    // calculate mean long. of ascending node of lunar orbit:
    var omega = angle(125.044555 - 1934.1361849 * T + .0020762 * T2
                      + T3 / 467410 - T4 / 60616000);

    // Fudge: don't count nutation in longitude for now:
    var delpsi = 0.;

    var W = modrad(this.lambda - delpsi - omega);
    var A = modrad(Math.atan2( (Math.sin(W)*Math.cos(this.beta)*Math.cos(I)
                                - Math.sin(this.beta)*Math.sin(I)),
                               (Math.cos(W) * Math.cos(this.beta))));

    // Calculate optical librations (also in radians) then convert to degrees:
    // libL is longitude (east), libB is latitude (north)
    this.libEast = (A - F)/DEG2RAD;
    if (this.libEast > 180) this.libEast -= 360;

    this.libNorth = Math.asin(-Math.sin(W) * Math.cos(this.beta)
				   * Math.sin(I)
                              - Math.sin(this.beta) * Math.cos(I));
    this.libNorth /= DEG2RAD;

    // skip the physical librations for now,
    // 'cause I don't want to type in another long table ...

    // Add the libration to the terminator position:
    this.terminator += this.libEast;
}

// Display an angle: convert to degrees and truncate significant digits
function deangle(num)
{
    return (Math.round(num / DEG2RAD * 100)) / 100.;
}

function roundit(num, precision)
{
    var pow10;
    if (precision == 1)
        pow10 = 10;
    else
        pow10 = 100;
    return Math.abs(Math.floor(num * pow10 + .5) / pow10);
}

function setDate()
{
    updateMoonTbl(new Date(document.getElementById("thedate").value));
}

function addDay()
{
    var d = new Date(document.getElementById("thedate").value);
    d.setDate(d.getDate() + 1);
    updateMoonTbl(d);
}

function printWhatsUp(date, moonEphem)
{
    // Observer's Handbook
    // December 15 has libration longitude +6 == east limb exposed
    // December 27 has lat=-7 == south limb exposed, long=-5 == west limb

    var thedate = document.getElementById("thedate");
    if (thedate)
        thedate.value = date;
    else alert("No thedate");

    var moondesc = document.getElementById("moondesc");
    if (moondesc) {
        var direc, whichterm, waxwane;
        if (moonEphem.terminator < 0)
            direc = "west";
        else
            direc = "east";
        if (moonEphem.phaseAngle >= 0 && moonEphem.phaseAngle <= 180) {
            whichterm = "sunrise";
            waxwane = "waxing"
                } else {
                    whichterm = "sunset";
                    waxwane = "waning"
                        }

        // How many days old is the moon? 
        // Should this be + .5?
        var day = Math.floor((180-moonEphem.phaseAngle) * 29.5 / 360);

        moondesc.innerHTML = day + "-day old " + waxwane + " moon.<br>"
            + "<span class=\"terminator\">The " + whichterm
            + " terminator is at selenographic longitude "
            + roundit(moonEphem.terminator, 1) + " degrees " + direc
            + ".</span>"
    }
    else alert("No moondesc");

    var libtbl = document.getElementById("libtbl");
    if (libtbl) {
        var imday;
        if (day == 14 || day == 15)
            imday = "fm";
        else if (day < 10)
            imday = "0" + day;
        else
            imday = day;

        var tblstr = "<table align=center border=1>"
            + "<tr><td rowspan=3 align=center>Current Ephemeris of the Moon<br>(degrees):"
            + "<th colspan=1><th>latitude <th>longitude"
            + "<tr><th>Geocentric Position: <td>" + deangle(moonEphem.beta)
            + " <td>" + deangle(moonEphem.lambda);

        var EWlib, EWmag;
        EWlib = " ";
        EWmag = roundit(moonEphem.libEast, 2);
        if (moonEphem.libEast > 0) {
            EWlib = " E";
        } else if (moonEphem.libEast < 0) {
            EWlib = " W";
        }

        var NSlib, NSmag;
        NSlib = " ";
        NSmag = roundit(moonEphem.libNorth, 2);
        if (moonEphem.libNorth > 0)
            NSlib = " N";
        else if (moonEphem.libNorth < 0) {
            NSlib = " S";
        }

        tblstr += "<tr><th>Optical Libration: <td>"
            + NSmag + NSlib
            + " <td>" + EWmag + EWlib
            +"</table><br clear=all>";

        libtbl.innerHTML = tblstr;
    }
    else alert("No libtbl");

    /*
    doc.writeln("If you don't find what you want here, you might try today's ");
    doc.writeln("<a href=\"http://www.inconstantmoon.com/day_"
	        + imday
		+ ".htm\" target = \"_top\">Inconstant Moon</a>.");
    */
}

// end hiding -->

