/***********************************************************
* Diverse generelle Dubex JavaScript funktioner
***********************************************************/



/***********************************************************
* Variabel defineret til at være ingenting (= undefined).
*
* Nye browsere bør have undefined defineret, men det skader
* ikke at re-definere den.  Gamle browsere kræver at man
* definerer den selv, som det står her.
*
* Formål: At man også kan skrive if (var == undefined)
* (osv.) i stedet for if (typeof(var) == "undefined").
***********************************************************/
var undefined;



/***********************************************************
* Undgå fjollede problemer med forældede browsere ved
* at fange dem her og fortælle hvorfor de er i stykker.
***********************************************************/
function checkBrowser() {
	if (document.cookie.indexOf("want_broken_rendering") == -1) {
		var ua = navigator.userAgent.toLowerCase();
		if (/msie (\d+)\./.test(ua)) {
			if (RegExp.$1 < 7) {
				document.location.href = '/help/browsertooold/';
				return;
			}
		}
	}
	document.cookie = "want_broken_rendering=irrelevant; path=/";
}
checkBrowser();



/***************************
 * getViewWidth() & getViewHeight()
 * -----
 * Returnerer højde / bredde på vindue (frame?)
 ***************************/
var dbxWidth = null;
var dbxHeight = null;

function findWidthAndHeight() {
	// intern metode

	/* Old method:
		if (document.layers) {
			dbxWidth = window.[inner/outer]Width;
			dbxHeight = window.[inner/outer]Height;
		}
		if (document.all) {
			dbxWidth = document.body.clientWidth;
			dbxHeight = document.body.clientHeight;
		}
	*/

	if (typeof(window.innerWidth) != "undefined") {
		dbxWidth = window.innerWidth;
		dbxHeight = window.innerHeight;
	} else {
		if (document.documentElement && typeof(document.documentElement.clientWidth) != "undefined" && document.documentElement.clientWidth != 0) {
			dbxWidth = document.documentElement.clientWidth;
			dbxHeight = document.documentElement.clientHeight;
		} else {
			if (document.body && typeof(document.body.clientWidth) != "undefined") {
				dbxWidth = document.body.clientWidth;
				dbxHeight = document.body.clientHeight;
			}
		}
	}
}

function getViewWidth() {
	if (dbxWidth) return dbxWidth;
	else {
		findWidthAndHeight();
		return dbxWidth;
	}
}

function getViewHeight() {
	if (dbxHeight) return dbxHeight;
	else {
		findWidthAndHeight();
		return dbxHeight;
	}
}



/***************************
 * switchClass(obj)
 * -----
 * Laver "mouse over" effekt på et-eller-andet.
 * Kald denne fra mouseover OG mouseout.
 * Husk CSS klasserne "blahblah" og "blahblahHover"...
 ***************************/
function switchClass(obj) {
	var cName = obj.className;
	if (cName.indexOf("Hover") > -1) {
		cName = cName.replace("Hover", "");
	} else {
		cName = cName + "Hover";
	}
	obj.className = cName;
}



/***************************
 * findFirstChildWithTagName(parent object, tag name)
 * -----
 * Finder den første kontrol (kan være parent) med et givent HTML tag.
 * 'tag name' skal angived med store bogstaver.
 ****************************/
function findFirstChildWithTagName(parent, tagName) {
	if ((new String(parent.tagName)).toUpperCase() == tagName) return parent;
	for (var i = 0; i < parent.childNodes.length; i++) {
		var testChild = findFirstChildWithTagName(parent.childNodes[i], tagName);
		if (testChild) return testChild;
	}
	return null;
}



/***************************
 * hoverClick(parent object)
 * -----
 * Simulerer musetryk på et A element eller sub-element.
 * Bruges typisk i forbindelse med mouseover, hvor et tryk på en TD
 * skal resultere i et tryk på et A link inde i TD'en.
 ****************************/
function hoverClick(parentObj) {
	var foundObj = findFirstChildWithTagName(parentObj, "A");
	if (foundObj) {
		if (foundObj.click) foundObj.click();
		else location.href = foundObj.href;
	}
	return false;
}



/***************************
 * flipIt(object id)
 * -----
 * Skjuler / viser et element.
 ***************************/
function flipIt(objName) {
	var obj = document.getElementById(objName);
	if (obj.style.display != 'none') {
		obj.styleFlipped = obj.style.display;
		obj.style.display = 'none';
	} else {
		if (obj.styleFlipped) obj.style.display = obj.styleFlipped;
		else obj.style.display = '';
	}
	// in case we were called from the onclick event of an A tag (hyperlink), return false so that the link won't be followed.
	return false; 
}



/***************************
 * checkIp(input field)
 * -----
 * Checker om et input felt indeholder en valid IP adresse
 *
 *
 * resetBg(object)
 * -----
 * Sætter baggrundsfarve til hvid på objekt (typisk input felt).
 ***************************/
function resetBg(field) {
	field.style.backgroundColor = "#ffffff";
}

function goodIp(field) {
	field.style.backgroundColor = "#ddffdd";
}

function badIp(field) {
	field.style.backgroundColor = "#ffdddd";
}

var valid = "0123456789.*";

function checkNumber(number) {
	var nrStr = "" + number;
	if (nrStr == "*") return true;
	if (nrStr.indexOf("*") > -1) return false;
	if (nrStr.length < 1) return false;
	for (var j = 0; j < nrStr.length; j++) {
		if (valid.indexOf(nrStr.substring(j, j + 1)) == "-1") return false;
	}
	if (number > 255) return false;
	return true;
}

function checkIp(field) { 
	var value = field.value;
	var temp = "";
	var pos = -1;
	var counter = 0;

	if (value == "") {
		resetBg(field);
		return;
	}

	for (var i = 0; i < value.length; i++) {
		temp = "" + value.substring(i, i + 1);
		if (temp == "." ) counter++;
		if (valid.indexOf(temp) == "-1") {
			badIp(field);
			return;
		}
	}

	if (counter != 3) {
		badIp(field);
		return;
	}

	if (value.lastIndexOf(".") == (value.length - 1)) {
		badIp(field);
		return;
	}

	for (var i = 0; i < value.length; i++) {
		pos = value.indexOf(".", i);
		if (pos == -1) pos = value.length;
		temp = value.substring(i, pos);
		i = pos;
		if (! checkNumber(temp)) {
			badIp(field);
			return;
		}
	}

	goodIp(field);
	return;
}



/***************************
 * showHelp(help id, width, height)
 * -----
 * Åbner et nyt vindue, som viser en hjælpe artikel
 ***************************/
function showHelp(id, w, h) {
	window.open("/dems/help/?id=" + id, null, "width=" + w + ",height=" + h + ",resizable=yes,scrollbars=yes");
	return false;
}



/***************************
 * showLogView(parameter object)
 * -----
 * Åbner et nyt vindue, som viser en log viewer
 ***************************/
function showLogView(parms) {
	var url = '/dems/analyses/fw1viewer/?';
	for (p in parms) url += p + "=" + parms[p] + "&";
	url += "start=yes";
	showNewWindow(url);
	return false;
}



/***************************
 * showNewWindow(url)
 * -----
 * Åbner et nyt vindue ud fra en url
 ***************************/
function showNewWindow(url) {
	findWidthAndHeight();
	var features = "width=" + Math.round(dbxWidth / 1.5) + ",height=" + Math.round(dbxHeight / 1.5) + ",resizable=yes,scrollbars=yes";
	window.open(url, null, features);
	return false;
}



/***************************
 * placeFocus()
 * -----
 * Placerer tekstmarkør i første tekstkontrol i først form på siden
 ***************************/
function placeFocus() {
	if (document.forms.length > 0) {
		var field = document.forms[0];
		for (i = 0; i < field.length; i++) {
			if ((field.elements[i].type == 'text') || (field.elements[i].type == 'textarea') || (field.elements[i].type.toString().charAt(0) == 's')) {
				document.forms[0].elements[i].focus();
				break;
			}
		}
	}
}



/***************************
 * getInnerHtml(containerId)
 * -----
 * returnerer indholdet (innerHTML) af den navngivne kontrol
 ***************************/
function getInnerHtml(containerId){
	var obj = document.getElementById(containerId);
	return obj.innerHTML;
}



/***************************
 * assureMaxLengthLimit(field, maxlimit)
 * -----
 * sørger for, antallet af karakterere ikke overstiger maxlimit i den vedsendte kontrol.
 * nyttig i forbindelse med multi-line textboxes, da maxlength=xx egenskaben ikke har nogen effekt på disse.
 * funktionen kaldes da for tekstboksens keydown og keyup metoder med fx (this, 200) som parametre.
 ***************************/
function assureMaxLengthLimit(field, maxlimit) {
	if (field.value.length > maxlimit) field.value = field.value.substring(0, maxlimit);
}



/***************************
 * DbxDate
 * -----
 * En wrapper til Date objektet som er lidt mindre sindsyg end den indbyggede i JavaScript.
 *
 * Konstruktører:
 * new DbxDate() - dato objekt indeholdende client time.
 * new DbxDate(year, month, dayOfMonth) - dato objekt indeholdende specificerede parametre.
 * new DbxDate(xxx) hvor xxx er en anden DbxDate - samme som DbxDate.clone().
 *
 * God reference: http://www.merlyn.demon.co.uk/#dat
 ***************************/
function DbxDate(year, month, day) {
	// Variable to hold private Date object.
	var nativeDate = new Date(-1, 0, 1);

	// Private pad function.
	var padDate = function(value, length) {
		value = new String(value);
		var prefix = "";
		if (value.substring(0, 1) == "-") {
			prefix = "-";
			value = value.substring(1, value.length);
		}
		value = "0000" + value;
		value = value.substring(value.length - length, value.length);
		return prefix + value;
	}

	// Private days in month array (february value for non-leap years).
	var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

	// Getter functions.  Fix getYear() by using getFullYear().  Also adjust month by +1.
	this.getYear = function() { return nativeDate.getFullYear(); }
	this.getMonth = function() { return nativeDate.getMonth() + 1; }
	this.getDayOfMonth = function() { return nativeDate.getDate(); }
	this.getDayOfWeek = function() {
		// According to JavaScript, sunday is the first day of the week.
		// The Romans used astronomical names for week days, eg. Sun, Moon, Mars, Mercury, Jupiter, Venus and Saturn.
		// So according to the order in which they perceived the astronomical bodies, sunday comes first.
		// In countries speaking latin-derived languages (eg. france and spain), the week day names and day order derives from the Roman ordering.
		//
		// In English, some of the week day names are named after Norse gods, which throws things a bit off.
		//
		// In Christianity and related religions, God rested on the 7th day, which makes monday the first day of the week.
		// ISO 8601 also defines monday as the first day of the week.
		// So do we :-).  Mostly because it feels natural to me.  And I'm the archetype for modern mankind, the ultimate glorious original hybrid being from which all other inferior modern humans were modelled.  There you have it.  Remind me to change the epoch from 1/1/1970 to my birthday.
		return (nativeDate.getDay() + 6) % 7;
	}
	this.getDaysInMonth = function() {
		// Could be made generic instead of always returning date per _this_ month, if need be..
		var month = nativeDate.getMonth();
		var year = nativeDate.getFullYear();
		if (month == 1 && (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))) return 29;
		else return daysInMonth[month];
	}

	// Setter functions.  Fix setYear() by using setFullYear().  Also adjust month by -1.
	//
	// Each of these functions will validate the date afterwards,
	// which will adjust the date silently if it falls on an invalid day-of-month.
	//
	// Therefore, always set year first, then month, then day of month.
	this.setYear = function(year) { nativeDate.setFullYear(year); }
	this.setMonth = function(month) { nativeDate.setMonth(month - 1); }
	this.setDayOfMonth = function(day) { nativeDate.setDate(day); }
	this.setDate = function(year, month, day) {
		if ((year == undefined) || (month == undefined) || (day == undefined)) {
			var now = new Date();
			nativeDate.setFullYear(now.getFullYear());
			nativeDate.setMonth(now.getMonth());
			nativeDate.setDate(now.getDate());
		}
		if (year != undefined) nativeDate.setFullYear(year);
		if (month != undefined) nativeDate.setMonth(month - 1);
		if (day != undefined) nativeDate.setDate(day);
	}

	// Add/Subtract functions.
	// Rollback avoidance algorithms nicked from http://www.brainjar.com/js/calendar/default3.asp.
	this.addDays = function(days) { nativeDate.setDate(nativeDate.getDate() + days); }
	this.addMonths = function(months) {
		// Avoid rollover, eg. adjust date back a few days if it falls outside of selected month.
		var prevDay = nativeDate.getDate();
		// Set day of month to 1 to avoid rollover.
		nativeDate.setDate(1);
		nativeDate.setMonth(nativeDate.getMonth() + months);
		// Restore day or set day to month max if it would overflow.
		nativeDate.setDate(Math.min(prevDay, this.getDaysInMonth()));
	}
	this.addYears = function(years) {
		// Avoid rollover, eg. adjust date back a few days if it falls outside of selected month.
		var prevDay = nativeDate.getDate();
		// Set day of month to 1 to avoid rollover.
		nativeDate.setDate(1);
		nativeDate.setFullYear(nativeDate.getFullYear() + years);
		// Restore day or set day to month max if it would overflow.
		nativeDate.setDate(Math.min(prevDay, this.getDaysInMonth()));
	}

	// Comparison functions.
	this.compareTo = function(opposite) {
		if (opposite instanceof Date) {
			var nat = nativeDate.getTime();
			var opp = opposite.getTime();
			if (nat < opp) return -1;
			if (nat > opp) return 1;
			return 0;
		} else if (opposite instanceof DbxDate) {
			return -(opposite.compareTo(nativeDate));
		}
		return undefined;
	}
	this.equals = function(opposite) { return (this.compareTo(opposite) == 0); }

	// toString() functions.
	//
	// Internet Explorer will crap out with "Syntax Error in Line 0" and
	// a fat debug dialog which will take you absolutely nowhere even
	// if you do have their ancient Script Debugger installed.
	//
	// So apparently that name was ill-chosen.
	// ToString with a capital T seems fine, however.
	this.ToString = function(format) {
		if (format == undefined) return undefined;
		if (isNaN(nativeDate.getTime())) return undefined;
		var year = this.getYear();
		var nativeMonth = nativeDate.getMonth();
		var month = this.getMonth();
		var dayOfWeek = this.getDayOfWeek();
		var dayOfMonth = this.getDayOfMonth();
		var re = /(yyyy|yyy|MMMM|MMM|MM|M|dddd|ddd|dd|d)/g;
		var matches = format.match(re);
		var i, begin, end;
		var res = "";
		var tmp;
		for (i = 0; i < matches.length; i++) {
			switch (matches[i]) {
				case "yyyy":  tmp = padDate(year, 4); begin = format.indexOf("yyyy"); end = begin + 4; break;
				case "yyy":   tmp = year; begin = format.indexOf("yyy"); end = begin + 3; break;
				case "MMMM":  tmp = monthName[nativeMonth]; begin = format.indexOf("MMMM"); end = begin + 4; break;
				case "MMM":   tmp = monthName[nativeMonth].substring(0, 3); begin = format.indexOf("MMM"); end = begin + 3; break;
				case "MM":    tmp = padDate(month, 2); begin = format.indexOf("MM"); end = begin + 2; break;
				case "M":     tmp = month; begin = format.indexOf("M"); end = begin + 1; break;
				case "dddd":  tmp = weekDayName[dayOfWeek]; begin = format.indexOf("dddd"); end = begin + 4; break;
				case "ddd":   tmp = weekDayName[dayOfWeek].substring(0, 3); begin = format.indexOf("ddd"); end = begin + 3; break;
				case "dd":    tmp = padDate(dayOfMonth, 2); begin = format.indexOf("dd"); end = begin + 2; break;
				case "d":     tmp = dayOfMonth; begin = format.indexOf("d"); end = begin + 1; break;
			}
			res += format.substring(0, begin);
			format = format.substring(end, format.length);
			res += tmp;
		}
		return res;
	}
	this.toShortString = function() { return this.ToString(dateFormatShort); }
	this.toLongString = function() { return this.ToString(dateFormatLong); }
	this.toIsoString = function() { return this.ToString("yyyy-MM-dd"); }

	// clone() function.
	this.clone = function() { return new DbxDate(this) };

	// Initialize the internal Date object.
	if (year instanceof DbxDate) this.setDate(year.getYear(), year.getMonth(), year.getDayOfMonth());
	else this.setDate(year, month, day);
}



/***************************
 * formCarriageReturn() og formSubmit()
 * -----
 * formCarriageReturn() håndterer når vognretur tasten
 * trykkes på et element under en form.  Dette er et
 * workaround til .NET, som kun understøtter én FORM tag
 * per web side.  For at undgå tryk på forkerte knapper
 * slår vi enten helt submit via vognretur fra, eller
 * finder manuelt den nærmeste input button og fyrer en
 * simuleret click event af på den.
 *
 * Note: virker selvsagt kun hvis Dubex.Web.Form bruges.
 ***************************/
var crPressed = false;
function formSubmit() {
	crPressed = ! crPressed;
	return crPressed;
}
function formCarriageReturn(evt) {
	evt = (evt) ? evt : window.event;
	var charCode =
		(evt.charCode) ? evt.charCode :
		((evt.which) ? evt.which :
		evt.keyCode);
	// charCode 3 is for Macintosh and alikes, 13 is for most other platforms.
	if (charCode == 13 || charCode == 3) {
		// Stopping event propagation via stopPropagation() or cancelBubble()
		// is not enough in some browsers, so we employ our own hack to avoid
		// submitting the form.
		crPressed = true;
		// TODO:
		//        1. Create function to find next matching control in DOM tree
		//           given a starting control and a callback that will check if
		//           a given node matches or not.
		//        2. Call said function using the current focused control as
		//           the first search object, and a match function that
		//           returns true if the element given has tag == input and
		//           type == button.
		//        3. Simulate click on found button.
	}
}
