// Basic JavaScript functions
// --------------------------

// Quick IE detection; works IE > 4.0
var isIE = false;
/*@cc_on
  isIE = true;
@*/

// Finds the index of an item in an array, returns -1 on failure
// extends the Array prototype (JavaScript feature since 1.5, not implemented in IE up to 7)
function arrayIndexOf(val)
{
	if (!val || !this) return -1;
	var i;
	for (i = 0; i < this.length; i++) if (this[i] == val) return i;
	return -1;
}
Array.prototype.indexOf = arrayIndexOf;

// Find an object with id
function findObject(oid)
{
	if (document.getElementById) return document.getElementById(oid);   // W3C compliant
	if (document.all) return document.all[oid];                         // IE4 style
	return null;
}

// Find an object with id in the given document
function findObjectDocument(doc, oid)
{
	if (doc.getElementById) return doc.getElementById(oid);            // W3C compliant
	if (doc.all) return doc.all[oid];                                  // IE4 style
	return null;
}

// Determines if o2 is a parent of o
function isParentOf(o, o2)
{
  while (o = o.parentNode) if (o == o2) return true;
  return false;
}

// Return the style subobject of an object
function getStyleObject(o)
{
	if (!o) return null;
	if (o.style) return o.style;
	return o;
}

// Show or hide an object
function showObject(o, doShow)
{
	var styleObject = getStyleObject(o);
	if (styleObject) {
		if (doShow) styleObject.display = "";
		else styleObject.display = "none";
	}
}

// Make an object visible or invisible
function makeObjectVisible(o, doShow)
{
	var styleObject = getStyleObject(o);
	if (styleObject) {
		if (doShow) styleObject.visibility = "visible";
		else styleObject.visibility = "hidden";
	}
}

// Shortcuts
function show(o) { showObject(o, true); }
function hide(o) { showObject(o, false); }
function appear(o) { makeObjectVisible(o, true); }
function disappear(o) { makeObjectVisible(o, false); }

// Determines if an element is visible
function isVisible(o)
{
  var style = null;
  while (o) {
    style = getStyleObject(o);
    if (style.display == "none" || style.visibility == "hidden") return false;
    o = o.parentNode;
  }
  return true;
}

// Adds an event handler to an object
// Event handlers are added in a way so that they are triggered in the same
// sequence they are added (which is not guaranteed by addEventListener or attachEvent)
// Event handlers can be called manually via callEvents without triggering an actual event
function addEvent(o, eventType, eventHandler)
{
	if (!o) return false;

	// Save the handler in an internal list, so that it can be triggered manually
	if (!o["eventCount"]) o["eventCount"] = 0;
	o["eventCount"]++;
	o["event" + o["eventCount"]] = eventHandler;
	o["eventType" + o["eventCount"]] = eventType;

	// Add the handler to the object, so that it's being triggered by a user action
  var oldHandler = o["on" + eventType];
	if (!oldHandler) o["on" + eventType] = eventHandler;
	else o["on" + eventType] = function(e) { oldHandler.call(this, e); return eventHandler.call(this, e); }
	return true;
}

// Adds an event handler to an object if an event handler of that type does not yet exist
function addEventOnce(o, eventType, eventHandler)
{
  if (!o) return false;
  var c = o["eventCount"], i;
  for (i = 0; i < c; i++) if (o["eventType" + i] == eventType) return true;
  return addEvent(o, eventType, eventHandler);
}

// Calls all event handlers of an object without triggering the event; stops when an event handler return false
// Can also call events for a specific event type
function callEvents(o, eventType)
{
	if (!o) return false;

	for (var i = 1; i <= o["eventCount"]; i++)
		if (!eventType || eventType == o["eventType" + i]) {
			if (o["event" + i]() == false) return false;
		  //alert("Calling: " + o.id+".on"+o["eventType" + i]+o["event"+i]);
	}
	return true;
}

// Gets all elements of a certain type; tagname = "" -> all elements
function getAllElements(tagName)
{
	if (document.getElementsByTagName) return document.getElementsByTagName(tagName == "" ? "*" : tagName);
  if (document.all) return (tagName == "" ? document.all : document.all.tags(tagName));
  return null;
}

// Calls all event handlers on all elements that have a certain class or type; stops when a handler returns false
function callAllEvents(className, tagName, eventType)
{
	var allElements = getAllElements(tagName);
	if (!allElements) return false;

	for (var i = 0; i < allElements.length; i++)
		if (className == "" || allElements[i].className == className)
			if (callEvents(allElements[i], eventType) == false) return false;
	return true;
}

// Retrieves the function that handles the event with the given index
function getEvent(o, index)
{
	if (o["eventCount"] < index) return null;
	return o["event" + index];
}

// Determines if the element has an event of the given type
function hasEvent(o, eventType)
{
  var c = o["eventCount"];
  for (var i = 0; i < c; i++) if (o["eventType" + i] == eventType) return true;
  return false;
}

// Removes all events from an element
function removeEvents(o)
{
	var eventCount = (!o ? 0 : (!o["eventCount"] ? 0 : o["eventCount"])), i, eventName;
	if (eventCount < 1) return;
	o["eventCount"] = null;
	for (i = 1; i <= eventCount; i++ ) {
		eventName = o["eventType" + i];
		if (o["on" + eventName]) o["on" + eventName] = null;
		o["eventType" + i] = null;
		o["event" + i] = null;
	}
}

// Removes all events from all elements
// Note: This function is useful due to a bug in Firefox when the browser does not disable all elements' events
//       after destroying all user variables. This results in script errors. This behaviour does not occur on IE.
//       On IE, it prevents memory leaks.
function removeAllEvents(tagName)
{
	var allElements = getAllElements(tagName), i;
	for (i = 0; i < allElements.length; i++) removeEvents(allElements[i]);
}

// Shows of hides all elements of the given class
function showElements(classname, doShow)
{
	var e = getAllElements("");
	if (!e) return;
	for (var i = 0; i < e.length; i++)
		if (e[i].className == classname) showObject(e[i], doShow);
}

/* Stops event processing */
function StopEvent(evt)
{
  var e = window.event ? window.event : evt;
  if (e.stopPropagation) e.stopPropagation();
  if (typeof(e.cancelBubble) == 'boolean') e.cancelBubble = true;
  return true;
}

// Returns the requested border size of the given object
function getBorderSize(o, dim)
{
  var style;
  if (o.currentStyle) { style = o.currentStyle[dim];  }
  else if (window.getComputedStyle) style = document.defaultView.getComputedStyle(o, null).getPropertyValue(dim);
  style = parseInt(style);
  return isNaN(style) ? 0 : style;
}

// Gets the horizontal position of an element
function getX(o)
{
  if (!o) return 0;
	var x = 0;
  if (o.offsetParent) {
    do {
      x += o.offsetLeft;
      if (isIE && o.offsetParent && o.offsetParent.tagName.toLowerCase() != "table") x += getBorderSize(o.offsetParent, "borderLeftWidth");
    } while (o = o.offsetParent);
  } else x = o.x;
	return x;
}

// Gets the horizontal position of an element
function getY(o)
{
	if (!o) return 0;
	var y = 0;
  if (o.offsetParent) {
    do {
      y += o.offsetTop;
      if (isIE && o.offsetParent && o.offsetParent.tagName.toLowerCase() != "table") y += getBorderSize(o.offsetParent, "borderTopWidth");
    } while (o = o.offsetParent);
  } else y = o.y;
	return y;
}

// Gets the horizontal width of an element
function getWidth(o)
{
	if (!o) return 0;
	if (o.clip) return o.clip.width;
	return o.offsetWidth;
}

// Gets the height of an element
function getHeight(o)
{
	if (!o) return 0;
	if (o.clip) return o.clip.height;
	return o.offsetHeight;
}

// Sets an element's position
function moveTo(o, x, y)
{
	var style = getStyleObject(o);
	if (!style) return;
	if (style == o) {
		o.left = x;
		o.top = y;
	} else {
		style.left = x + 'px';
		style.top = y + 'px';
	}
}

// Sets an elements width and height
function resizeTo(o, w, h)
{
	var style = getStyleObject(o);
	if (!style) return;
	style.width = w + 'px';
	style.height = h + 'px';
}

// Sets the opacity of an element; opacity ranges from 0 to 100
function setOpacity(o, opacity)
{
	var style = getStyleObject(o);

	if (typeof style.opacity != 'undefined') style.opacity = opacity / 100.0;
	if (typeof style.filter != 'undefined') style.filter = "alpha(opacity=" + opacity + ")";
}

// Adds a leading zero if necessary
function leadingZero(n)
{
	if (n < 10) return "0" + n;
	else return "" + n;
}

// Selects a list entry by value
function selectByValue(o, v)
{
	if (!o) return -1;
	for (var i = 0; i < o.options.length; i++)
		if (o.options[i].value == v) return o.options.selectedIndex = i;
	return -1;
}

// Selects a list entry by text
function selectByText(o, text)
{
	if (!o) return -1;
	for (var i = 0; i < o.options.length; i++)
		if (o.options[i].text == text) return o.options.selectedIndex = i;
	return -1;
}

// Selects a list entry by text, ignoring case
function selectByTextIgnoreCase(o, text)
{
	if (!o) return -1;
	for (var i = 0; i < o.options.length; i++)
		if (o.options[i].text.toLowerCase() == text.toLowerCase()) return o.options.selectedIndex = i;
	return -1;
}

// Formats a floating point number
// The function can take a number or a string and removes optionally a part of the string.
// The number will be formatted with precis digits after the decimal point and will have
// thousand separators inserted
function formatFloat(num, precis, remove)
{
  num = num.toString();                                                     // Make sure it's a string
  if (!!remove && remove != "")
    num.replace(new RegExp(remove, "g"), "");                               // replace substring remove from number if there
  if (isNaN(num)) return num;                                               // return unchanged if not a number
  
  var number = num.split('.'), round = "", frac, neg = false;               // split into before and after decimal point
  if (!!precis && precis > 0) {                                             // Generate decimals only if precision is present
    if (number.length < 2) frac = "0";                                      // No fraction -> fraction = 0
    else frac = number[1];                                                  // otherwise fraction is second part of string
    if (frac.length > precis)                                               // check if precision matches, is greater or less
      frac = Math.round(frac / Math.pow(10.0, frac.length - precis));       // If greater, then divide by 10 to the power of the difference between decimal points and precision
    else for (; frac.length < precis; frac += '0');                         // If precision higher then add 0s
  }

  if (number[0].length == 0) number[0] = "0";                               // Start with 0, if the initial string was empty
  if (number[0].charAt(0) == '-') { neg = true; number[0] = number[0].substring(1); }      // Record sign and remove it
  var startC = 3 - (number[0].length % 3), i;                               // Put in thousand separators
  for (i = 0; i < number[0].length; i++, startC++) {
    if (startC > 2) { startC = 0; if (i) round += ','; }
    round += number[0].charAt(i);
  }

  return (neg ? '-' : '') + round + (precis > 0 ? ('.' + frac) : "");       // Put all the parts together again
}

function buttonClassSwitch(t, OnText)
{
	var c = t.className;
	if (c == "ButtonDisabled") return;
	if (c.substr(c.length - OnText.length, OnText.length) == OnText) c = t["savedClass"];
	else {
		t["savedClass"] = c;
		c += OnText;
	}
	t.className = c;
}

// Enables or disables a button
// The code expects that buttons consist of an input element which is given
// as parameter and an element around it. The input element will be disabled, and
// style or the parent element changed to disabled
// This regards to the current implementation of buttons in the site.
function enableButton(b, enable)
{
  if (!b) return;
  b.disabled = enable ? false : true;
  b = b.parentNode;
  if (!b) return;
  var c = b.className;
  if (!enable && c != "ButtonDisabled") {
    b["savedClass"] = c;
    c = "ButtonDisabled";
  } else if (enable && c == "ButtonDisabled") c = b["savedClass"];
  b.className = c;
}

// Determines if the element is a "button". A "button" in this sense is an element
// which is surrounded by a div whose classname starts with "Button"
// If defaultable check is turned on, it will be checked additionally if the button
// has a default frame
function isButton(o, checkDefaultable)
{
  var p = (!o ? null : o.parentNode);
  if (!p || p.className.substr(0, "Button".length) != "Button") return false;
  return (!checkDefaultable || (p.parentNode && p.parentNode.className.substr(0, "DefaultFrame".length) == "DefaultFrame"));
}

// Changes the default visuals of a button
// Depends on the current implementation of button: input element -> div for button visuals -> div for default visuals (-> means "is child node of")
function setDefaultVisuals(o, OnOff)
{
  var p = (!o ? null : o.parentNode);

  var defaultFrame = (!p ? null : p.parentNode);
  if (!defaultFrame || defaultFrame.className.substr(0, "DefaultFrame".length) != "DefaultFrame") return;
  defaultFrame.className = (!OnOff ? "DefaultFrame" : "DefaultFrameOn");
}

// Fix problems with the non-transparent PNG shadows on a few IE versions
// Uses the Conditional Compilation feature of IE4 or later; code inside will only
// be execute in Internet Explorer JScript implementations
function fixPNGs(BlankImage)
{
  /*@cc_on
  var imgs = getAllElements("img"), i, realSrc;
	for (i = 0; i < imgs.length; i++) {
		if (imgs[i].className == "PNGClass" && typeof imgs[i].runtimeStyle != 'undefined' ) {
			realSrc = imgs[i].src;
			imgs[i].src = BlankImage;
			imgs[i].runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + realSrc + "', sizingMethod='scale')";
		}
	}
	@*/
}

// Strips leading zeroes
function cleanLeadingZeroes(s)
{
	return s.replace(/^0/, "");
}

// Filters the value of an object to contain only digits.
// Sets the new value only if it is different from the old value. This prevents
// the selection from disappearing in unconvenient circumstances
function numericFilter(o, keepZero)
{
  var newValue = cleanLeadingZeroes(o.value.replace(/\D/g, ""));
  if (newValue == "" && keepZero) newValue = "0";
  if (newValue != o.value) o.value = newValue;
}