
/*  EDDEC  --  Format a floating point number with the
               specified number of decimal places.  This
               assumes JavaScript won't represent the number
               in scientific notation.  */

function eddec(n, places)
{
    var ni, sgn = false;

    if (n < 0) {
        sgn =  true;
        n = -n;
    }
    ni = Math.floor((n * Math.pow(10.0, places)) + 0.5);
    ni = ni.toString();
    while (ni.length <= places) {
        ni = "0" + ni;
    }
//log += "ni = " + ni + "\n";
    return (sgn ? "-" : "") + ni.substr(0, ni.length - places) + "." + ni.substr(-places);
}

/*  VENUSK  --  Get "k" index value for Venus from a year
                and fraction.  */

function venusK(Y)
{
    var A = 2451996.706,
        B = 583.921361;
    var k;

    k = ((365.2425 * Y) + 1721060 - A) / B;
    if (k < 0) {
        k = Math.ceil(k);
    } else {
        k = Math.floor(k);
    }
    return k;
}

/*  VENUS  --  Obtain time of Venus' inferior conjunction
               and greatest eastern and western elongations
               and angles nearest to a year and fraction.
               Results are returned in a new array with
               elements as follows:

                  0:  Julian date of inferior conjunction
                  1:  Julian date of greatest eastern elongation
                  2:  Angle at greatest eastern elongation (degrees)
                  3:  Julian date of greatest western elongation
                  4:  Angle at greatest western elongation (degrees)
*/

function venus(k)
{
    var A = 2451996.706,
        B = 583.921361,
        M0 = 82.7311,
        M1 = 215.513058;

    var JDE0, M, T, T2, JDEi, JDEe, JDEw, ANGe, ANGw;

/*
    k = ((365.2425 * Y) + 1721060 - A) / B;
    if (k < 0) {
        k = Math.ceil(k);
    } else {
        k = Math.floor(k);
    }
*/
    JDE0 = A + (k * B);
    M = fixangle(M0 + k * M1);
    T = (JDE0 - 2451545) / 36525;
    T2 = T * T;

/*
log += "k = " + k + "\n" +
       "JDE0 = " + JDE0 + "\n" +
       "M = " + M + "\n" +
       "T = " + T + "\n";
*/

    M = dtr(M);

    //  Inferior conjunction

    JDEi = JDE0
                +                    (-0.0096 + 0.0002 * T - 0.00001 * T2)
                + (Math.sin(    M) * ( 2.0009 - 0.0033 * T - 0.00001 * T2))
                + (Math.cos(    M) * ( 0.5980 - 0.0104 * T + 0.00001 * T2))
                + (Math.sin(2 * M) * ( 0.0967 - 0.0018 * T - 0.00003 * T2))
                + (Math.cos(2 * M) * ( 0.0913 + 0.0009 * T - 0.00002 * T2))
                + (Math.sin(3 * M) * ( 0.0046 - 0.0002 * T               ))
                + (Math.cos(3 * M) * ( 0.0079 + 0.0001 * T               ));

    //  Greatest eastern elongation (evening visibility)

    JDEe = JDE0
                +                   (-70.7600 + 0.0002 * T - 0.00001 * T2)
                + (Math.sin(    M) * ( 1.0282 - 0.0010 * T - 0.00001 * T2))
                + (Math.cos(    M) * ( 0.2761 - 0.0060 * T               ))
                + (Math.sin(2 * M) * (-0.0438 - 0.0023 * T + 0.00002 * T2))
                + (Math.cos(2 * M) * ( 0.1660 - 0.0037 * T - 0.00004 * T2))
                + (Math.sin(3 * M) * ( 0.0036 + 0.0001 * T               ))
                + (Math.cos(3 * M) * (-0.0011              + 0.00001 * T2));

    //  Angle at greatest eastern elongation

    ANGe =                           (46.3173 + 0.0001 * T               )
                + (Math.sin(    M) * ( 0.6916 - 0.0024 * T               ))
                + (Math.cos(    M) * ( 0.6676 - 0.0045 * T               ))
                + (Math.sin(2 * M) * ( 0.0309 - 0.0002 * T               ))
                + (Math.cos(2 * M) * ( 0.0036 - 0.0001 * T               ));

    //  Greatest western elongation (morning visibility)

    JDEw = JDE0
                +                   (+70.7462              - 0.00001 * T2)
                + (Math.sin(    M) * ( 1.1218 - 0.0025 * T - 0.00001 * T2))
                + (Math.cos(    M) * ( 0.4538 - 0.0066 * T               ))
                + (Math.sin(2 * M) * ( 0.1320 + 0.0020 * T - 0.00003 * T2))
                + (Math.cos(2 * M) * (-0.0702 + 0.0022 * T + 0.00004 * T2))
                + (Math.sin(3 * M) * ( 0.0062 - 0.0001 * T               ))
                + (Math.cos(3 * M) * ( 0.0015              - 0.00001 * T2));

    //  Angle at greatest western elongation

    ANGw =                            46.3245
                + (Math.sin(    M) * (-0.5366 - 0.0003 * T + 0.00001 * T2))
                + (Math.cos(    M) * ( 0.3097 + 0.0016 * T - 0.00001 * T2))
                + (Math.sin(2 * M) * (-0.0163                            ))
                + (Math.cos(2 * M) * (-0.0075 + 0.0001 * T               ));

    return new Array(JDEi, JDEe, ANGe, JDEw, ANGw);
}

/*  PAD  --  Pad a string to a given length with a given fill character.  */

function pad(str, howlong, padwith) {
    var s = str.toString();

    while (s.length < howlong) {
        s = padwith + s;
    }
    return s;
}

/*  EDATE  --  Edit date to application specific format.  */

var Months = new Array( "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                      );

function edate(j) {
    var date, time;

    date = jyear(j);

    return pad(date[0], 4, " ") + " " + Months[date[1] - 1] + " " +
           pad(date[2], 2, " ");
}

/*  EDURLTIME  --  Edit date and time to embed in URL.  */

function edURLtime(j) {
    var date, time;

    j += (30.0 / (24 * 60 * 60));     // Round to nearest minute
    date = jyear(j);
    time = jhms(j);

    return date[0] + "%2F" + date[1] + "%2F" + date[2] + "+" +  
           time[0] + "%3A" + time[1];
}

//  GEN  --  Update the tables when an action button is pressed

function gen() {
    var k, s, v, kr, ns, elo, mag;

    window.status = "Calculating..";
    document.calc.results.value = "";
    year = document.calc.year.value;
    v = "Apparition      Date       Elongation\n" +
        "----------   -----------   ----------\n";
    s = "";

//log = "";
//log += "Calculating for " + year + "\n";

    k = venusK(year - 0.5);
    ns = 0;
    document.calc.selection.options.length = 0;
    while (true) {

        kr = venus(k);
        if (jyear(kr[1])[0] == year) {
            elo = eddec(kr[2], 1) + "°E";
            s = edate(kr[1]);
            v += " Evening     " + s + "     " + elo + "\n";
            document.calc.selection.options.length = ns + 1;
            document.calc.selection.options[ns].value = kr[1].toString();
            document.calc.selection.options[ns++].text = s;
        }
        if (jyear(kr[3])[0] > year) {
            break;
        }
        if (jyear(kr[3])[0] == year) {
            elo = eddec(kr[4], 1) + "°W";
            s = edate(kr[3]);
            v += " Morning     " + s + "     " + elo + "\n";
//document.calc.log.value += "Ns = " + ns + "\n";
//document.calc.log.value += s + "\n";
            document.calc.selection.options.length = ns + 1;
            //  Morning apparitions are flagged by a negative JD in the select
            document.calc.selection.options[ns].value = (-kr[3]).toString();
            document.calc.selection.options[ns++].text = s;
        }
        k++;
    }

    document.calc.results.value = v;

    //  Set number of selectable items to number actually in box
    document.calc.selection.length = ns;

//document.calc.log.value += log;

    window.status = "Done.";
}

//  VIEW  --  View an elongation from a given site

function view()
{
    var n, jd, vlat, vlon, morning, ys, url;
    var ppos,
        lM, bM, rM, ldM, bdM,
        lE, bE, rE, ldE, bdE,
        raM, decM,
        altS, aziS, altM, aziM,
        vazi;

//document.calc.log.value = "";
//log = "";
    n = document.calc.selection.selectedIndex;
    if (n < 0) {
//log += "Nothing selected\n";
        alert("Please select an elongation Date\n" +
              "before pressing the Sky Map button.\n");
        return;
    }

    jd = Number(document.calc.selection.options[n].value);
    if ((morning = (jd < 0)) == true) {
        jd = -jd;
    }
//log += "Viewing item " + n + ": JD = <" + jd + "> " + edate(jd) +
//       (morning ? " Morning" : " Evening") + "\n";
    vlat = Number(document.calc.vlat.value);
    if (isNaN(vlat) || (vlat < 0) || (vlat > 90)) {
        alert("Latitude must be a number\n" +
              "between 0 and 90.");
        return;
    }
    if (document.calc.latns[1].checked) {
        vlat = -vlat;
    }
    vlon = Number(document.calc.vlon.value);
    if (isNaN(vlon) || (vlon < 0) || (vlon > 180)) {
        alert("Longitude must be a number\n" +
              "between 0 and 180.");
        return;
    }
    if (document.calc.lonew[0].checked) {
        vlon = -vlon;
    }
//log += "Site latitude = " + vlat + " longitude = " + vlon + "\n";

    //  Tweak the time of day to make it noonish on elongation day

//document.calc.log.value += "Elongation JD = " + jd + "\n";
    jd = Math.floor(jd + 0.5) + (vlon / 360.0);
//document.calc.log.value += "Tweaked JD = " + jd + " vlon = " + vlon + "\n";

    /*  We assemble the URL, open the window, then plug the
        URL into its location due to bug in Netscrape 2 which
        ignores the URL argument.  */

    url         = "/cgi-bin/uncgi/Yoursky?date=1&utc=" +
                  edURLtime(jd) +
                  "&lat=" + Math.abs(vlat) + 
                  "&ns=" + ((vlat >= 0) ? "North" : "South") +
                  "&lon=" + Math.abs(vlon) + "&ew=" + ((vlon >= 0) ? "West" : "East") +
                  "&coords=on&moonp=on" +
                  "&consto=on&constn=on&constb=on" +
                  "&limag=5.5" +
                  "&showmb=-1.5&showmd=6.0" +
                  "&imgsize=512&scheme=0&elements=";
    ys = open("", "Fourmilab_YourSky");
    ys.location = url;
    ys.focus();

//document.calc.log.value += log;
}

//  ORRERY  --  View orrery rendering of a given elongation

function orrery()
{
    var n, jd, vlat, vlon, url;

//document.calc.log.value = "";
//log = "";
    n = document.calc.selection.selectedIndex;
    if (n < 0) {
//log += "Nothing selected\n";
        alert("Please select an elongation Date\n" +
              "before pressing the Orrery button.\n");
        return;
    }

    jd = Math.abs(Number(document.calc.selection.options[n].value));
//log += "Viewing item " + n + ": JD = <" + jd + "> " + edate(jd) + "\n";

    /*  If the user has specified a latitude and longitude,
        pass it along to Solar System Live, but if not
        simply use default values.  The observing site affects
        only the local positions in the table at the bottom of
        the orrery display, which few users pay attention to.  */

    vlat = Number(document.calc.vlat.value);
    if (isNaN(vlat) || (vlat < 0) || (vlat > 90)) {
        vlat = 47;
    }
    if (document.calc.latns[1].checked) {
        vlat = -vlat;
    }
    vlon = Number(document.calc.vlon.value);
    if (isNaN(vlon) || (vlon < 0) || (vlon > 180)) {
        vlon = 7;
    }
    if (document.calc.lonew[0].checked) {
        vlon = -vlon;
    }
//log += "Site latitude = " + vlat + " longitude = " + vlon + "\n";

    /*  We assemble the URL, open the window, then plug the
        URL into its location due to bug in Netscrape 2 which
        ignores the URL argument.  */

    url         = "/cgi-bin/uncgi/Solar?date=1&" +
                  "utc=" + edURLtime(jd) + "&" +
                  "img=-k0&sys=-Si&imgsize=320&eyes=0&" +
                  "orb=-b1&" +
                  "lat=" + Math.abs(vlat) + "&ns=" +
                      ((vlat > 0) ? "North" : "South") + "&" +
                  "lon=" + Math.abs(vlon) + "&ew=" +
                      ((vlon > 0) ? "West" : "East") + "&" +
                  "hlat=90%B0&hns=North&hlon=0%B0&elements=";

    ys = open("", "Fourmilab_YourSky");
    ys.location = url;
    ys.focus();

//document.calc.log.value += log;
}

