
/////////////////////////////////////////////
// sunposition.js
// Copyright 2006, 1995 Sustainable By Design
/////////////////////////////////////////////



/////////////
// GLOBALS //
/////////////

var currentDay;
var currentMonth;
var daysRemaining;
var delimiterCharacter;
var inputAltitudeChecked;
var inputAngleUnits;
var inputAzimuthChecked;
var inputDateStyle;
var inputDayLengthChecked;
var inputDeclinationChecked;
var inputEOTChecked;
var inputFrequency;
var inputHourAngleChecked;
var inputLatitude;
var inputLongitude;
var inputLeapYearChecked;
var inputIncludeHeaderChecked;
var inputResolution;
var inputStartDate;
var inputStartMonth;
var inputStartTimeHours;
var inputStartTimeMinutes;
var inputTimeStyle;
var inputTimeBasis;
var newline;
var outputString;
var samplesPerDay;

var showedLongitudeMeridianWarning = false;

var didAlert = false;


	///////////////
	// CONSTANTS //
	///////////////

var degreesToRadians = 3.1416 / 180;
var radiansToDegrees = 180 / 3.1416;
var degreeMinutesToDecimal =    1.0000 /   60.0000;
var degreeSecondsToDecimal =    1.0000 / 3600.0000;				


///////////////////////////
// CHECK INPUTS FUNCTION //
///////////////////////////

function CheckInputs () {

	var error = false;

	var error_message = "The following inputs must be corrected before the sun angle data can be calculated:\n\n";

	var f = document.theForm;

	var inputLatitude   = f.inputLatitude.value;
	
	// LATITUDE

	var latitudeOkay = false;

	if (inputLatitude.search ("^[0-9]+[dD][0-9]+[mM][0-9]+[sS]$") > -1) { latitudeOkay = true; }
	
	else { if ((inputLatitude >= 0 ) && (inputLatitude <= 90)) { latitudeOkay = true; } }

	if (! latitudeOkay) {
		
		error_message = error_message + "* The latitude must be between 0 and 90 degrees (click on the latitude label for details)\n";
		
		error = true;
	}
	
	// LONGITUDE
	
	if (CalculatingClockTime ()) {

		var inputLongitude   = f.inputLongitude.value;

		var longitudeOkay = false;
	
		if (inputLongitude.search ("^[0-9]+[dD][0-9]+[mM][0-9]+[sS]$") > -1) { longitudeOkay = true; }
		
		else { if ((inputLongitude >= 0 ) && (inputLongitude <= 360)) { longitudeOkay = true; } }
	
		if (! longitudeOkay) {
			
			error_message = error_message + "* The longitude must be between 0 and 360 degrees (click on the longitude label for details)\n";
			
			error = true;
		}
	}
	
	// ALERT / RETURN

	if (error == true) { alert (error_message); }

	return (! error);
}


////////////////////////////////////////////////////////////////////////////////////
//  MAIN COMPUTE FUNCTION  
////////////////////////////////////////////////////////////////////////////////////

function compute () {

	var f = document.theForm;
	
	// set newline character dependent on browser
	
	if (navigator.appName.substring(0,9) == "Microsoft") { 
	
		newline = "\r\n";
	}

	else { 
	
		newline = "\n";
	}

	// retrieve input values
	
	         // time basis
	         
	var timeBasis = GetRadioButtonValue (f.inputTimeBasis);
	
	         // sunangles
	
	inputAltitudeChecked    = f.inputAltitude.checked;                                   // boolean
	inputAzimuthChecked     = f.inputAzimuth.checked;                                    // boolean
	inputDeclinationChecked = f.inputDeclination.checked;                                // boolean
	inputEOTChecked         = f.inputEOT.checked;                                        // boolean
	inputHourAngleChecked   = f.inputHourAngle.checked;                                  // boolean
	inputDayLengthChecked   = f.inputDayLength.checked;                                  // boolean
	inputAlternateTimeChecked = f.inputAlternateTime.checked;                            // boolean

	         // location
	         
	         	// latitude

	inputLatitude  = f.inputLatitude.value;

	if (inputLatitude.indexOf("d") != -1) {
	
		degMarker = inputLatitude.indexOf("d");
		minMarker = inputLatitude.indexOf("m");
		secMarker = inputLatitude.indexOf("s");

		LatitudeDeg = inputLatitude.substr(0,degMarker)                       - 0;
		LatitudeMin = inputLatitude.substr(degMarker+1,minMarker-degMarker-1) - 0;
		LatitudeSec = inputLatitude.substr(minMarker+1,secMarker-minMarker-1) - 0;
		
		inputLatitude = LatitudeDeg + (LatitudeMin * degreeMinutesToDecimal) + (LatitudeSec * degreeSecondsToDecimal);
	}
	
	else { inputLatitude -= 0; }
	
	var inputNorthSouth = f.inputNorthSouth;           // radio button                 

	         	// longitude
	         	
	if (CalculatingClockTime ()) {	         	

		inputLongitude  = f.inputLongitude.value;
	
		if (inputLongitude.indexOf("d") != -1) {
		
			degMarker = inputLongitude.indexOf("d");
			minMarker = inputLongitude.indexOf("m");
			secMarker = inputLongitude.indexOf("s");
	
			LongitudeDeg = inputLongitude.substr(0,degMarker)                       - 0;
			LongitudeMin = inputLongitude.substr(degMarker+1,minMarker-degMarker-1) - 0;
			LongitudeSec = inputLongitude.substr(minMarker+1,secMarker-minMarker-1) - 0;
			
			inputLongitude = LongitudeDeg + (LongitudeMin * degreeMinutesToDecimal) + (LongitudeSec * degreeSecondsToDecimal);
		}
		
		else { inputLongitude -= 0; }
		
		var inputEastWest = f.inputEastWest;               // radio button                 
	
					// time zone
					
		var inputTimeZone = f.inputTimeZone.options[f.inputTimeZone.selectedIndex].value - 0;
		var meridian = inputTimeZone * -15;
	}
	
	         // data resolution
	
	inputFrequency         = f.inputFrequency.options[f.inputFrequency.selectedIndex].text;                  // text
	inputResolution        = f.inputResolution.options[f.inputResolution.selectedIndex].text;                // text
	inputStartMonth        = f.inputStartMonth.options[f.inputStartMonth.selectedIndex].text;                // text
	inputStartDate         = f.inputStartDate.options[f.inputStartDate.selectedIndex].text;                  // text
	inputStartTimeHours    = f.inputStartTimeHours.options[f.inputStartTimeHours.selectedIndex].text;        // text
	inputStartTimeMinutes  = f.inputStartTimeMinutes.options[f.inputStartTimeMinutes.selectedIndex].text;    // text
	
	         // output format
	
	var inputDelimiter            = f.inputDelimiter.options[f.inputDelimiter.selectedIndex].text;    // text
	    inputAngleUnits           = f.inputAngleUnits.options[f.inputAngleUnits.selectedIndex].text;  // text
	    inputDateStyle            = f.inputDateStyle.options[f.inputDateStyle.selectedIndex].text;    // text
	    inputTimeStyle            = f.inputTimeStyle.options[f.inputTimeStyle.selectedIndex].text;    // text
	    inputLeapYearChecked      = f.inputLeapYear.checked;                                          // boolean
	    inputIncludeHeaderChecked = f.inputIncludeHeader.checked;                                     // boolean

	// INPUT DERIVATIVES
	
		// determine samples per year from frequency input
	
	if (inputFrequency == "every day")        { var samplesPerYear = 365 + inputLeapYearChecked; }  // boolean evaluates to 0 or 1
	if (inputFrequency == "weekly")           { var samplesPerYear =  52; }
	if (inputFrequency == "monthly")          { var samplesPerYear =  12; }
	if (inputFrequency == "quarterly")        { var samplesPerYear =   4; }
	if (inputFrequency == "one specific day") { var samplesPerYear =   1; }
	
		// determine samples per day from resolution input
	
	if (inputResolution == "every 15 minutes") { samplesPerDay = 96; }
	if (inputResolution == "every 30 minutes") { samplesPerDay = 48; }
	if (inputResolution == "every hour")       { samplesPerDay = 24; }
	if (inputResolution == "every 3 hours")    { samplesPerDay =  8; }
	if (inputResolution == "every 4 hours")    { samplesPerDay =  6; }
	if (inputResolution == "every 6 hours")    { samplesPerDay =  4; }
	if (inputResolution == "every 8 hours")    { samplesPerDay =  3; }
	if (inputResolution == "every 12 hours")   { samplesPerDay =  2; }
	if (inputResolution == "once a day")       { samplesPerDay =  1; }

		// determine month and day numbers from string inputs
	
	currentMonth = MonthStringToMonthNum (inputStartMonth);
	currentDay   = inputStartDate * 1;
	
		// correct latitude for north/south hemisphere
	
	if (GetRadioButtonValue (inputNorthSouth) == 'south') { inputLatitude *= -1; }
	
		// correct longitude for east/west hemisphere
	
	if (CalculatingClockTime ()) {
	
		if (GetRadioButtonValue (inputEastWest) == 'east') { inputLongitude *= -1; }

		// fix longitude > 180 deg
		
		if (inputLongitude > 180) {
		
			inputLongitude = inputLongitude - 360;
		}

		// fix longitude < -180 deg
		
		if (inputLongitude < -180) {
		
			inputLongitude = inputLongitude + 360;
		}

			// alert if laongitude differs too much from time zone
			
		var longitudeMeridianDifference = inputLongitude  - meridian;
	
		if ((! showedLongitudeMeridianWarning) && ((longitudeMeridianDifference > 30) || (longitudeMeridianDifference < -30))) {
		
			alert ("Warning:  The longitude differs from the center of the selected time zone by more than 30 degrees.  This may be correct, or it may indicate that one of those two inputs is incorrect.\n\nPlease click on the 'time zone' input for more information.\n\n(You will not be shown this warning again.)");
			
			showedLongitudeMeridianWarning = true;
		}
	}	
	
	else {

		longitudeMeridianDifference = 0;
		
		inputTimeZone = 0;
	}
	
		// output delimiter character
		
	if (inputDelimiter ==     "space") { delimiterCharacter = " ";  }
	if (inputDelimiter ==       "tab") { delimiterCharacter = "\t"; }
	if (inputDelimiter ==     "comma") { delimiterCharacter = ",";  }
	if (inputDelimiter ==     "colon") { delimiterCharacter = ":";  }
	if (inputDelimiter == "semicolon") { delimiterCharacter = ";";  }


	// CREATE HEADER STRING
	
	if (inputIncludeHeaderChecked) {
	
		if (inputNorthSouth[1].checked == true) { var latitudeHeaderString = "south"; }
		else { var latitudeHeaderString = "north"; }
		
		var headerString = "SunPosition output complete" + newline + "Latitude is " + inputLatitude + " degrees " + latitudeHeaderString + newline;

		if (CalculatingClockTime ()) {
		
			var longitudeHeaderString = GetRadioButtonValue (f.inputEastWest);
			
			headerString += "Longitude is " + inputLongitude + " degrees " + longitudeHeaderString + newline;

			headerString += "Time zone offset from GMT is " + inputTimeZone + " hours" + newline;
		}
		

		headerString += "Output angle units are " + inputAngleUnits + newline + newline + "date";

		if (timeBasis == 'solar') {
		
			headerString += delimiterCharacter + "solar time";
		}
		
		else {
		
			headerString += delimiterCharacter + "clock time";
		}
		
		if (   inputAltitudeChecked == true) { headerString += delimiterCharacter + "altitude"; }
		if (    inputAzimuthChecked == true) { headerString += delimiterCharacter + "azimuth"; }
		if (inputDeclinationChecked == true) { headerString += delimiterCharacter + "declination"; }
		if (        inputEOTChecked == true) { headerString += delimiterCharacter + "eot"; }
		if (  inputHourAngleChecked == true) { headerString += delimiterCharacter + "hour angle"; }
		if (  inputDayLengthChecked == true) { headerString += delimiterCharacter + "day length"; }
		
		if (inputAlternateTimeChecked == true) { 
		
			if (timeBasis == 'solar') {
			
				headerString += delimiterCharacter + "clock time";
			}
			
			else {
			
				headerString += delimiterCharacter + "solar time";
			}
		}
		
		headerString += newline;
	}
	
	else {
	
		headerString = '';
	}
	
	// CALCULATIONS
	
	// determine number of iterations
	
	daysRemaining = samplesPerYear;
	
	f.outputs.value = "Samples remaining to calculate: " + daysRemaining * samplesPerDay + newline;
	
	outputString = "";
  
	while (daysRemaining > 0) {
	
		if ((daysRemaining % 10) == 0) { 	f.outputs.value = "Samples remaining to calculate: " + daysRemaining * samplesPerDay + newline; }
    
    	DoOneDay (currentMonth, currentDay, timeBasis, longitudeMeridianDifference, inputAlternateTimeChecked, inputTimeZone);
    
    	daysRemaining -= 1;
    	
    	if (daysRemaining > 0) { Iterate (); }
    
	} // end while days remaining

	f.outputs.value = headerString + outputString;
	
} // end compute function


// DO ONE DAY FUNCTION

function DoOneDay (whichMonth, whichDay, timeBasis, longitudeMeridianDifference, inputAlternateTimeChecked, inputTimeZone) {

	if (inputResolution == "once a day") {

		var minutes = (60 * inputStartTimeHours) + (1 * inputStartTimeMinutes);
		
		DoOneCalc (whichMonth, whichDay, minutes, timeBasis, longitudeMeridianDifference, inputAlternateTimeChecked, inputTimeZone);		
	}
	else {

		var done = 0;
		var minutes = 0;
		
		while (! done) {
			DoOneCalc (whichMonth, whichDay, minutes, timeBasis, longitudeMeridianDifference, inputAlternateTimeChecked, inputTimeZone);
			minutes += (1440 / samplesPerDay);
			if (minutes >= 1440) { done = 1; }
		}
	}
	
} // end do one day function


// DO ONE CALC FUNCTION

function DoOneCalc (whichMonth, whichDay, minutes, timeBasis, longitudeMeridianDifference, inputAlternateTimeChecked, inputTimeZone) {

	// determine day of year

	var dayOfYear = MonthNumToDays (whichMonth) + (whichDay * 1);
	
	// new line for output string
	
	outputString += newline;
	
	// add date to tempString
	
	if (inputDateStyle == "1/21") { outputString += whichMonth + "/" + whichDay + delimiterCharacter; }
	
	if (inputDateStyle == "01/21") {
		if (whichMonth < 10) { printMonth = "0" + whichMonth; } else { printMonth = whichMonth; }
		if (  whichDay < 10) {   printDay = "0" +   whichDay; } else { printDay = whichDay; }
		outputString += printMonth + "/" + printDay + delimiterCharacter;
	}
	
	if (inputDateStyle == "jan 21") { outputString += MonthNumToShortName (whichMonth) + " " + whichDay + delimiterCharacter; }
	
	if (inputDateStyle == "January 21") { outputString += MonthNumToLongName (whichMonth) + " " + whichDay + delimiterCharacter; }
	
	if (inputDateStyle == "21/1") { outputString += whichDay + "/" + whichMonth + delimiterCharacter; }
	
	if (inputDateStyle == "21/01") {
		if (whichMonth < 10) { printMonth = "0" + whichMonth; } else { printMonth = whichMonth; }
		if (  whichDay < 10) {   printDay = "0" +   whichDay; } else { printDay = whichDay; }
		outputString += printDay + "/" + printMonth + delimiterCharacter;
	}
	
	if (inputDateStyle == "21 jan") { outputString += whichDay + " " + MonthNumToShortName (whichMonth) + delimiterCharacter; }
	
	if (inputDateStyle == "21 January") { outputString += whichDay + " " + MonthNumToLongName (whichMonth) + delimiterCharacter; }
	
	// add time to output string

	var primaryTimeString = CreateTimeString (minutes, inputTimeStyle);
	
	outputString += primaryTimeString;

	// declination and eot
	
		// note: EOT is calculated for the year 2009

	if (whichMonth > 2) {
		var correctedYear = 2009;
		var correctedMonth = whichMonth - 3;
	}
	else {
		var correctedYear = 2008;
		var correctedMonth = whichMonth +9;
	}	
  
	var UT = (minutes / 60) - inputTimeZone;

	var t = ((UT / 24.0) + whichDay + Math.floor (30.6 * correctedMonth + 0.5) + Math.floor (365.25 * (correctedYear - 1976)) - 8707.5) / 36525.0;
  
	var G = 357.528 + 35999.05 * t;
	G = NormalizeTo360 (G);
  
	var C = (1.915 * Math.sin (G * degreesToRadians)) + (0.020 * Math.sin (2.0 * G * degreesToRadians));
	
	var L = 280.460 + (36000.770 * t) + C;
	L = NormalizeTo360 (L);
	
	var alpha = L - 2.466 * Math.sin (2.0 * L * degreesToRadians) + 0.053 *  Math.sin (4.0 * L * degreesToRadians);
	
	var obliquity = 23.4393 - 0.013 * t;
	
	var declination = Math.atan (Math.tan (obliquity * degreesToRadians) * Math.sin (alpha * degreesToRadians)) * radiansToDegrees;

	var eotAdjustment = (L - C - alpha) / 15.0 * 60.0;

	// clock time to solar time adjustment (required unless solar time with no clock time being calculated)
	
	if (CalculatingClockTime ()) {
	
		var clockTimeToLSOTAdjustment = ((longitudeMeridianDifference) / 15.0) - (eotAdjustment / 60.0);   // in hours;  doesn't include DST
	}
	
	// calculate solar time and clock time
	
		// if time basis is solar time
	
	if (timeBasis == 'solar') {
	
	// //////////////////////////////////////////
	// debugging begins  //////////////////////////
	// //////////////////////////////////////////
	
	if (didAlert) {
	
		infoString = minutes;
		
		alert (infoString);
		
		didAlert = true;
	}

	// //////////////////////////////////////////
	// debugging ends  //////////////////////////
	// //////////////////////////////////////////
	
		solarTimeMinutes = minutes;
		
		if (inputAlternateTimeChecked) {
		
			clockTimeMinutes = minutes + (clockTimeToLSOTAdjustment * 60.0);
		
			outputAlternateTime = CreateTimeString (clockTimeMinutes, inputTimeStyle);
		}
	}
	
		// if time basis is clock time
	
	else {
	
		solarTimeMinutes = minutes - (clockTimeToLSOTAdjustment * 60.0);
		
		if (inputAlternateTimeChecked) {
		
			outputAlternateTime = CreateTimeString (solarTimeMinutes, inputTimeStyle);
		}
	}

	// hour angle
	
	var hourAngle = (solarTimeMinutes - (12 * 60)) / 4 * -1;
	
	// altitude angle
	
	var altitudeAngle = radiansToDegrees * ArcSin (
		(Math.cos (inputLatitude   * degreesToRadians)  *
		 Math.cos (declination     * degreesToRadians)  *
		 Math.cos (hourAngle       * degreesToRadians)) +
		(Math.sin (inputLatitude   * degreesToRadians)  *
		 Math.sin (declination     * degreesToRadians)));
	
	// azimuth angle
	
	var azimuthMeat = (
		(Math.sin (altitudeAngle  * degreesToRadians)  *
		 Math.sin (inputLatitude  * degreesToRadians)) -
		 Math.sin (declination    * degreesToRadians)) /
		(Math.cos (altitudeAngle  * degreesToRadians)  *
		 Math.cos (inputLatitude  * degreesToRadians));
		 
	if (azimuthMeat >  1) { azimuthMeat =  1; }
	if (azimuthMeat < -1) { azimuthMeat = -1; }
			
	var azimuthAngle = radiansToDegrees * ArcCos (azimuthMeat);
		 
	if (azimuthAngle * hourAngle < 0) { azimuthAngle *= -1 };
	
	// day length
	
	var dayLength = 2 * radiansToDegrees * ArcCos ( -1.0 *
		Math.sin (inputLatitude  * degreesToRadians) *
		Math.sin (declination    * degreesToRadians) /
		Math.cos (inputLatitude  * degreesToRadians) /
		Math.cos (declination    * degreesToRadians)) * 4;
	
	// convert outputs to radians if necessary
	
	if (inputAngleUnits == "radians") {
		altitudeAngle *= degreesToRadians;
		 azimuthAngle *= degreesToRadians;
		  declination *= degreesToRadians;
		    hourAngle *= degreesToRadians;
	}
	
	// add outputs as requested

	if (   inputAltitudeChecked == true) { outputString += (delimiterCharacter + FormatFloatString (altitudeAngle)); }
	if (    inputAzimuthChecked == true) { outputString += (delimiterCharacter + FormatFloatString ( azimuthAngle)); }
	if (inputDeclinationChecked == true) { outputString += (delimiterCharacter + FormatFloatString (  declination)); }
	if (        inputEOTChecked == true) { outputString += (delimiterCharacter + FormatFloatString (eotAdjustment)); }
	if (  inputHourAngleChecked == true) { outputString += (delimiterCharacter + FormatFloatString (    hourAngle)); }
	if (  inputDayLengthChecked == true) { outputString += (delimiterCharacter + FormatFloatString (    dayLength)); }
	if (  inputAlternateTimeChecked == true) { outputString += (delimiterCharacter + outputAlternateTime); }
	
} // end do one calc function


// ITERATE FUNCTION

function Iterate () {

	if (inputFrequency == "every day") {
    
		currentDay += 1;
    
		if (currentDay > 28) {
			if ((currentMonth == 1) || (currentMonth == 3) || (currentMonth == 5) || (currentMonth == 7) || (currentMonth == 8) || (currentMonth == 10) || (currentMonth == 12)) {
				if (currentDay == 32) {
					currentDay = 1;
					currentMonth += 1;
				}
			}
			else if (currentMonth != 2) {
				if (currentDay == 31) {
					currentDay = 1;
					currentMonth += 1;
				}
			}
			else {
				if (currentDay == (29 + inputLeapYearChecked)) {
					currentDay = 1;
					currentMonth += 1;
				}   
			}
		}
    
		if (currentMonth == 13) { currentMonth = 1; }
    
	} // frequency is every day
  
	if (inputFrequency == "weekly") {
    
		currentDay += 7;
    
		if (currentDay > 28) {
			if ((currentMonth == 1) || (currentMonth == 3) || (currentMonth == 5) || (currentMonth == 7) || (currentMonth == 8) || (currentMonth == 10) || (currentMonth == 12)) {
				if (currentDay > 31) {
					currentDay -= 31;
					currentMonth += 1;
				}
			}
			else if (currentMonth != 2) {
				if (currentDay > 30) {
					currentDay -= 30;
					currentMonth += 1;
				}
			}
			else {
				if (currentDay > (28 + inputLeapYearChecked)) {
					currentDay -= (28 + inputLeapYearChecked);
					currentMonth += 1;
				}
			}
		}
		    
		if (currentMonth == 13) { currentMonth = 1; }
    
	} // end if frequency is weekly
  
	if (inputFrequency == "monthly") {

		currentMonth += 1;

		if (currentMonth == 13) { currentMonth = 1; }

		if (inputStartDate > 28) {
			if ((currentMonth == 4) || (currentMonth == 6) || (currentMonth == 9) || (currentMonth == 11)) {
				if (inputStartDate == 31) { currentDay = 30; }
			}
			else if (currentMonth == 2) {
				if (inputStartDate > (28 + inputLeapYearChecked)) { currentDay = (28 + inputLeapYearChecked); }
			}
			else { currentDay = inputStartDate; }
		}
		
	} // end if monthly frequency

	if (inputFrequency == "quarterly") {

		currentMonth += 3;

		if (currentMonth > 12) { currentMonth -= 12; }

		if (inputStartDate > 28) {
			if ((currentMonth == 4) || (currentMonth == 6) || (currentMonth == 9) || (currentMonth == 11)) {
				if (inputStartDate == 31) { currentDay = 30; }
			}
			else if (currentMonth == 2) {
				if (inputStartDate > (28 + inputLeapYearChecked)) { currentDay = (28 + inputLeapYearChecked); }
			}
			else { currentDay = inputStartDate; }
		}
		
	} // end if quarterly frequency
	
} // end iterate function

// CREATE TIME STRING FUNCTION

function CreateTimeString (minutes, inputTimeStyle) {

	// fix minutes out of bounds
	
	while (minutes < 0) { 
	
		minutes += (60 * 24);
	}

	while (minutes > (60 * 24)) { 
	
		minutes -= (60 * 24);
	}

	// create time strings

	var hoursString = Math.floor (minutes / 60);
	var minutesString = Math.floor (minutes % 60);
	if (minutesString < 10) { minutesString = "0" + minutesString };
	
	if (inputTimeStyle == "1400") {
		if (hoursString < 10) { hoursString = "0" + hoursString; }
		timeString = String (hoursString) + String (minutesString);
	}

	if (inputTimeStyle == "14:00") {
		if (hoursString < 10) { hoursString = "0" + hoursString; }
		timeString = hoursString + ":" + minutesString;
	}

	if (inputTimeStyle == "2:00") {
		if (hoursString > 12) { hoursString = hoursString - 12; }
		if (hoursString == 0) { hoursString = 12; }
		timeString == hoursString + ":" + minutesString;
	}

	if (inputTimeStyle == "2:00pm") {
		if (hoursString == 0) { timeString = "12:" + minutesString + "am"; }
		if ((hoursString > 0) && (hoursString < 12)) { timeString = hoursString + ":" + minutesString + "am"; }
		if (hoursString == 12) { timeString = "12:" + minutesString + "pm"; }
		if (hoursString > 12) { timeString = (hoursString - 12) + ":" + minutesString + "pm"; }
	}

	if (inputTimeStyle == "2:00 pm") {
		if (hoursString == 0) { timeString = "12:" + minutesString + " am"; }
		if ((hoursString > 0) && (hoursString < 12)) { timeString = hoursString + ":" + minutesString + " am"; }
		if (hoursString == 12) { timeString = "12:" + minutesString + " pm"; }
		if (hoursString > 12) { timeString = (hoursString - 12) + ":" + minutesString + " pm"; }
	}
	
	return timeString;
}


// MONTH NUM TO SHORT NAME FUNCTION

function MonthNumToShortName (whichMonth) {

	if (whichMonth ==  1) return ("jan");
	if (whichMonth ==  2) return ("feb");
	if (whichMonth ==  3) return ("mar");
	if (whichMonth ==  4) return ("apr");
	if (whichMonth ==  5) return ("may");
	if (whichMonth ==  6) return ("jun");
	if (whichMonth ==  7) return ("jul");
	if (whichMonth ==  8) return ("aug");
	if (whichMonth ==  9) return ("sep");
	if (whichMonth == 10) return ("oct");
	if (whichMonth == 11) return ("nov");
	if (whichMonth == 12) return ("dec");
		
	return ("Zeke the Solar Cat");

} // end function month num to short name

// MONTH NUM TO SHORT NAME FUNCTION

function MonthNumToLongName (whichMonth) {

	if (whichMonth ==  1) return (  "January");
	if (whichMonth ==  2) return ( "February");
	if (whichMonth ==  3) return (    "March");
	if (whichMonth ==  4) return (    "April");
	if (whichMonth ==  5) return (      "May");
	if (whichMonth ==  6) return (     "June");
	if (whichMonth ==  7) return (     "July");
	if (whichMonth ==  8) return (   "August");
	if (whichMonth ==  9) return ("September");
	if (whichMonth == 10) return (  "October");
	if (whichMonth == 11) return ( "November");
	if (whichMonth == 12) return ( "December");
		
	return ("Zeke the Solar Cat");

} // end function month num to long name

// MONTH NUM TO DAYS FUNCTION

function MonthNumToDays (whichMonth) {

	if (whichMonth ==  1) return   (0);
	if (whichMonth ==  2) return  (31);
	if (whichMonth ==  3) return  (59);
	if (whichMonth ==  4) return  (90);
	if (whichMonth ==  5) return (120);
	if (whichMonth ==  6) return (151);
	if (whichMonth ==  7) return (181);
	if (whichMonth ==  8) return (212);
	if (whichMonth ==  9) return (243);
	if (whichMonth == 10) return (273);
	if (whichMonth == 11) return (304);
	if (whichMonth == 12) return (334);
		
	return ("Zeke the Solar Cat");

} // end month num to days function

// MONTH STRING TO MONTH NUM FUNCTION

function MonthStringToMonthNum (whichMonth) {

	if (whichMonth ==   "January") return  (1);
	if (whichMonth ==  "February") return  (2);
	if (whichMonth ==     "March") return  (3);
	if (whichMonth ==     "April") return  (4);
	if (whichMonth ==       "May") return  (5);
	if (whichMonth ==      "June") return  (6);
	if (whichMonth ==      "July") return  (7);
	if (whichMonth ==    "August") return  (8);
	if (whichMonth == "September") return  (9);
	if (whichMonth ==   "October") return (10);
	if (whichMonth ==  "November") return (11);
	if (whichMonth ==  "December") return (12);
		
	return ("Zeke the Solar Cat");
	
} // end month string to month num function


// NORMALIZE TO 360 FUNCTION

function NormalizeTo360 (theThing) {

	return (theThing - Math.floor (theThing / 360.0) * 360);

} // end normalize to 360 function


// ARCSIN FUNCTION

function ArcSin (theThing) {

	return (Math.asin (theThing));

} // end arcsin function
	

// ARCCOS FUNCTION

function ArcCos (theThing) {

	return (Math.acos (theThing));

} // end arccos function


// FORMAT FLOAT STRING FUNCTION

function FormatFloatString (theInput) {

// Forces two digits of precision after the decimal point
	
	var negativeNumber = false;
	if (theInput < 0) {
		negativeNumber = true;
		theInput *= -1;
	}

	integerPortion = Math.floor (theInput); 
	decimalPortion = Math.round (theInput * 100) % 100;

	// added 7/17/99 to correct problem with 0.999 being rounded to 0.000 in decimal conversion:
	if ((decimalPortion == 0) && ((theInput - integerPortion) > 0.5)) {
		integerPortion += 1;
	}
	
 	integerPortionString = "" + integerPortion;
        
	if (decimalPortion < 10) decimalPortionString = "0" + decimalPortion;   // add a leading zero if necessary
	else decimalPortionString = "" + decimalPortion;
	
	if (negativeNumber == true) return ("-" + integerPortionString + "." + decimalPortionString);
	else return (integerPortionString + "." + decimalPortionString);

} // end format float string function

