// utilities namespace
util = {};




// ******************************************************************************************** //
// OBJECT FUNCTIONS

util.objects = {};

// function to make subClass class inherit from baseClass class
// stolen from: http://www.kevlindev.com/tutorials/javascript/inheritance/
util.objects.inherit = function(subClass, baseClass) {
   function inheritance() {}
   inheritance.prototype = baseClass.prototype;
   subClass.prototype = new inheritance();
   subClass.prototype.constructor = subClass;
   subClass.baseConstructor = baseClass;
   subClass.superClass = baseClass.prototype;
}





// ******************************************************************************************** //
// FOR CALLING MULTIPLE ONLOAD FUNCTIONS
// -- taken from Simon Willison (http://simonwillison.net/) via http://www.webreference.com/programming/javascript/onloads/

util.addLoadEvent = function (func) {
  
  var oldonload = window.onload;
  
  if (typeof window.onload != 'function') {
    
    window.onload = func;
    
  } else {
  
    window.onload = function() { 
    
      if (oldonload) { 
        oldonload(); 
      }
      
      func(); 
    }
    
  }
  
} 





// ******************************************************************************************** //
// size and position functions

// get the full size of an element, including margin, padding, and border


// returns full height of the element, borders and padding included
util.getFullHeight = function (el) {
  
  return el.offsetHeight;
  
}


// returns full width of the element, borders and padding included
util.getFullWidth = function (el) {

  return el.offsetWidth;

}

util.setLeft = function (el, value) {
  
  el.style.left = value + "em";  
}


// runs through elements until reaches parent
util.getElementPositionInElement = function (cur_elem, parent_elem) {

  pos_x = cur_elem.offsetLeft
  pos_y = cur_elem.offsetTop;

  cur_parent = cur_elem.offsetParent;
  
  while ((cur_parent != null) && (cur_parent != parent_elem)) {
            
    pos_x = pos_x + cur_parent.offsetLeft;
    pos_y = pos_y + cur_parent.offsetTop;
    
    cur_parent = cur_parent.offsetParent;
    
  }
  
  return [ pos_x, pos_y ];
  
}








// ******************************************************************************************** //
// UTILITY FUNCTIONS

listenForMouseClick = function (element, clickFunction) {

  if (window.addEventListener)
		element.addEventListener('click', clickFunction, false);
  else
	  element.onclick = clickFunction;

}


listenForMouseOver = function (element, overFunction) {
  
  if (window.addEventListener)
		element.addEventListener('mouseover', overFunction, false);
  else
	  element.onmouseover = overFunction;

}


listenForMouseOut = function (element, outFunction) {
  
  if (window.addEventListener)
		element.addEventListener('mouseout', outFunction, false);
  else
	  element.onmouseout = outFunction;

}



// Event handler for preventing the HREF tag from actually going through
// -- Internet Explorer seems to require that you return false
//    from the event handler rather than accessing the preventDefault() method
// -- e will be null in Internet Explorder
preventDefault = function(e) {
	if (!e) {
		return false
	}
	else {
		e.preventDefault();
		return false;
	}
}

// takes a link node and blocks it from executing the default linking action
blockDefaultAction = function (link) {
  
  // block the default action for the href
  if (window.addEventListener)
	  link.addEventListener('click', preventDefault, false);
	else
		link.onclick = preventDefault;

}



// returns a sibling element -- that is, something that isn't a text node or null
getNextElementSibling = function (element_node) {
    
  while (element_node = element_node.nextSibling) { 
    
    if (element_node.nodeType == 1)
      return element_node;
      
  }
  
  return null;
  
}


// returns the first child element node -- that is, something that isn't null or a text node
getFirstChildElementNode = function (element_node) {
  
  if (first_child = element_node.firstChild) {
  
    if (first_child.nodeType == 1)
      return first_child;
    else
      return getNextElementSibling (first_child);
      
  }
  
  return null;
  
}


// element name must be in all caps
getNextNodeOfType = function (tag_name, element_node) {
  
  while (element_node = element_node.nextSibling) {
  
    if (element_node.tagName == tag_name)
      return element_node;
  
  }
  
  return null;
  
}


// element name must be in all caps
getFirstChildNodeOfType = function (tag_name, element_node) {
  
  if (first_child = getFirstChildElementNode (element_node)) {
    
    if (first_child.tagName != tag_name)
      return getNextNodeOfType (tag_name, first_child);
    else
      return first_child;
      
  }
  
  return null;
  
}



// gather all <dd> elements and put their text bodies in an array indexed by the "id" of the elements
// -- returns error if duplicate id is found
getXmlDataArray = function (data_node) {
  
  var return_array = {};
  
  // get a list of properties by looking at all the <dd> elements
  var data = data_node.getElementsByTagName("dd");
  
  for (i=0; cur_elem = data[i]; i++) {
    
    if (cur_elem.id) {
      
      // output warning if there is a duplicate
      if (return_array[cur_elem.id])
        alert ("Duplicate in fct.util.getXmlDataArray on " + cur_elem.id);
      else   
        return_array[cur_elem.id] = getNodeInnerText(cur_elem);
    
    }
    
  }
  
  return return_array;

}



// returns the inner text (in the first child) of an element if it exists, or returns null
// -- may need to get rid of extraneous ending space characters for IE
getNodeInnerText = function (element_node) {

	if (element_node.firstChild)
    return element_node.firstChild.nodeValue;
  else
    return null;
    
}




// getStyle and toCamelCase are taken from somewhere -- not sure where
toCamelCase = function (sInput) {
  
  var oStringList = sInput.split('-');
  
  if (oStringList.length == 1)
    return oStringList[0];
  
  var ret = sInput.indexOf("-") == 0 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) : oStringList[0];
  
  for (var i = 1, len = oStringList.length; i < len; i++) {
    
    var s = oStringList[i];
    
    ret += s.charAt(0).toUpperCase() + s.substring(1)
    
  }
  
  return ret;

}

getStyle = function (el, style) {
  
  camelCaseStyle = toCamelCase(style);
  
  var value = el.style[camelCaseStyle];
 
  if (!value) {
  
    if(document.defaultView)
      value = document.defaultView.getComputedStyle(el, "").getPropertyValue(style);
    else if(el.currentStyle)
      value = el.currentStyle[camelCaseStyle];
   
  }
  
  return value;
  
}


// removes the final two characters from a string and returns as an integer
// -- multiplies result by 10 in case of em (this will need to be made a constant)
stripUnits = function (value) {
  
  var amount = parseInt(value.substr(0, value.length - 2));
  
  var units = value.substr(value.length - 2, value.length);
  
  if (units == "em")
    amount = amount * 10;
  
  return amount;
  
}

// if the e parameter is emtpy, passes back the IE method of accessing the event
getActualEvent = function (e) {
  
	if (!e) {
 		if (window.event)	{
			return window.event;
		}
 	}
 	else {
 		return e;
 	}

}


// returns the relative position of an event inside what should be an absolutely positioned element
getRelativeEventPosition = function (event) {
  
  var return_x;
  var return_y;
  
  if (!(return_x = event.layerX)) {
    if (!(return_x = event.offsetX)) {
      return_x = 0;
    }
  }

  if (!(return_y = event.layerY)) {
    if (!(return_y = event.offsetY)) {
      return_y = 0;
    }
  }
    
  return [ return_x, return_y ]
  
}