/**
 * js_main.js
 *
 * @author Orion Imaging, LLC, www.orionimaging.net
*/
	
	if (top.location.href!=location.href) top.location.href = top.location.href;
	
	//aveWindSpeedAuto = undefined; // initialize: fixes chrome / safari...

	
	function local()
	{
		if (location.href.substr(0, 17)=='http://127.0.0.1/') return true;
		else return false;
	}


	BASE_PATH = local() ? '/NewRoots.WindReport/' : '/' ;
	DEBUG = 1;


	function isset( varStr )
	// In:  [string] varName is variable to check existence of
	// Out:  [boolean] state of varName's existence
	{
		return (typeof(window[varStr])!='undefined') ? true : false;
	}


	function empty( varStr )
	// In:  [string] varName is variable to check existence of
	// Out:  [boolean] state of varName's existence
	{
		if ( null == varStr || "" == varStr )
		{
			return true;
		}
		return false;
	}


	function print_r( thing, niceHtml, level )
	// See also:
	//	http://binnyva.blogspot.com/2005/10/dump-function-javascript-equivalent-of.html
	//	http://www.brandnewbox.co.uk/logbook/category/Javascript/
	{
		if (!niceHtml) niceHtml = 0;
		if (!level) level = 0;
		
		var dump = '';
		var padding = ''; //pads beginning of line
		for (j=0; j<level+1; j++) padding += '  ';

		if (typeof(thing)=='object')
		{ //Array/Hashes/Objects
			for (var item in thing)
			{
				var value = thing[item];
				if (typeof(value)=='object')
				{ //If it is an array...
					dump += padding + "'" + item + "' ...\n";
					dump += print_r(value, niceHtml, level+1);
				}
				else
				{
					dump += padding + "'" + item + "' => \"" + value + "\"\n";
				}
			}
		}
		else
		{ //Strings/Chars/Numbers etc...
			dump = '['+typeof(thing)+']<<<'+thing+'>>>';
		}
		
		return dump;
	}
	
	
	function explode( sep, str )
	// Use:  mirrors php's explode
	{
		return str.split(sep);
	}
	
	
	function implode( sep, arr )
	// Use:  mirrors php's implode
	{
		var out = arr[0];
		for (var i=1; i<arr.length; ++i) out += sep+arr[i];
		return out;
	}
	
	
	/**
	 * round a number to a certain number of decimals
	 */
	function round ( num, dec )
	{
		return Math.round(num*Math.pow(10, dec)) / Math.pow(10, dec);
	}


	/**
	 * make sure input is in decimal degrees
	 *
	 * @param float an input that should be in decimal degrees
	 * @param float (optional) same as above, etc, etc... (as many args as you like)
	 * @return boolean if ANY of the arguments are not decimal degrees returns false, else returns true
	 */
	function checkDecDegrees ()
	{
		var pattern = /[ ]*[+-]?[0-9]+\.?[0-9]*[ ]*/;
		
		for (var i = 0; i < arguments.length; ++i) {
			if (arguments[i].match(pattern) != arguments[i]) {
				return false;
			}
		}
		
		return true;
	}


	/**
	 * check an email address for suppossed goodness
	 */
	function checkEmailAddr ( emailAddr )
	{
		var pattern = new RegExp('.+@.+\..+');
		if (emailAddr.match(pattern)) {
			return true;
		}
		else {
			return false;
		}
	}


	function toggle_menu( menuId, onOff )
	// In:  [string] menuId is id of menu container div,  [int] onOff is state to toggle to
	// Out:  toggled menu
	{
		//turn off other menus...
		if (!isset('allMenuIds')) allMenuIds = new Array('photoList', 'digimList', 'webdevList', 'aboutOiList');
		
		if (onOff)
		{ //turn things off before on...
			for (i=0; i<allMenuIds.length; ++i)
			{
				if (menuId!=allMenuIds[i])
				{
					document.getElementById(allMenuIds[i]).style.display = 'none';
				}
			}
		}
		
		root = document.getElementById(menuId);
		if (isset('timeOut')) clearTimeout(timeOut);

		if (onOff) root.style.display = 'block';
		else timeOut = setTimeout("root.style.display = 'none'", 400);
		
	}
	
	
	function show_contact_subform ( thisTab, showForm )
	// Use:  toggles contact subforms
	// In:  subform id you'd like to turn on
	// Out:  returns false to kill links
	{
		var formIds = new Array($('generalInquiry'), $('photoInquiry'), $('webDevInquiry'));
		
		formIds.invoke('setStyle', {'display': 'none'});
		$(showForm).style.display = 'block';
		$('formType').value = showForm;
		
		$$('#contactNav a').invoke('setStyle', {'textDecoration': 'none'});
		thisTab.setStyle({'textDecoration': 'underline'});
		thisTab.blur();
		
		return false;
	}
	
	
	function toggle_checkbox ( thisLink )
	// Use:  toggles labeled/linked checkboxes for forms
	// In:  this object from link
	// Out:  returns false to kill links
	{
		if (!thisLink.parentNode) return false;
		
		var i = document.forms[0][thisLink.parentNode.htmlFor];
		if (!i.checked) i.checked = true;
		else i.checked = false;
		
		thisLink.blur();
		return false;
	}
	
	
	function toggle_radiobutton ( thisLink, radioId )
	// Use:  toggles labeled/linked radio button for forms
	// In:  [need to pass id to fix IE]
	// Out:  returns false to kill links
	{
		var i = $(radioId);
		if (!i) return false;
		
		if (!i.checked) i.checked = true;
		else i.checked = false;
		
		thisLink.blur();
		return false;
	}
	
	
	function catch_tab_nav( e, goPage )
	// Use:  does tab / enter navigation
	// In:  e is standard event
	// Note:  this is actually just a dummy function with some verbage, which somehow make IE happy with tab-enter stuffs...
	{
		if (!e) e = window.event;
		if (!e) return;
		else if (e.keyCode==13) location.href = goPage; //13==enter
	}


	function show( elmId, displayType )
	// Use:  to show a particular element by id
	// In:  elmId is the element to show, [optional] displayType is either 'block' or 'inline' or another valid diplay value
	{
		var root = document.getElementById(elmId);
		if (root)
		{
			if (displayType) root.style.display = displayType; //set display...
			else root.style.display = 'block';
			if (displayType) root.style.display = displayType; //set visibility...
			else root.style.visibility = 'visible';
		}
	}
	
	
	function toggle_display( elmId )
	// In:  [string] elmId is id of element to toggle,  [int] onOff is state to toggle to (future dev...)
	// Out:  toggled element
	{
		root = document.getElementById(elmId);
		if (root.style.display=='block' || (arguments.length>1 && !arguments[1])) root.style.display = 'none';
		else root.style.display = 'block';
		return false; //kill link
	}

	
	function toggle_plusminus( elmId, toggleToSrc )
	// In:  [string] elmId is id of element to toggle,  [int] onOff is state to toggle to (future dev...)
	//	[implicit.string]  also inverts plus/minus state of elmId + "_img"
	// Out:  toggled element & inverted plus/minus
	{
		if (!toggleToSrc) var toggleToSrc = 'plus3m1minus1m1.png';
		
		if (document.getElementById(elmId+'_img'))
		{
			imgSrc = document.getElementById(elmId+'_img').src;
			var relSrc = imgSrc.split('/').pop();
			
			if (relSrc != toggleToSrc)
			{ //make minus...
				toggle_display(elmId, 0);
				oldSrc = document.getElementById(elmId+'_img').src; //remember...
				var relSrcRoot = oldSrc.split('/'+relSrc);
				document.getElementById(elmId+'_img').src = relSrcRoot[0]+'/'+toggleToSrc;
			}
			else
			{ //revert to last...
				toggle_display(elmId);
				document.getElementById(elmId+'_img').src = oldSrc;
			}
		}
		return false; //kill link
	}


function lowLight(elm_id)
//USE:  to 'lowlight' text (just bolder [no color change])
//IN:
//OUT:
{
	if (document.getElementById)
	{
		var root = document.getElementById(elm_id);
		weight_holder = root.style.fontWeight;  //sets global var to remember weight
		root.style.fontWeight = "900";
		if (!document.all) root.style.cursor = "pointer";
		else root.style.cursor = "hand";
	}
  return;
}


function lowLightMild(elm_id)
//USE:  to 'lowlight' text    {undelines & changes color to 'whitesmoke' (if not already)
//IN:  elm_id is element id, [color is optional color to highlight to]                 **A milder effect than lowLight()
//OUT:                                                                                **NOTE: use unLowLight() |OR| unLowLightMild() to undo lowLightMild()
{
	if (document.getElementById)
	{
		var root = document.getElementById(elm_id);
		color_holder = root.style.color;  //sets global var to remember element color
		weight_holder = root.style.fontWeight;
		//alert(root.style.textDecoration);
		//if (root.style.textDecoration == "underline") leave_underline = true;  else leave_underline = false;
		//root.style.fontWeight = "bold";
		root.style.textDecoration = "underline";
		if (arguments.length==2) root.style.color = arguments[1];
		else root.style.color = "whitesmoke";
		if (!document.all) root.style.cursor = "pointer"; //pointer
		else root.style.cursor = "hand";
	}
  return;
}


function unLowLight(elm_id)
//USE:  to unhighlight text
//IN:  elm_id is element id
//OUT:
{
	if (document.getElementById)
	{
		var root = document.getElementById(elm_id);
		root.style.fontWeight = weight_holder;
		root.style.textDecoration = "none";
		root.style.cursor = "auto";
	}
  return;
}


function unLowLightMild(elm_id)
//USE:  to unLowLightMild text
//IN:  elm_id is element id
//OUT:
{
	if (document.getElementById)
	{
		var root = document.getElementById(elm_id);
		root.style.textDecoration = "none";
		root.style.color = color_holder;
		root.style.cursor = "auto";
	}
  return;
}


function imageBorder( imageId ) //imageBorder(imageId[, width[, style[, color]]]);
//USE:  to put on, and take off borders, respectively
//IN:  img_name is string for image name, [optional] width, [optional] style, [optional] color
{
	var width = '1px';  var style = 'solid';  var color = '#EEEEEE';
	if (arguments.length>1)
	{
		if (arguments[1]) width = arguments[1];
		if (arguments[2]) style = arguments[2];
		if (arguments[3]) color = arguments[3];
	}
	if (document.getElementById)
	{
		document.getElementById(imageId).style.border = width+' '+style+' '+color;
	}
}
function imageUnborder( imageId ) //imageUnborder(imageId[, width[, style[, color]]]);
{
	var width = '0px';  var style = 'none';  var color = '#000000';
	if (arguments.length>1)
	{
		if (arguments[1]) width = arguments[1];
		if (arguments[2]) style = arguments[2];
		if (arguments[3]) color = arguments[3];
	}
	if (document.getElementById)
	{
		document.getElementById(imageId).style.border = width+' '+style+' '+color;
	}
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin: Ajax things...
//In: [array] images is array of image src's
//Out: fading images, recirculates to [0] image
function AjaxImageShow( images )
{
	//variables...
	var imageCount = 1; //**change this to zero to include first image in array...
	var readyState = 0;
	var responseText = 'Loading...';
	
	//properties...
	this.images = images;
	this.fadeSpeed = 9; //25;
	this.fadeStepSize = 1; //3;
	
	//methods...
	this.nextImage = nextImage;

	function nextImage( target )
	// Use:  nextImage(target)
	//*Note:  remember to set the global 'imageShell' if you need a different container (where imageShell is the server-side image container)
	{
		if (!imageShell) imageShell = 'images/image_ajax.php';
		
		//set globals, avoid loss of scope...
		fadeSpeed = this.fadeSpeed;
		fadeStepSize = this.fadeStepSize;
		if (imageCount>=this.images.length) imageCount = 0; //reset the show...

		var xmlHttp = (window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
		if (xmlHttp)
		{ //ajax is go...
			var content = imageShell+'?image='+this.images[imageCount];
			xmlHttp.open("GET", content, true); 
			xmlHttp.send(null);
			xmlHttp.onreadystatechange = function()
			{
				if (xmlHttp.readyState==4)
				{
					if (xmlHttp.status=='200')
					{
						imageABFadeByContainer(target, fadeSpeed, fadeStepSize, xmlHttp.responseText); //AB-fade images...
					}
					else replaceById('** Error loading object', target);
					
					++imageCount;
				}
			}
		}
		
		return;
	} //end method: nextImage;

} //end class: AjaxImageShow();


function imageABFadeByContainer( target, fadeSpeed, fadeStepSize, responseText )
// Use:  fades one image into another
{
	if (!imageShell) var imageShell = false;
	imageFadeByContainer(target, 'out', fadeSpeed, fadeStepSize, 1, responseText); //fading out image & swap...
	
	//replaceById(responseText, target);
	//setOpacityByContainer(target, 0);
	
	//imageFadeByContainer(target, 'in', fadeSpeed, fadeStepSize, 1); //fade in image...
} //end function: imageABFadeByContainer();


function ajaxFile( content, target ) //ajaxFile(content, target[, int spaceBefore, int spaceAfter])
{
	var readyState = 0;
	var responseText = '';
	var spaceBefore = 0;  var spaceAfter = 0; //for padding the in-between animation...
	if (arguments.length>2)
	{
		if (arguments[2].substr(0,12)=='spaceBefore=') spaceBefore = arguments[2].substr(12);
		if (arguments[3].substr(0,11)=='spaceAfter=') spaceAfter = arguments[3].substr(11);
	}

	var xmlHttp = (window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
	xmlHttp.open("GET", content, true); //get new doc...
	xmlHttp.send(null);
	
	//might be in cache...
	//replaceById('<p><br />&nbsp;<br />Hello: '+xmlHttp.status+'</p>', target); //**debug
	try { if (xmlHttp.readyState && xmlHttp.status=='200') replaceById(xmlHttp.responseText, target); }
	catch (e) {}
	
	xmlHttp.onreadystatechange = function()
	{
		//alert('readyState == '+readyState);
		readyState = xmlHttp.readyState;
		if (readyState==4)
		{
			if (xmlHttp.status=='200') responseText = xmlHttp.responseText;
			else responseText = '**Error loading object';
			replaceById(responseText, target);
		}
	}
	return;
} //end function: ajaxFile();


function getOpacityByContainer( target ) //opacity := [0,100]
{
	var opacity = '';
	target = document.getElementById(target); //.getElementsByTagName('img')[0];
	
	if (target.style.MozOpacity!=undefined && target.style.MozOpacity!='')
	 opacity = target.style.MozOpacity*100;
	else if (target.style.KhtmlOpacity!=undefined)
	 opacity = target.style.KhtmlOpacity*100;
	else if (target.filters && target.filters.alpha!=undefined)
	 opacity = target.filters.alpha.opacity;
	else if (target.style.opacity!=undefined && target.style.opacity!='')
	 opacity = target.style.opacity*100;
	else opacity = 100;

	return opacity;
} //end method: getOpacityByContainer();


function setOpacityByContainer( target, opacity ) //opacity := [0,100]
{
	target = document.getElementById(target); //.getElementsByTagName('img')[0];
	target.style.opacity = opacity/100;
	target.style.MozOpacity = opacity/100;
	target.style.KhtmlOpacity = opacity/100;
	target.style.filter = 'alpha(opacity='+opacity+')';
	//alert('target.filters.alpha.opacity == '+target.filters.alpha.opacity);
} //end method: setOpacityByContainer();


function imageFadeByContainer( target, inOut, fadeSpeed, fadeStepSize, offset, responseText )
 //imageFadeByContainer(target, inOut[, fadeSpeed[, fadeStepSize]])
// In:  [optional int] offset is for AB-fading an image in after fading out a previous one
{
	if (!fadeSpeed) var fadeSpeed = 25;
	if (!fadeStepSize) var fadeStepSize = 3;
	if (!offset) var offset = 0;  else var offset = 1;
	if (!responseText) var responseText = '** Error: no responseText';
	if (!offset) var offset = 0;  else var offset = 1;
	if (!imageShell) var imageShell = false;

	var opacity = getOpacityByContainer(target);
	var timerCount = 0;
	var count = 0;
	fadeId = new Array(); //global array for holding setTimeout id's...

	if (inOut=='in')
	{ //fade image in...
		if (offset)
		{
			replaceById(responseText, target);
			setOpacityByContainer(target, 0);
			opacity = 0;
		}

		do
		{
			if (offset) timeOffset = countPrevious*fadeSpeed; // * (fadeSpeed*timerCount) / 2;
			else timeOffset = 0;
			
			opacity = Math.min(100, opacity+fadeStepSize/1.5);
			fadeId[count] = setTimeout('setOpacityByContainer(\''+target+'\', '+opacity+')', (fadeSpeed*timerCount)+timeOffset);
			++timerCount;
			++count;
		}
		while (opacity<100);
		
		if (offset)
		{ //initiate next slide...
			setTimeout("imageShow.nextImage('"+target+"')", timeBetweenSlides + (fadeSpeed*timerCount) + timeOffset);
		}
	}
	else
	{ //fade image out...
		do
		{
			opacity = Math.max(0, opacity-fadeStepSize);
			fadeId[count] = setTimeout('setOpacityByContainer(\''+target+'\', '+opacity+')', fadeSpeed*timerCount);
			
			//if (offset && opacity<5) break;
			
			++timerCount;  ++count;
		} while (opacity>0);

		if (offset)
		{ //replace image once faded out, then fade in the next...
			//fadeId[count] = setTimeout("replaceById('"+responseText+"', '"+target+"')", fadeSpeed*(timerCount));
			//fadeId[count+1] = setTimeout("setOpacityByContainer('"+target+"', 0)", fadeSpeed*(timerCount+1));
			fadeId[count] = setTimeout("imageFadeByContainer('"+target+"', 'in', '"+fadeSpeed+"', '"+fadeStepSize+"', 1, '"+responseText+"')", fadeSpeed*(timerCount)); //fade in image...
		}
		
		countPrevious = count; //*Note: global
	}

} //end function: imageFade();


function replaceById(content, target)
{
	if (document.getElementById)
	{
		document.getElementById(target).innerHTML = content;
		return true;
	}
	return false;
} //end function: replaceById();


//flash video things...
function getFlashMovieObject( movId )
{
	if (document.embeds && document.embeds[movId])
	{
		return document.embeds[movId];
	}
	  
	else if (document.getElementById(movId))
	{
		return document.getElementById(movId);
	}
	
	else return false;

/* //inspired by the following (found on the net @ http://www.permadi.com/tutorial/flashjscommand/)...
  if (window.document[movieName]) 
  {
      return window.document[movieName];
  }
  if (navigator.appName.indexOf("Microsoft Internet")==-1)
  {
    if (document.embeds && document.embeds[movieName])
      return document.embeds[movieName]; 
  }
  else // if (navigator.appName.indexOf("Microsoft Internet")!=-1)
  {
    return document.getElementById(movieName);
  }
*/
}


function SendDataToFlashMovie( movId, command )
{
    var movie = getFlashMovieObject(movId);
    if (!movie) alert('No movie.');
	else movie.SetVariable("/:message", command);
}


function StopFlashMovie( movId )
{
	var movie = getFlashMovieObject(movId);
    if (!movie) alert('No movie.');
	else movie.StopPlay();
}


function PlayFlashMovie( movId )
{
	var movie = getFlashMovieObject(movId);
    if (!movie) alert('No movie.');
	else movie.Play();
	//embed.nativeProperty.anotherNativeMethod();
}


// slideshowpro methods
function flashPutHref(href) {
	location.href = href; // Permalinks option
}
function toggleDisplayMode() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').toggleDisplayMode(null);
}
function loadAlbum(albumID,num) {
	thisMovie(arguments.length > 2 ? arguments[2] : 'ssp').loadAlbum(albumID,num);
}  
function loadImageNumber(num) {
	thisMovie(arguments.length > 1 ? arguments[1] : 'ssp').loadImageNumber(num);
	/*
	if (arguments.length > 2 && arguments[2])
	{
		thisMovie(arguments.length > 1 ? arguments[1] : 'ssp').previousImage();
		thisMovie(arguments.length > 1 ? arguments[1] : 'ssp').toggleDisplayMode(null);
	}
	*/
}
function nextGalleryScreen() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').nextGalleryScreen();
}
function nextImage() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').nextImage();
	if (arguments.length > 1 && arguments[1])
	{
		thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').previousImage();
		toggleDisplayMode(arguments.length > 0 ? arguments[0] : 'ssp');
	}
}
function nextImageGroup() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').nextImageGroup();
}
function previousGalleryScreen() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').previousGalleryScreen();
} 
function previousImage() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').previousImage();
	/*
	if (arguments.length > 1 && arguments[1])
	{
		thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').previousImage();
		toggleDisplayMode(arguments.length > 0 ? arguments[0] : 'ssp');
	}
	*/
}  
function previousImageGroup() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').previousImageGroup();
}
function setSize(w,h) {
	thisMovie(arguments.length > 2 ? arguments[2] : 'ssp').setSize(w,h);
}  
function toggleGallery() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').toggleGallery();
}
function toggleNav() {
	thisMovie(arguments.length > 0 ? arguments[0] : 'ssp').toggleNav();
}

// NRE: make sure only one NY incentive is chosen...
function checkNyIncentives ( elm )
{
	if (elm['id'] == 'incentiveUseNyLipa')
	{
		if ($('incentiveUseNyLipa').value == 1) $('incentiveUseNyserda').value = 0;
	}
	else
	{
		if ($('incentiveUseNyserda').value == 1) $('incentiveUseNyLipa').value = 0;
	}
}

/**
 * NRE: check ITC loan reduction settings...
 */
function checkItcLoanReduction ( elm )
{
	if ($('loanItcReduction').value == 1)
	{
		if ($('itcTimePeriod').value != 1)
		{
			alert('When reducing your loan by the ITC, you must use the ITC in the first year.');
		}
		$('itcTimePeriod').value = 1;
	}
	checkItcAsGrant(elm);
}

/**
 * NRE: check ITC / grant loan reduction settings...
 */
function checkItcAsGrant ( elm )
{
	if ($('itcAsGrant').value == 1)
	{
		if ($('itcTimePeriod').value != 1)
		{
			alert('When choosing a grant instead of the ITC, the ITC is set to be used in the first year.');
		}
		$('itcTimePeriod').value = 1;
	}
}

/**
 * NRE: check finance model time span vs. loan time span settings...
 */
function checkLoanTimeSpan ( elm )
{
	if ($('loanFinancing').value == 1 && $('loanPeriod').value*1 > $('timeSpan').value*1) // the *1 is type cast...
	{
		alert('The time span of the model is being adjusted to include the full amortization period of the loan.');
		$('timeSpan').value = $('loanPeriod').value;
	}
}

/**
 * NRE: save model description
 */
function saveModelParam ( thisForm )
{
	// post some info...
	var url = local() ? 'http://127.0.0.1/NewRoots.WindReport/model/saved-sessions' : 'http://windreport.newrootsenergy.com/model/saved-sessions';
	
	new Ajax.Request( url,
		{
			method: 'post',
			parameters: {
				'model_id': thisForm.model_id.value,
				'user_id': thisForm.user_id.value,
				'param': thisForm.param.value,
				'value': thisForm.value.value
			},
			onSuccess: function (transport) {
				thisForm.elements[1].fade({ duration: 0.5 });
			},
			onFailure: function (transport) {
				thisForm.elements[1].replace('Failed');
			}
		}
	); 
	return false;
}

/**
 * NRE: update save button visibility
 */
function saveModelParamButton ( thisForm )
{
	if (thisForm.elements[1].style.display == 'none')
	{
		thisForm.elements[1].appear({ duration: 0.5 });
	}
	return;
}

/**
 * NRE: delete model from user's view
 */
function saveModelDelete ( modelId, userId, rowId )
{
	var go = confirm('Are you sure you would like to delete this record?');
	
	if (!go)
	{
		return false;
	}
	
	// post some info...
	var url = local() ? 'http://127.0.0.1/NewRoots.WindReport/model/saved-sessions' : 'http://windreport.newrootsenergy.com/model/saved-sessions';
	
	new Ajax.Request( url,
		{
			method: 'post',
			parameters: {
				'action': 'delete',
				'model_id': modelId,
				'user_id': userId
			},
			onSuccess: function (transport) {
				try
				{
					$(rowId).fade({ duration: 0.5 });
				}
				catch (err)
				{
					location.href = location.href;
				}
			},
			onFailure: function (transport) {
				alert('Transport failed.');
			}
		}
	); 
	return false;
}

// swf finder
function thisMovie(movieName) {
	if (navigator.appName.indexOf("Microsoft") != -1) {
		return window[movieName]
	} else {
	    return document[movieName]
	}
}

// form handling
function submitOnEnter (thisInput, e)
{
	var keycode;
	if (window.event) keycode = window.event.keyCode;
	else if (e) keycode = e.which;
	else return true;

	if (keycode == 13)
	{
		thisInput.form.submit();
		return false;
	}
	else return true;
}


// do things
function setSemiTrans ( target )
{
	//var (!opacity) ? opacity = 50 : opacity = argument[1];
	var opacity = 70;
	setOpacityByContainer( target, opacity )
}

function releaseSemiTrans ( target )
{
	var opacity = 100;
	setOpacityByContainer( target, opacity )
}


/**
 * display working state (ie: show a lil' moving graphic)
 *
 * @param boolean optional display is true to turn on (default), false to turn off
 */
function working ( display )
{
	var messages = $('messages');
	if (display == false)
	{
		//messages.fade({ duration: 0.5 });
		messages.style.display = 'none';
		messages.update('');
	}
	else
	{
		$('messages').update('Working...<img src="' + BASE_PATH + 'images/loadingIndicator_teardropCircleChasing_777799-FFFFFF-1.gif"/>');
		messages.appear({ duration: 0.25 });
	}
}


/**
 * convert meters to feet
 *
 * @param float $windSpeed is windspeed in meters per second
 * @returns float wind speed in miles per hour
 */
function m2ft ( distance )
{
	return distance * 3.2808399;
}


/**
 * convert feet to meters
 *
 * @param float $distance is distance in feet
 * @returns float distance in meters
 */
function ft2m ( distance )
{
	return distance / 3.2808399;
}


/**
 * convert meters per second to miles per hour
 *
 * @param float $speed is speed in meters per second
 * @returns float speed in miles per hour
 */
function mps2mph ( speed )
{
	return speed * 2.23694;
}


/**
 * convert miles per hour to meters per second
 *
 * @param float $speed is speed in miles per hour
 * @returns float speed in meters per second
 */
function mph2mps ( speed )
{
	return speed / 2.23694;
}


/**
 * get some wind speed data
 */
function addr2wind ( address, state, zip, height )
{
	// check yoself...
	var error = Array();
	if ($('addrCoorOverride').checked)
	{
		if (!$('addrLat')) error.push('latitude');
		if (!$('addrLon')) error.push('longitude');
	}
	else
	{
		if (empty(address)) error.push('address');
		if (empty(state)) error.push('state');
		if (empty(zip)) error.push('zip code');
		if (empty(height)) error.push('tower height');
	}
	
	if (error.length > 0)
	{
		alert('To use the auto-set wind speed feature, please enter values for the ' + error.join(', ') + ' field' + (error.length > 1 ? 's' : '') + '.');
		return false;
	}
	
	// tower height needs special treatment (min of 20m, max of 80m)...
	height = Math.min(80, Math.max(20, ft2m(height)));
	
	// prepare the request...
	working();
	if ($('addrCoorOverride').checked) // ie: non-geocoder...
	{
		new Ajax.Request(BASE_PATH + 'model/request', {
			method: 'post',
			parameters: { 'action': 'coors2wind', 'lat': $('addrLat').value, 'lon': $('addrLon').value, 'height': height },
			onSuccess: function(transport) {
				working(0);
				//alert('addr2wind() success.\n' + transport.responseText);
				var response = transport.responseText.evalJSON();
				if (!response) alert('Failed request coors2wind.');
				else if (response.error) alert(response.error);
				else
				{
					$('aveWindSpeed').value = round(mps2mph(response.mean), 2);
					if ($('autoWindSpeedEnabled'))
					{
						$('autoWindSpeedEnabled').value = 1;
						anemomShow(0);
					}
					//$('addrLat').value = response.lat;
					//$('addrLon').value = response.lon;
					
					// hidden fields (values f/ disabled inputs)...
					if ($('addrLat').disabled)
					{
						var elm = new Element('input', { 'id': 'addrLatHidden', 'name': 'addrLat', 'type': 'hidden', 'value': response.lat });
						$('addrLat').insert({ 'before': elm });
						var elm = new Element('input', { 'id': 'addrLonHidden', 'name': 'addrLon', 'type': 'hidden', 'value': response.lon });
						$('addrLon').insert({ 'before': elm });
					}
					else
					{
						$('addrLatHidden').remove();
						$('addrLonHidden').remove();
					}
				}
			},
			onFailure: function(transport) {
				working(0);
				alert('addr2wind() failed. \n' + (DEBUG ? transport.responseText : ''));
			}
		});
	}
	else // non geo-coor override (uses geocoder)...
	{
		new Ajax.Request(BASE_PATH + 'model/request', {
			method: 'post',
			parameters: { 'action': 'addr2wind', 'address': address, 'state': state, 'zip': zip, 'height': height },
			onSuccess: function(transport) {
				working(0);
				//alert('addr2wind() success.\n' + transport.responseText);
				var response = transport.responseText.evalJSON();
				if (!response) alert('Failed request addr2wind.');
				else if (response.error) alert(response.error);
				else
				{
					$('aveWindSpeed').value = round(mps2mph(response.mean), 2);
					if ($('autoWindSpeedEnabled'))
					{
						$('autoWindSpeedEnabled').value = 1;
						anemomShow(0);
					}
					$('addrLat').value = response.lat;
					$('addrLon').value = response.lon;
					
					// hidden fields (values f/ disabled inputs)...
					if ($('addrLat').disabled)
					{
						var elm = new Element('input', { 'id': 'addrLatHidden', 'name': 'addrLat', 'type': 'hidden', 'value': response.lat });
						$('addrLat').insert({ 'before': elm });
						var elm = new Element('input', { 'id': 'addrLonHidden', 'name': 'addrLon', 'type': 'hidden', 'value': response.lon });
						$('addrLon').insert({ 'before': elm });
					}
					else
					{
						$('addrLatHidden').remove();
						$('addrLonHidden').remove();
					}
				}
			},
			onFailure: function(transport) {
				working(0);
				alert('addr2wind() failed. \n' + (DEBUG ? transport.responseText : ''));
			}
		});
	}
}


/**
 * geocode an address:  using geocoder.us
 */
function addr2coors ( address, state, zip )
{
	// check yoself...
	var error = Array();
	if (empty(address)) error.push('address');
	if (empty(state)) error.push('state');
	if (empty(zip)) error.push('zip code');
	
	if (error.length > 0)
	{
		alert('To use the auto-set coordinates feature, please enter values for the ' + error.join(', ') + ' field' + (error.length > 1 ? 's' : '') + '.');
		return false;
	}
	
	// prepare the request...
	working();
	new Ajax.Request(BASE_PATH + 'model/request', {
		method: 'post',
		parameters: { 'action': 'addr2coors', 'address': address, 'state': state, 'zip': zip },
		onSuccess: function(transport) {
			working(0);
			var response = transport.responseText.evalJSON();
			if (!response) alert('Failed request addr2coors.');
			else if (response.error) alert(response.error);
			else {
				$('addrLat').value = response.lat;
				$('addrLon').value = response.lon;
				
				// hidden fields (values f/ disabled inputs)...
				if ($('addrLat').disabled)
				{
					var elm = new Element('input', { 'id': 'addrLatHidden', 'name': 'addrLat', 'type': 'hidden', 'value': response.lat });
					$('addrLat').insert({ 'before': elm });
					var elm = new Element('input', { 'id': 'addrLonHidden', 'name': 'addrLon', 'type': 'hidden', 'value': response.lon });
					$('addrLon').insert({ 'before': elm });
				}
				else
				{
					$('addrLatHidden').remove();
					$('addrLonHidden').remove();
				}
			}
		},
		onFailure: function(transport) {
			working(0);
			alert('addr2coors() failed. \n' + (DEBUG ? transport.responseText : ''));
		}
	});
}


/**
 * handle what to do when clicking geo coordinate override on/off
 */
function coorOverride ()
{
	
	if (window.addrLatAuto == undefined)
	{
		window.addrLatAuto = '';
		window.addrLonAuto = '';
	}
	
	// engage coor direct input...
	if ($('addrCoorOverride').checked)
	{
		// lat values...
		$('addrLat').disabled = false;
		$('addrLat').removeClassName('disabled');
		
		if ($('addrLatHidden'))
		{
			window.addrLatAuto = $('addrLatHidden').value;
			$('addrLatHidden').remove();
		}
		else if ($('addrLat').value != '')
		{
			window.addrLatAuto = $('addrLat').value;
		}
		
		
		// lon values...
		$('addrLon').disabled = false;
		$('addrLon').removeClassName('disabled');
		
		if ($('addrLonHidden'))
		{
			window.addrLonAuto = $('addrLonHidden').value;
			$('addrLonHidden').remove();
		}
		else if ($('addrLon').value != '')
		{
			window.addrLonAuto = $('addrLon').value;
		}
		
		// handle non-empty manual coors in memory...
		if (window.addrLatManual)
		{
			$('addrLat').value = window.addrLatManual;
		}
		if (window.addrLonManual)
		{
			$('addrLon').value = window.addrLonManual;
		}
		
		// update 'set location' button...
		if ($('windSpeedOverride').checked) {
			$('autoLatLon-element').fade({ 'duration': 0.2 });
		}
		else {
			$('autoLatLon-element').appear({ 'duration': 0.2 });
			$('autoLatLon').value = 'Get Location & Wind Speed';
			$('autoLatLon').title = 'Get Location & Wind Speed';
		}
		
		//if ($('autoLatLon-element')) $('autoLatLon-element').fade({ 'duration': 0.2 });
		//else if ($('autoLatLonFinance')) $('autoLatLonFinance').fade({ 'duration': 0.2 });
	}
	else // ie: auto-set coors by geocode (note that hidden elms are also added w/ addr2coors...
	{
		if ($('addrLatHidden')) $('addrLatHidden').remove();
		if ($('addrLonHidden')) $('addrLonHidden').remove();
		
		// remember these, then clear them (handles starting page view with non-auto, then flipping auto on & off)...
		if ($('addrLat').value != '')
		{
			window.addrLatManual = $('addrLat').value;
			$('addrLat').value = '';
		}
		if ($('addrLon').value != '')
		{
			window.addrLonManual = $('addrLon').value;
			$('addrLon').value = '';
		}
		
		$('addrLat').disabled = true;
		$('addrLat').addClassName('disabled');
		$('addrLat').value = window.addrLatAuto;
		var elm = new Element('input', { 'id': 'addrLatHidden', 'name': 'addrLat', 'type': 'hidden', 'value': window.addrLatAuto });
		$('addrLat').insert({ 'before': elm });
		
		$('addrLon').disabled = true;
		$('addrLon').addClassName('disabled');
		$('addrLon').value = window.addrLonAuto;
		var elm = new Element('input', { 'id': 'addrLonHidden', 'name': 'addrLon', 'type': 'hidden', 'value': window.addrLonAuto });
		$('addrLon').insert({ 'before': elm });
		
		// update 'set location' button...
		if (!$('windSpeedOverride').checked) {
			$('autoLatLon-element').appear({ 'duration': 0.2 });
			$('autoLatLon').value = 'Get Location & Wind Speed';
			$('autoLatLon').title = 'Get Location & Wind Speed';
		}
		else {
			$('autoLatLon-element').appear({ 'duration': 0.2 });
			$('autoLatLon').value = 'Get Location';
			$('autoLatLon').title = 'Get Location';
		}
		
		//if ($('autoLatLon-element')) $('autoLatLon-element').appear({ 'duration': 0.2 });
		//else if ($('autoLatLonFinance')) $('autoLatLonFinance').appear({ 'duration': 0.2 });
	}
}


/**
 * handle what to do when clicking wind speed override on/off
 */
function windSpeedOverride ()
{
	if (!window.aveWindSpeedAuto || window.aveWindSpeedAuto == undefined)
	{
		window.aveWindSpeedAuto = '';
	}
	
	if ($('windSpeedOverride').checked)
	{
		anemomShow();
		$('aveWindSpeed').enable(); //.disabled = false; // yea, more cross-browser fixes (chrome / safari)...
		$('aveWindSpeed').removeAttribute('disabled');
		$('aveWindSpeed').removeClassName('disabled');
		
		if ($('aveWindSpeedHidden'))
		{
			window.aveWindSpeedAuto = $('aveWindSpeedHidden').value;
			$('aveWindSpeedHidden').remove();
		}
		else if ($('aveWindSpeed').value != '')
		{
			window.aveWindSpeedAuto = $('aveWindSpeed').value;
		}
		
		// update 'set location' button...
		if ($('addrCoorOverride').checked) {
			$('autoLatLon-element').fade({ 'duration': 0.2 });
		}
		else {
			$('autoLatLon-element').appear({ 'duration': 0.2 });
			$('autoLatLon').value = 'Get Location';
			$('autoLatLon').title = 'Get Location';
		}
		
		// handle non-empty manual coors in memory...
		if (window.aveWindSpeedManual)
		{
			$('aveWindSpeed').value = window.aveWindSpeedManual;
		}
		
		//if ($('autoLatLon-element')) $('autoLatLon-element').fade({ 'duration': 0.2 });
	}
	else // ie: auto-set wind speed by geocode (note that hidden elms are also added w/ addr2coors...
	{
		anemomShow(0);
		
		if ($('aveWindSpeed').value != '')
		{
			window.aveWindSpeedManual = $('aveWindSpeed').value;
			$('aveWindSpeed').value = '';
		}
		
		//$('aveWindSpeed').disabled = true; // yea, more cross-browser fixes (chrome / safari)...
		$('aveWindSpeed').disable(); //.disabled = false; // yea, yea, more cross-browser fixes (chrome / safari)...
		//$('aveWindSpeed').setAttribute('disabled', 'disabled');
		$('aveWindSpeed').addClassName('disabled');
		$('aveWindSpeed').value = window.aveWindSpeedAuto;
		var elm = new Element('input', { 'id': 'aveWindSpeedHidden', 'name': 'aveWindSpeed', 'type': 'hidden', 'value': window.aveWindSpeedAuto });
		$('aveWindSpeed').insert({ 'before': elm });
		
		// update 'set location' button...
		if (!$('addrCoorOverride').checked) {
			$('autoLatLon-element').appear({ 'duration': 0.2 });
			$('autoLatLon').value = 'Get Location & Wind Speed';
			$('autoLatLon').title = 'Get Location & Wind Speed';
		}
		else {
			$('autoLatLon-element').appear({ 'duration': 0.2 });
			$('autoLatLon').value = 'Get Wind Speed';
			$('autoLatLon').title = 'Get Wind Speed';
		}
		
		//if ($('autoLatLon-element')) $('autoLatLon-element').appear({ 'duration': 0.2 });
	}
}


/**
 * show the anemometer height fields
 *
 * @param boolean optional false will hide the fields, else show the fields
 */
function anemomShow ()
{
	if (arguments.length > 0 && arguments[0] == 0)
	{
		$('anemometerHeight-label').hide(); // fixes browsers other than FF & IE...
		$('anemometerHeight-element').hide();
		//$('anemometerHeight-label').fade({ duration: 0.2 });
		//$('anemometerHeight-element').fade({ duration: 0.2 });
	}
	else
	{
		$('anemometerHeight-label').show(); // fixes browsers other than FF & IE...
		$('anemometerHeight-element').show();
		//$('anemometerHeight-label').appear({ duration: 0.2 });
		//$('anemometerHeight-element').appear({ duration: 0.2 });
	}
}


function addListeners ()
{
	$$('.semiTransOver').each( function (e) {
			e.observe('mouseover', function () {
					e.id = e.identify();
					setSemiTrans(e.id);
					$(e.id).setStyle({'cursor': 'pointer'});
					//alert('hmm = '+e.id);
				}
			);
			e.observe('mouseout', function () {
					releaseSemiTrans(e.id);
				}
			);
		}
	);
	
	$$('.activateNav').each( function (e) {
			e.observe('mouseover', function () {
					window.clearTimeout(window.navAdmin);
					show('navAdmin');
				}
			);
			e.observe('mouseout', function () {
					window.navAdmin = show.delay(0.21, 'navAdmin', 'none');
				}
			);
			$('navAdmin').observe('mouseout', function () {
					window.navAdmin = show.delay(0.21, 'navAdmin', 'none');
				}
			);
			$('navAdmin').observe('mouseover', function () {
					window.clearTimeout(window.navAdmin);
					show('navAdmin');
				}
			);
		}
	);
	
	$$('.tooltip.clickable').each( function (e) {
			e.observe('click', function () {
					if (this.getAttribute('target') === '_blank') window.open(this.getAttribute('href'), '_blank');
					else window.location = this.getAttribute('href');
				}
			);
		}
	);
	
	$$('.emailUserCreds').each( function (e) {
			e.observe('click', function () {
				emailUserButtonElm = this; // *global state
				var rel = this.getAttribute('rel');
				rel = explode('::', rel);
				var uid = rel[0];
				var email = rel[1];
				
				if (!checkEmailAddr(email)) {
					alert('The email address "'+email+'" does not appear to be valid.');
					return;
				}
				
				var confirmed = confirm('Email this user\'s credentials to "'+email+'"?');
				
				if (confirmed) {
					try {
						new Ajax.Request(BASE_PATH + 'admin/ajax-email-creds', {
							method: 'post',
							parameters: { 'uid': uid },
							onSuccess: function (transport) {
								emailUserButtonElm.fade({ duration: 0.2 });
							},
							onFailure: function(transport) {
								alert('Transport failure:\nSorry, an error has occurred when sending this request.');
							}
						});
					}
					catch (e) {
						alert('Sorry, an error has occurred when preparing this request.');
					}
				}
				else {
					// nothing... alert('Nothing done!');
				}
			});
		}
	);
	
	if ($('userInfoForm')) // remind admins to save changes...
	{
		/*
		$('userInfoForm').observe('keyup', function (e) {
				if (e.which == 17 || e.which == 18) { // ctrl(17) and alt(18)
					return;
				}
				show('saveChanges');
			}
		);
		$$('#userInfoForm input').each( function (e) {
				e.observe('keydown', function (e) {
						alert('down = '+e);
					}
				);
				e.observe('keyup', function (e) {
						alert('up = '+e.value);
					}
				);
			}
		);
		*/
		
		$$('#userInfoForm a, #userInfoForm input, #userInfoForm select').each( function (e) {
				e.observe('change', function () {
						show('saveChanges');
					}
				);
			}
		);
	}
	
	/*
	if ($('modelInputs')) // run model when user hits enter...
	{
		$$('#modelInputs input[type=text]').each(function (e) { // this fires AFTER the observe click on #autoLatLon
			e.observe('keyup', function (e) {
				if (e.which == 13) {
					//Event.stop(e);
					//alert('aha!');
					//$('modelInputs').submit();
				}
			});
		});
	}
	*/
	
	// Bergey-specific resale value...
	if ($$('.bergey #totalCost').length > 0 && $$('.bergey #resaleValue').length > 0)
	{
		$$('.bergey #totalCost')[0].observe('keyup', function () {
				$$('.bergey #resaleValue')[0].value = round(this.value * 0.3, 2);
			}
		);
		/*
		$$('.bergey #totalCost')[0].observe('blur', function () {
				alert('End-of-life resale value has been updated to 30% of the total system cost.');
			}
		);
		*/
	}
	
	/* Bergey-specific anemometer height (this is invisible for Bergey users, so auto-update anemometer height = 2/3 * tower height)...
	if ($$('.bergey #towerHeight'))
	{
		$('towerHeight').observe('keyup', function (e) {
			$('anemometerHeight').value = this.value * 2 / 3;
		});
	}
	*/
	
	if ($('messages'))
	{
		$('messages').setStyle({ display: 'none' });
		
		document.observe('scroll', function (e) {
				var offsets = document.viewport.getScrollOffsets();
				$('messages').setStyle({ 'top': offsets[1] + 'px' });
			}
		);
	}
	
	if (isset('enableTooltips'))
	{
		enableTooltips();
	}
	
} // end: addListeners();


document.observe('dom:loaded', function () {

		$('anemometerHeight-label').hide(); // fixes browsers other than FF & IE...
		$('anemometerHeight-element').hide();
		
		addListeners();
	}
);

