///////////////////////////////////////////////////
//         THIS IS A SHARED FILE
//
//         THIS IS A SHARED FILE
//
//         THIS IS A SHARED FILE
///////////////////////////////////////////////////

//  *check-Web Generic Scripts
//  Author: Geoffrey Elliott

if (window.navigator.userAgent.toLowerCase().indexOf('msie') != -1) navigator.org = "microsoft";
var classVar = (navigator.org == "microsoft") ? "className" : "class";

var storedRowHeights;
var hiddenFrameHeights = '0,0,0,0,100';

function showUpdateAccountFrame(frameUrl){
	if(top.$('#checkFrameset').attr('rows') != hiddenFrameHeights){
		storedRowHeights = top.$('#checkFrameset').attr('rows');
		top.loginUpdate.location.href = frameUrl;
		top.$('#checkFrameset').attr('rows', hiddenFrameHeights);
	}
}

function hideUpdateAccountFrame(){
	top.$('#checkFrameset').attr('rows', storedRowHeights);
}

//	Regular Expressions from NetContinuum

var re1 = /([^[:alnum:]_\<])(getopt|exec|system|eval|fork)(\x20|\x09|\x0d|%0a)*\(.*\)/gim;
var re2 = /getopt|exec|system|eval|fork/gim;

function filterNetContinuumStrings(field) {
	var fieldString = field.val();
	// console.log(field.attr('id') + " value=" + fieldString + " | match: " + fieldString.match(re1));
	var matchArray = re1.exec(fieldString);
	if(matchArray) {
		//alert(field.attr('id') + " matched unix-shell-command-substrings.")
		for(var i=0; i<matchArray.length; i++) {
			console.log("Matched the string " + matchArray[i]);
			fieldString = fieldString.replace(matchArray[i], matchArray[i].slice(0,1) + "@@" + matchArray[i].slice(1));
		}
	}
	
	return fieldString;
}


function removeNCPlaceholders(field) {
	var fieldString = field.val();
	fieldString = fieldString.replace(/@@/, "");
	return fieldString;
}


// Firebug fix for unsupported browsers (everything but Firefox for now)

if (!window.console || !console.firebug)
{
  var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
  "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

  window.console = {};
  for (var i = 0; i < names.length; ++i)
    window.console[names[i]] = function() {}
}


// array prototype to allow for simple insertion of new value/object
Array.prototype.insert = function(newValue, position)
{
  if(typeof position == "number" && position > -1)
    this.splice(position, 0, newValue);
  else
    this.push(newValue);
}


// array prototype to implement indexOf() for lagging browsers
if(!Array.indexOf) {
  Array.prototype.indexOf = function(obj)
	{
    for(var i=0; i<this.length; i++){
      if(this[i]==obj){
        return i;
      }
    }
    return -1;
  }
}

//  String prototype to allow for simple indexOf check
String.prototype.includes = function(subString)
{
  return (this.indexOf(subString) >= 0);
}


//	removeCommas ::

function removeCommas( strValue ) {
  var objRegExp = /,/g; //search for commas globally
  //replace all matches with empty strings
  return strValue.replace(objRegExp,'');
}


//  checkForEnter - given an event, checks to set if the key pressed was "enter"

function checkForEnter(evt) {
    evt = (evt) ? evt : event;
    var charCode = (evt.which) ? evt.which : evt.keyCode;
    //If user pressed the Enter/Return key...
    return (charCode == 13 ) ? true: false;
}

//  createDialog - opens a dialog window with the given properties to a given URL

function createDialog(url, type, dialogWidth, maxHeight) {
  if(typeof currentDialog != "undefined" && currentDialog !== null && !currentDialog.closed) {
    currentDialog.close();
    currentDialog = null;
  }

  var dialogHeight = ((screen.availHeight-50) > maxHeight) ? maxHeight : screen.availHeight-50;
  var windowName = type + "Dialog";
  currentDialog = window.open(url, windowName, "scrollbars,resizable,width=" + dialogWidth + ",height=" + dialogHeight);
  var nwLeft = (screen.availWidth - dialogWidth) / 2;
  var nwTop = (screen.availHeight - dialogHeight) / 2;
  currentDialog.moveTo(nwLeft,nwTop);
  currentDialog.focus();
}

//  getElement - returns the source of an event

function getElement(evt) {
    evt = (evt) ? evt : ((window.event) ? window.event : "");

    if (evt) {
        var elem;
        if (evt.target) {
            elem = (evt.target.nodeType == 3) ? evt.target.parentNode : evt.target;
        }
        else {
            elem = evt.srcElement;
        }
        return elem;
    }
    else {
        alert("No event received.");
    }
}

// formatFloat - given a float and number of decimal places, returns a float with the specified number of decimal places

function formatFloat(expr, decPlaces) {
  if(expr.toFixed)
    return expr.toFixed(decPlaces);
  else {
    // raise incoming value by power of 10 times the number of decimal places; round to an integer; convert to a string.
    var str = "" + Math.round(eval(expr) * Math.pow(10, decPlaces))
    // pad small value strings with zeros to the left of rounded number
    while (str.length <= decPlaces) {
        str = "0" + str;
    }

    // establish location of decimal point
    var decPoint = str.length - decPlaces;

    // assemble final result
    return str.substring(0, decPoint) + "." + str.substring(decPoint, str.length);
  }
}

// parseElement -

function parseElement(thisString, index, delim) {

    // find the starting delimiter
    var startloc = -1;
    for (var i=1; i<index; i++)
        {
        // for the nth element, we want to find the n-1th delimiter
        startloc = thisString.indexOf(delim, startloc+1);
        }
    if (startloc == -1 && index != 1) return "";

    // find the ending delimiter
    var endloc = thisString.indexOf(delim, startloc+1)
    if (endloc == -1) endloc = thisString.length;
    return thisString.substring(startloc+1, endloc);
}

// highlightInput - given a form input ID, changes the color to red

function highlightInput(inputFieldID) {
	$('#' + inputFieldID)
		.addClass('invalid')
		.siblings('span.valueDisplay').find('span.value').addClass("invalid");
}

// normalizeInput - given a form input ID, changes the color to the default black
// Does not always work for IE5/Mac

function normalizeInput(inputFieldID) {
	$('#' + inputFieldID)
		.removeClass('invalid')
		.siblings('span.valueDisplay').find('span.value').removeClass("invalid");
}

// isEmail - checks the given string to determine whether it follows valid email address format

function isEmail(str) {
    // are regular expressions supported?
    var supported = 0;

    if (window.RegExp) {
        var tempStr = "a";
        var tempReg = new RegExp(tempStr);
        if (tempReg.test(tempStr))
            supported = 1;
    }

    if (!supported)
        return (str.indexOf(".") > 2) && (str.indexOf("@") > 0);

    var r1 = new RegExp("(@.*@)|(\\.\\.)|(@\\.)|(^\\.)");
    var r2 = new RegExp("^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");

    return (!r1.test(str) && r2.test(str));
}

/*  limitText :: given a string and a maxLength, returns whether the string is too long.  Used with onKeyPress event. */

function limitText(value, maxLength, event) {
	event = (event) ? event : ((window.event) ? window.event : "");
  var length = (value.length > 0) ? value.length : 0; // In case nothing's been entered yet.
  if(event.keyCode == 8 || event.keyCode == 46) return true; // backspace or delete
  return (length < maxLength);
}

/*  overTextLengthLimit :: determines if a string is longer than maxLength.  Used onBlur for if users paste in text. */

function overTextLengthLimit (value, maxLength) {
    if (value.length > maxLength) {
        alert ("Text in this field is limited to " + maxLength + " characters.");
        return true;
        }
    else
        return false;
}

/*  removeCharacters :: given a text input, removes problematic characters from the string value */

function removeCharacters(inputField, silentMode) {
	var invalidChars = new Array('&', '<', '>', '"')
  var inputString = inputField.value;
  var newString = false;

	for(var i=0; i<invalidChars.length; i++) {
		while(inputString.includes(invalidChars[i])) {
			var index = inputString.indexOf(invalidChars[i]);
      var tempString = inputString.slice(0, index);
      var tempString2 = inputString.slice(index+1);
      inputString = tempString + "and" + tempString2;
      newString = true;
		}
	}

	if(newString) {
		inputField.value = inputString;

    if(!silentMode) alert("The characters <, >, and \" have been removed from this field and any use of the & character has been replaced with \"and.\"\nUse of these characters can cause errors when loading and saving project information.");
	}
}

//  initComplianceResults - when a field has changed we set the results to "TBD"

function initComplianceResults() {
    if(top && !top.results.TBD) top.results.setTBD();
}


//  addEvent ::

function addEvent(obj, type, fn) {
  if (obj.addEventListener)
    obj.addEventListener(type, fn, false);
  else if (obj.attachEvent) {
    obj["e"+type+fn] = fn;
    obj[type+fn] = function() { obj["e"+type+fn](window.event); }
    obj.attachEvent("on"+type, obj[type+fn]);
  }
}


// removeEvent ::

function removeEvent(obj, type, fn) {
  if (obj.removeEventListener)
    obj.removeEventListener(type, fn, false);
  else if (obj.detachEvent) {
    obj.detachEvent("on"+type, obj[type+fn]);
    obj[type+fn] = null;
    obj["e"+type+fn] = null;
  }
}


jQuery.fn.labelOver = function(overClass) {
  return this.each(function(){
    var label = jQuery(this);
    var f = label.attr('for');
    if (f) {
      var input = jQuery('#' + f);

      this.hide = function() {
        label.css({ textIndent: -10000 })
      }

      this.show = function() {
        if (input.val() == '') label.css({ textIndent: 0 })
      }

      // handlers
      input.focus(this.hide);
      input.blur(this.show);
      label.addClass(overClass).click(function(){ input.focus() });

      if (input.val() != '') this.hide();
    }
  });
}

// prettyTypeTitle - returns a marked-up title

function prettyTypeTitle(componentTitle) {
	if(componentTitle.includes("sqft")) {
		return componentTitle.replace("sqft", "ft<sup>2</sup>");
	}
	else if(componentTitle.includes("sq.ft.")) {
		return componentTitle.replace("sq.ft.", "ft<sup>2</sup>");
	}
	else if(componentTitle.includes("ft2")) {
		return componentTitle.replace("ft2", "ft<sup>2</sup>");
	}
	else
		return componentTitle;
}

var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
BrowserDetect.init();


//  codeArray :: used for translating between code name strings and the engine enums

var codeArray = new Array;

codeArray["90.1 (1989) Code"] = "CEZ";
codeArray["90.1 (1999) Standard"] = "CEZ_90_1_1999";
codeArray["90.1 (2001) Standard"] = "CEZ_90_1_2001";
codeArray["90.1 (2004) Standard"] = "CEZ_90_1_2004";
codeArray["90.1 (2007) Standard"] = "CEZ_90_1_2007";
codeArray["Vermont"] = "CEZ_VT";
codeArray["Georgia"] = "CEZ_GA";
codeArray["Minnesota"] = "CEZ_MN";
codeArray["Massachusetts"] = "CEZ_MAS";
codeArray["New York"] = "CEZ_NY";
codeArray["New Hampshire"] = "CEZ_NH";
codeArray["1998 IECC"] = "CEZ_IECC1998";
codeArray["2000 IECC"] = "CEZ_IECC2000";
codeArray["2001 IECC"] = "CEZ_IECC2001";
codeArray["2003 IECC"] = "CEZ_IECC2003";
codeArray["2004 IECC"] = "CEZ_IECC2004";
codeArray["2006 IECC"] = "CEZ_IECC2006";
codeArray["Pima, AZ: 2006 IECC (&gt;= 4000ft)"] = "CEZ_PIMA_ABOVE4000";
codeArray["Pima, AZ: 2006 IECC (&lt; 4000ft)"] = "CEZ_PIMA_BELOW4000";
codeArray["Pima, AZ: Sustainable Energy Standard"] = "CEZ_SES";


//	codeArrayRES ::
	
var codeArrayRES = new Array;

codeArrayRES["1992 MEC"] = "MEC92";
codeArrayRES["1993 MEC"] = "MEC93";
codeArrayRES["1995 MEC"] = "MEC95";
codeArrayRES["1998 IECC"] = "IECC1998";
codeArrayRES["2000 IECC"] = "IECC2000";
codeArrayRES["2003 IECC"] = "IECC2003";
codeArrayRES["2006 IECC"] = "IECC2006";
codeArrayRES["Arkansas"] = "AK";
codeArrayRES["Georgia"] = "GA";
codeArrayRES["Minnesota"] = "MN";
codeArrayRES["New Hampshire"] = "NH";
codeArrayRES["New York"] = "NY";
codeArrayRES["Vermont"] = "VT";
codeArrayRES["Wisconsin"] = "WI";
codeArrayRES["Pima, AZ: 2006 IECC (&lt;4,000 ft)"] = "PIMA_BELOW4000";
codeArrayRES["Pima, AZ: 2006 IECC (&gt;=4,000 ft)"] = "PIMA_ABOVE4000";
codeArrayRES["Pima, AZ: 2006 IECC (<4,000 ft)"] = "PIMA_BELOW4000";
codeArrayRES["Pima, AZ: 2006 IECC (>=4,000 ft)"] = "PIMA_ABOVE4000";
codeArrayRES["Pima, AZ: SES"] = "SES";


//	isCodeBasedOn :: mimics the Util method, for use in Javascript

//	TODO: build this in a JSP file so that it can depend upon Util.isCodeBasedOn, so we aren't making changes twice.  Even so, this will save us time adding new codes.
	
function isCodeBasedOn(baseCode, curCode) {
  var retBool = false;

  //Note: if the current code is based on another code (baseCode) then make sure the current code 
  //gets considered in earlier baseCodes as well. 
  //e.g., CEZ_NY is based on CEZ_IECC2003 and CEZ_IECC2003 is based on CEZ_IECC2001 so CEZ_NY needs 
  //to be included in both the CEZ_IECC2003 and CEZ_IECC2001 'else if' clauses.

  if (baseCode == curCode) {  // the current code same as baseCode being checked for; always true
    retBool = true;   
  }
	else if ((baseCode == "CEZ_90_1_1999" || baseCode == "CEZ_90_1_2004") && (curCode == "CEZ_GA" || curCode == "CEZ_90_1_2007")){         
		// Commercial GA is based on 90.1-2004, but 2004 is almost all dependent on 90.1-1999
    retBool = true;   
  }
	else if ((baseCode == "CEZ_90_1_1999" || baseCode == "CEZ_90_1_2001") && (curCode == "CEZ_90_1_2001" || curCode == "CEZ_90_1_2004" || curCode == "CEZ_90_1_2007")){ 
		// 90.1-2001, 2004 and 2007 are based on 90.1-1999
    retBool = true;   
  }
	else if (baseCode == "CEZ_IECC2001" && (curCode == "CEZ_IECC2003" || curCode == "CEZ_IECC2004" || curCode == "CEZ_IECC2006" || curCode == "CEZ_NY" || curCode == "CEZ_VT"  || isPimaCode(curCode) || curCode == "CEZ_NH")){
    retBool = true;
  }
	else if (baseCode == "CEZ_IECC2003" && (curCode == "CEZ_IECC2004" || curCode == "CEZ_IECC2006" || curCode == "CEZ_NY" || isPimaCode(curCode) || curCode == "CEZ_NH")){
    retBool = true;
  }
	else if (baseCode == "CEZ_IECC2004" && (curCode == "CEZ_IECC2006" || isPimaCode(curCode))){
    retBool = true;
    //As of 7/1/2007 the two Pima County codes and SES are to be based on CEZ_IECC2006
  }
	else if (baseCode == "CEZ_IECC2006" && (isPimaCode(curCode))){
    retBool = true;
   	// NY is really based on the 2001 IECC. But the 2001 IECC is the same
   	// as the 2000 IECC with amendments. The 2000 code requirements in MECcheck
   	// all apply to the 2001 and NY, such as the foundation covering, the SHGC requirement,
   	// and the extended mass wall table. Applies to Louisiana as well.
  }
	else if (baseCode == "IECC2000" && (curCode == "IECC2003" || curCode == "IECC2001" || curCode == "NY" || curCode == "LA" || curCode == "ARK")){
  	retBool = true;
   	//Note for this condition: IECC2003 is really based on IECC2000 so any call to this routine 
   	//could apply a basecode argument of IECC2000 or IECC2003
  }
	else if (baseCode == "IECC2003" && curCode == "ARK"){
  	retBool = true;
    //As of 4/10/2007 the two Pima County codes are to be based on IECC2006
  }
	else if (baseCode == "IECC2006" && (isPimaCode(curCode) || curCode == "IRC2006" || curCode == "NH" || isGeorgiaRESCode(curCode))){
  	retBool = true;
  }
  
	return retBool; 
}


//	isPimaCode ::
	
function isPimaCode(curCode) {
	if(curCode == "SES" || curCode == "PIMA_BELOW4000" || curCode == "PIMA_ABOVE4000" || curCode == "CEZ_SES" || curCode == "CEZ_PIMA_BELOW4000" || curCode == "CEZ_PIMA_ABOVE4000") {
  	return true;
  }
  
	return false;
}


//	isGeorgiaRESCode :: 
	
function isGeorgiaRESCode(curCode) {
	if(curCode == "GA") {
    return true;
  }

  return false;
}