
// Solar System Ephemeris
// Written by : Brian Chopp
// Copywright 2004

function cleanPage() {

// Fill the date fields with the current system date and the latitude and 
// logitude with South Bend's coordinates.  Then display the ephemeris for 
// the Sun.

	var dateNow = new Date();
	
	var yearNow  = dateNow.getYear();
	var monthNow = dateNow.getMonth() + 1;
	var dayNow   = dateNow.getDate();

// Set the input year, month, day fields.

	ephemeris_Frm.year_TxB.value  = yearNow;
	ephemeris_Frm.month_TxB.value = monthNow;
	ephemeris_Frm.day_TxB.value   = dayNow;
	
// Select the Sun as the solar system object.
	
	setSelect(ephemeris_Frm.ssObject_Sel);
	
// Set the latitude and logitude to South Bend's coordinates.

	ephemeris_Frm.latDeg_TxB.value = 41;
	ephemeris_Frm.latMin_TxB.value = 42;
	setSelect(ephemeris_Frm.latNS_Sel);
	ephemeris_Frm.lonDeg_TxB.value = 86;
	ephemeris_Frm.lonMin_TxB.value = 19;
	setSelect(ephemeris_Frm.lonEW_Sel);
	
	processPage();
	
	return true;
	
	}
	
function openHelp() {

// Display the help for the Solar System Ephemeris.

	helpWindow = window.open("ssehelp.htm","sseHelpWindow","width=500,height=350,left=200,top=200,scrollbars=yes");
	helpWindow.focus();
	
	return false;
	
	}

function processPage() {

// Process the user input.  First, validate the input data and display messages
// if there are errors.  Then, calculate the ephemeris values for the
// selected solar system object for the given date and location.  Finally, format
// and display the ephemeris values in the text boxes.
	
// Check to see that all of the input data is valid.  If so, continue processing.

	if ( validInput() ) {
	    
// Calculate the ephemeris values for the selected solar system object.

		var ephemeris = new Array();
		ephemeris = calculatePage();

// Format the ephemeris values for display on the screen.
	
		var ephemerisDisplay = new Array();
		ephemerisDisplay = formatPage(ephemeris);
		
// Move the formatted ephemeris values onto the page.

		ephemeris_Frm.RA_TxB.value        = ephemerisDisplay[3];
		ephemeris_Frm.Dec_TxB.value       = ephemerisDisplay[4];
		ephemeris_Frm.R_TxB.value         = ephemerisDisplay[5];
		ephemeris_Frm.Elong_TxB.value     = ephemerisDisplay[6];
		ephemeris_Frm.ADiameter_TxB.value = ephemerisDisplay[7];
		ephemeris_Frm.Magnitude_TxB.value = ephemerisDisplay[8];
		ephemeris_Frm.PctIllum_TxB.value  = ephemerisDisplay[9];
		ephemeris_Frm.Rise_TxB.value      = ephemerisDisplay[10];
		ephemeris_Frm.South_TxB.value     = ephemerisDisplay[11];
		ephemeris_Frm.Set_TxB.value       = ephemerisDisplay[12];
		ephemeris_Frm.Const_TxB.value     = getConstellation(ephemeris[3]);

		}
		
	return true;

	}
	
function calculatePage() {

// Conver the input data into the proper units for the ephemeris calculators.
// Then call the appropriate calculator based on the solar system object selected.
// An array will be returned with the ephemeris values for the solar system object
// selected.

// Create variables for the input fields so we can use a shorter name.

	var ssObject_Sel = ephemeris_Frm.ssObject_Sel;
	var day    = parseInt(ephemeris_Frm.day_TxB.value);
	var month  = parseInt(ephemeris_Frm.month_TxB.value);
	var year   = parseInt(ephemeris_Frm.year_TxB.value);
	var latDeg = parseInt(ephemeris_Frm.latDeg_TxB.value);
	var latMin = parseInt(ephemeris_Frm.latMin_TxB.value);
	var latNS  = ephemeris_Frm.latNS_Sel;
	var lonDeg = parseInt(ephemeris_Frm.lonDeg_TxB.value);
	var lonMin = parseInt(ephemeris_Frm.lonMin_TxB.value);
	var lonEW  = ephemeris_Frm.lonEW_Sel;

// Convert the latitude and logitude from degrees to radians.  Note that a South
// latitude and East longitude need to be negative.

	var latitude = latDeg + latMin / 60;
	if (getSelectValue(latNS) == "South") {
		latitude = latitude * -1;
		}
	latitude = degToRad(latitude);
	
	var longitude = lonDeg + lonMin / 60;
	if (getSelectValue(lonEW) == "West") {
		longitude = longitude * -1;
		}
	longitude = degToRad(longitude);
		
// Calculate the ephemeris for the appropriate solar system object.

	var ephemeris = new Array();
	var object = getSelectValue(ssObject_Sel);

	switch (object)
	{
	case "Sun":
	ephemeris = sunEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Mercury":
	ephemeris = mercuryEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Venus":
	ephemeris = venusEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Moon":
	ephemeris = moonEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Mars":
	ephemeris = marsEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Jupiter":
	ephemeris = jupiterEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Saturn":
	ephemeris = saturnEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Uranus":
	ephemeris = uranusEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Neptune":
	ephemeris = neptuneEphemeris(year, month, day, latitude, longitude);
	break;
	
	case "Pluto":
	ephemeris = plutoEphemeris(year, month, day, latitude, longitude);
	break;
	
	}
	
	return ephemeris;
	
	}
	
function formatPage(ephemerisIn) {

// Format the ephemeris information for display on the page.  Convert
// radian values to degrees.  Add the proper units to the values.

	var object = getSelectValue(ephemeris_Frm.ssObject_Sel);
	var ephemerisFormated = new Array();
	
// Format right ascension, element [3].

	ephemerisFormated[3] = formatRA(radToHr(ephemerisIn[3]));
	
// Format declination, element [4].

	if (ephemerisIn[4] > Math.PI) {
		ephemerisFormated[4] = formatAngle(radToDeg(ephemerisIn[4] - 2 * Math.PI));
		}
	else {
		ephemerisFormated[4] = formatAngle(radToDeg(ephemerisIn[4]));
		}

// Format distance, element [5].

	ephemerisFormated[5] = roundNumber(ephemerisIn[5], 3);
	if (object == "Moon") {
		ephemerisFormated[5] = ephemerisFormated[5] + " Earth Radii";
		}
	else {
		ephemerisFormated[5] = ephemerisFormated[5] + "AU";
		}

// Format elongation, element [6].

	ephemerisFormated[6] = formatAngle(radToDeg(ephemerisIn[6]));

// Format apparent diameter, element [7].

	ephemerisFormated[7] = formatAngle2(ephemerisIn[7]);
	
// Format magnitude, element [8].

	if (ephemerisIn[8] != "Not Available") {
		ephemerisFormated[8] = roundNumber(ephemerisIn[8], 1);
		}
	else {
		ephemerisFormated[8] = ephemerisIn[8];
		}

// Format percent illumination, element [9].

	ephemerisFormated[9] = roundNumber(ephemerisIn[9], 0) + "%";

// Format rise time, element [10].

	ephemerisFormated[10] = formatTime(ephemerisIn[10]);

// Format South time, element [11].

	ephemerisFormated[11] = formatTime(ephemerisIn[11]);

// Format set time, element [12].

	ephemerisFormated[12] = formatTime(ephemerisIn[12]);

	return ephemerisFormated;
	
	}
	
function validInput() {

// Validate input data.  If an error was found, return false.  Otherwise,
// if ererything was valid, return true.

// Create variables for the input fields so we can use a shorter name.

	var day    = ephemeris_Frm.day_TxB;
	var month  = ephemeris_Frm.month_TxB;
	var year   = ephemeris_Frm.year_TxB;
	var latDeg = ephemeris_Frm.latDeg_TxB;
	var latMin = ephemeris_Frm.latMin_TxB;
	var lonDeg = ephemeris_Frm.lonDeg_TxB;
	var lonMin = ephemeris_Frm.lonMin_TxB;
	
// Validate that day is a valid number.

	if (isNaN(day.value)) {
	    alert("Day is invalid.");
	    day.focus();
	    day.select();
	    }

// Validate that the day is between 1 and 31.

	else if (day.value < 1 || day.value > 31) {
		alert("Day must be between 1 and 31.");
		day.focus();
		day.select();
		}

// Validate that month is a valid number.

	else if (isNaN(month.value)) {
	    alert("Please enter a numeric month.");
	    month.focus();
	    month.select();
	    }

// Validate that the hours are between 1 and 12.

	else if (month.value < 1 || month.value > 12) {
		alert("Month must be between 1 and 31.");
		month.focus();
		month.select();
		}

// Validate that year is a valid number.

	else if (isNaN(year.value)) {
	    alert("Year is invalid.");
	    year.focus();
	    year.select();
	    }

// Validate that the year is between 1900 and 2100.

	else if (year.value < 1800 || year.value > 2100) {
		alert("Please enter a year between 1800 and 2100.");
		year.focus();
		year.select();
		}

// Validate that latitude degrees is a valid number.

	else if (isNaN(latDeg.value)) {
	    alert("Latitude degrees are invalid.");
	    latDeg.focus();
	    latDeg.select();
	    }

// Validate that the latidude degrees are between 0 and 89.

	else if (latDeg.value < 0 || latDeg.value > 89) {
		alert("Please enter latidude degrees between 0\xB0 and 89\xB0.");
		latDeg.focus();
		latDeg.select();
		}

// Validate that latitude minutes is a valid number.

	else if (isNaN(latMin.value)) {
	    alert("Latitude minutes are invalid.");
	    latMin.focus();
	    latMin.select();
	    }

// Validate that the latidude minutes are between 0 and 59.

	else if (latMin.value < 0 || latMin.value > 59) {
		alert("Please enter latidude minutes between 0' and 59'.");
		latMin.focus();
		latMin.select();
		}

// Validate that longitude degrees is a valid number.

	else if (isNaN(lonDeg.value)) {
	    alert("Longitude degrees are invalid.");
	    lonDeg.focus();
	    lonDeg.select();
	    }

// Validate that the longitude degrees are between 0 and 179.

	else if (lonDeg.value < 0 || lonDeg.value > 179) {
		alert("Please enter longitude degrees between 0\xB0 and 179\xB0.");
		lonDeg.focus();
		lonDeg.select();
		}

// Validate that longitude minutes is a valid number.

	else if (isNaN(lonMin.value)) {
	    alert("Longitude minutes are invalid.");
	    lonMin.focus();
	    lonMin.select();
	    }

// Validate that the longitude minutes are between 0 and 59.

	else if (lonMin.value < 0 || lonMin.value > 59) {
		alert("Please enter longitude minutes between 0' and 59'.");
		lonMin.focus();
		lonMin.select();
		}

// If we get to this point, everything was valid.  Return ture.

	else {	
		return true;
		}
		
// An error was found.  Return false.
		
	return false;

	}
	
function getConstellation(RA) {

// Determine which consellation the object is in based on it right accension.

	var constellation;
	
	if (RA > 0.466876 && RA <= 0.894481) {
		constellation = "Aries";
	}
	else if (RA > 0.894481 && RA <= 1.570796) {
		constellation = "Taurus";
	}
	else if (RA > 1.570796 && RA <= 2.094395) {
		constellation = "Gemini";
	}
	else if (RA > 2.094395 && RA <= 2.452188) {
		constellation = "Cancer";
	}
	else if (RA > 2.452188 && RA <= 3.045600) {
		constellation = "Leo";
	}
	else if (RA > 3.045600 && RA <= 3.761185) {
		constellation = "Virgo";
	}
	else if (RA > 3.761185 && RA <= 4.145157) {
		constellation = "Libra";
	}
	else if (RA > 4.145157 && RA <= 4.289147) {
		constellation = "Scorpius";
	}
	else if (RA > 4.289147 && RA <= 4.638212) {
		constellation = "Ophiuchus";
	}
	else if (RA > 4.638212 && RA <= 5.270894) {
		constellation = "Sagittarius";
	}
	else if (RA > 5.270894 && RA <= 5.750860) {
		constellation = "Capricornus";
	}
	else if (RA > 5.750860 && RA <= 6.130469) {
		constellation = "Aquarius";
	}
	else {
		constellation = "Pisces";
	}
	
	return constellation;
			
	}
	
function degToRad(degrees) {

// Convert the angle from degrees to radians.

	var radians = degrees * Math.PI / 180;
	
	return radians;
			
	}
	
function calcDayNumber(year, month, day) {

// Convert the date into a day number.

	var dayNumber = 0;
	var work1 = 0;
	var work2 = 0;
	var work3 = 0;
	
	work1 = Math.floor((month + 9) / 12);
	work2 = Math.floor(275 * month / 9);
	work3 = Math.floor(7 * (year + work1) / 4);
	dayNumber = 367 * year;
	dayNumber = dayNumber - work3 + work2 + day - 730530;
	
	return dayNumber;			
	}

function Ecc(e, M) {

// Calculate the Eccentric Anomaly from the eccentricity and mean anomaly.

	var E0 = 0;
	var E1 = 0;
	var E2 = 0;
	var E3 = 0;
	
	E0 = M + e * Math.sin(M) * (1 + e * Math.cos(M));
	E1 = E0 - (E0 - e * Math.sin(E0) - M) / (1 - e * Math.cos(E0));
	E2 = E1 - (E1 - e * Math.sin(E1) - M) / (1 - e * Math.cos(E1));
	E3 = E2 - (E2 - e * Math.sin(E2) - M) / (1 - e * Math.cos(E2));
	
	return E3;			
	}
	
function formatAngle(degrees) {

// Convert the numeric angle in degrees to a formatted text value.

	if (degrees == "Not Available") {
		return "Not Available";
		}
	else {
		var degreesOnly = Math.floor(degrees);
		var degreesText = degreesOnly + "\xB0";
		var minutes     = (degrees - degreesOnly) * 60;
		var minutesOnly = Math.round(minutes);
		var minutesText = minutesOnly + "m";
		return degreesText + " " + minutesText;
		}			
	}
	
function formatAngle2(degrees) {

// Convert the numeric angle in degrees to a formatted text value.

	if (degrees == "Not Available") {
		return "Not Available";
		}
	else {
		var degreesOnly = Math.floor(degrees);
		var degreesText = degreesOnly + "\xB0";
		var minutes     = (degrees - degreesOnly) * 60;
		var minutesOnly = Math.floor(minutes);
		var minutesText = minutesOnly + "m";
		var secondsOnly = Math.floor( (minutes - minutesOnly) * 60);
		var secondsText = secondsOnly + "s";
		return degreesText + " " + minutesText + " " + secondsText;
		}			
	}
	
function formatRA(hours) {

// Convert the numeric angle in hours to a formatted text value.

	var hoursOnly   = Math.floor(hours);
	var hoursText   = hoursOnly + "h";
	var minutes     = (hours - hoursOnly) * 60;
	var minutesOnly = Math.round(minutes);
	var minutesText = minutesOnly + "m";
//	var secondsOnly = Math.floor( (minutes - minutesOnly) * 60);
//	var secondsText = secondsOnly + "s";
	
//	return hoursText + " " + minutesText + " " + secondsText;
	return hoursText + " " + minutesText;
			
	}
	
function formatTime(hours) {

// Convert the numeric time in hours to a formatted time value.

	if (hours != "Always Up" && hours != "Always Set") {
		var hoursOnly   = Math.floor(hours);	
		var minutes     = (hours - hoursOnly) * 60;
		var minutesOnly = Math.round(minutes);

		if (hoursOnly < 10) {
			hoursOnly = "0" + hoursOnly;
			}
		if (minutesOnly < 10) {
			minutesOnly = "0" + minutesOnly;
			}

		return hoursOnly + " : " + minutesOnly + " UTC";
	}
	else {
		return hours;
		}
			
	}
	
function normalize(numberIn, upperLimit) {

// Normalize the number.  Modify the cyclic value to fall within range.
// For example, convert an hour to fall between 0 and 24.

	var numberNormal = 0;
	var numberInt = 0;

	if (numberIn >= 0) {
		numberInt = Math.floor(numberIn / upperLimit);
		numberNormal = numberIn - numberInt * upperLimit;
		}
	else {
		numberInt = Math.abs(Math.floor(numberIn / upperLimit));
		numberNormal = numberIn + numberInt * upperLimit;
		}
	
	return numberNormal;
			
	}

function obliquity(d) {

// Calculate the obliquity of Earth's axis.
// Input is the day number, d.

	var o1 = 23.4393;
	var o2 = 0.0000003563;
	var o  = 0;
	
	o1 = degToRad(o1);
	o2 = degToRad(o2);	
	o = o1 + o2 * d;
	o = normalize(o, 2 * Math.PI);
	
	return o;
	}
	
function radToDeg(radians) {

// Convert the angle from radians to degrees.

	var degrees = radians * 180 / Math.PI;
	
	return degrees;
			
	}

function radToHr(radians) {

// Convert the angle from radians to hours.

	var hours = radians * 24 / (2 * Math.PI);
	
	return hours;
			
	}

	
