/*-------------------------------------------
| This script contains useful utility functions
| Dependencies:
| 	-ieEmulation.js
---------------------------------------------*/

/*-------------------------------------------
| Locate DOM objects
---------------------------------------------*/
function getParentEl(srcObj,targetEl,excludeEl){
//crawl up the DOM to find and return the targetEl
  var excludeEl = (excludeEl) ? excludeEl : 'BODY';
  while (srcObj.tagName != 'BODY' && srcObj.tagName != 'HTML' && srcObj.tagName != targetEl.toUpperCase() && srcObj.tagName != excludeEl.toUpperCase()){
    srcObj = srcObj.parentNode;
  }
  return srcObj;
}

function getParentElByAttribute(srcObj,att,excludeEl){
//crawl up the DOM to find and return the first targetEl with an
//attribute [att]
  var excludeEl = (excludeEl) ? excludeEl : 'BODY';

  while(srcObj.tagName != 'BODY' && srcObj.tagName != 'HTML' && !srcObj.getAttribute(att) && srcObj.tagName != excludeEl.toUpperCase()){
    srcObj = srcObj.parentNode;
  }
  return srcObj;
}

function getParentElByClassName(srcObj,cName,excludeEl){
  //crawl up the DOM to find and return the first targetEl with
  //classname [cName]
  var excludeEl = (excludeEl) ? excludeEl : 'BODY';

  while(srcObj.tagName != 'BODY' && srcObj.tagName != 'HTML' && !classNameExists(srcObj,cName) && srcObj.tagName != excludeEl.toUpperCase()){
    srcObj = srcObj.parentNode;
  }
  return srcObj;
}

function getSrcElByTagName(e,elName,excludeEl){
//This function will return the source object that triggered the event.
//If the tagName does not match elName, assume that a child of the bound
//element triggered the event and attempt to find the parent el with elName.
  var excludeEl = (excludeEl) ? excludeEl : 'BODY';
  var oNode = getSrcEl(e);

  if (oNode.tagName.toUpperCase() != elName.toUpperCase()){
    oNode = getParentEl(oNode,elName,excludeEl);
  }
  return oNode;
}

function getFrame(name,startFrameObj){
/* This function descends recursively through all framesets, starting at the
topmost framset (or startFrameObj) until it finds a frame with name==name */

  var startFrameObj = (startFrameObj) ? startFrameObj.window : top.window;
  var curFrame = null;

  try {
    curFrame = startFrameObj.frames[name];
  }
  catch(e){
    curFrame = null;
  }

  var i=0;
  while(curFrame==null && i<startFrameObj.frames.length){
    curFrame = getFrame(name,startFrameObj.frames[i]);
    i++;
  }
  return curFrame;
}

function getElementByIdInFrames(id,startFrameObj){
/* This function starts at the current window, looking for an object by id.
If it doesn't find it, it descends recursively through all framesets,
starting at the topmost framset (or startFrameObj).  The entire function
is wrapped in a try in case the src of the window is outside of the current
domain (which would throw a security violation exception). */

/* TODO: If no startFrameObj is passed, start at the current branch and
drill down recursively.  If not found, start over again at window.top, but
figure out some way to skip the previously searched branch.  */

  try {
    //look in current window first:
    if (document.getElementById(id)) return document.getElementById(id);
    //then, if not found, start at the top and search recursively:
    var curFrame = (startFrameObj) ? startFrameObj.window : top.window;
    var curEl = (curFrame.document.getElementById(id)) ? curFrame.document.getElementById(id) : undefined;
    var i=0;
    while(!curEl && i<curFrame.frames.length){
      curEl = getElementByIdInFrames(id,curFrame.frames[i]);
      i++;
    }
    return curEl;
  }
  catch(e){
    //TODO: there may be some issues with returning false here
    return false;
  }
}

function getEvent(e){
  return (window.event) ? window.event : e; //for IE
}

function getSrcEl(e){
/* Returns the source element of event e. Since srcElement is proprietary
to IE, this behavior for standards-compliant browsers is made possible by
ieEmulation.js */
  var e = getEvent(e);
  var srcEl = null;
  srcEl = e.srcElement;
  return srcEl;
}

/*-------------------------------------------
| Determine coordinates of an event
---------------------------------------------*/
function getEventX(e){
//find X coordinate of event relative to current window
  var e = getEvent(e);

  if (is.ie){
    eX = e.clientX + document.body.scrollLeft;
  }
  else{
    eX = e.pageX;
  }
   return eX;
}

function getEventY(e){
//find Y coordinate of event relative to current window
  var e = getEvent(e);

  if (is.ie){
    eY = e.clientY + document.body.scrollTop;
  }
  else{
    eY = e.pageY;
  }
  return eY;
}

function getEventXinScreen(e){
  /* find X coordinate of event relative to screen.  This works no matter
  where the event ocurred--even in child windows */
  var e             = getEvent(e);
  var xInCurWin     = getEventX(e);
  var curWinScreenX = (is.ie) ? window.screenLeft-document.body.scrollLeft     : window.screen.left-window.pageXOffset-window.outerWidth-window.innerWidth;
  var topWinScreenX = (is.ie) ? top.window.screenLeft-document.body.scrollLeft : top.window.screen.left-window.pageXOffset-window.outerWidth-window.innerWidth;

  //alert("xInCurWin=" + xInCurWin +"\ncurWinScreenX=" + curWinScreenX + "\ntopWinScreenX=" + topWinScreenX)
  /* The current window's position will always be greater than the top
  window's position, so figure out the position of the current window
  relative to the top window, and then add the location of the event
  to that number. */
  var eX = curWinScreenX - topWinScreenX + xInCurWin;
  return eX;
}

function getEventYinScreen(e){
  /* find Y coordinate of event relative to screen.  This works no matter
  where the event ocurred--even in child windows */
  var e         = getEvent(e);
  var yInCurWin = e.screenY;
  var eY        = 0;

  if(is.ie){
    curWinScreenY = this.window.screenTop-document.body.scrollTop;
    topWinScreenY = top.window.screenTop-document.body.scrollTop;
    eY            = curWinScreenY - topWinScreenY// + getEventY(e) -15;
  }
  else {
    var toolbarHeight =  window.outerHeight - window.innerHeight - 24;
    var eY            = e.screenY - window.screenY - toolbarHeight + getEventY(e);
  }
  return eY;
}

/*-------------------------------------------
| Determine coorindates of DOM element
---------------------------------------------*/
function getElX(el){
//find absolute X offset relative to BODY
   var oNode = el;
   var elX = 0;
   while(oNode.tagName != "BODY"){
      elX += oNode.offsetLeft;
      oNode = oNode.offsetParent;
   }
   return elX;
}

function getElY(el) {
//find absolute Y offset relative to BODY
   var oNode = el;
   var elY = 0;
   while(oNode.tagName != "BODY"){
      elY += oNode.offsetTop;
      oNode = oNode.offsetParent;
   }
   return elY;
}

/*-------------------------------------------
| Determine coordinates of cursor
---------------------------------------------*/
function getCursorPos(p, event){
  if (is.ie) {
    p.x = window.event.clientX + document.body.scrollLeft; //+ document.documentElement.scrollLeft;
    p.y = window.event.clientY + document.body.scrollTop //+ document.documentElement.scrollTop;
  }
  else {
    p.x = event.clientX + window.scrollX;
    p.y = event.clientY + window.scrollY;
  }
}

/*-------------------------------------------
| Determine dimensions of DOM element
---------------------------------------------*/
function Point(){  //constructor
  this.x = 0;
  this.y = 0;
}

function Dimensions(){  //constructor
  this.topleft     = new Point();
  this.bottomright = new Point();
  this.width       = 'undefined';
  this.height      = 'undefined';
}

function getElMetrics(el){
  var dim = new Dimensions();

  //top-left corner
  dim.topleft.x     = getElX(el);
  dim.topleft.y     = getElY(el);
  //width and height
  dim.width         = el.offsetWidth;
  dim.height        = el.offsetHeight;
  //bottom-right corner
  dim.bottomright.x = dim.topleft.x + dim.width;
  dim.bottomright.y = dim.topleft.y + dim.height;

  return dim;
}

function getDocumentHeight(){
  //(safely) returns height of the document object

  d  = window.document ? window.document : null
  db = d.body ? d.body : null;
  de = d.documentElement ? d.documentElement : null;

  winHeight = (de && de.clientHeight) ? de.clientHeight : (db && db.clientHeight) ? db.clientHeight : (window.innerHeight) ? window.innerHeight : 0;
  return winHeight;
}

function getDocumentWidth(){
  //(safely) returns height of the document object

  d  = window.document ? window.document : null
  db = d.body ? d.body : null;
  de = d.documentElement ? d.documentElement : null;

  winHeight = (de && de.clientWidth) ? de.clientWidth : (db && db.clientWidth) ? db.clientWidth : (window.innerWidth) ? window.innerWidth : 0;
  return winHeight;
}

/*-------------------------------------------
| Classname manipulation
---------------------------------------------*/
function classNameExists(obj,cName){
  var exists = false;
	var classNameArray = getClassNames(obj);
	
  for(var i=0; i<classNameArray.length; i++){
    if (classNameArray[i] == cName){
      exists = true;
      break;
    }
  }
  return exists;
}

function getClassNames (obj) {
	//return an array of classnames for the object
  if(!obj || !obj.className) return false;
  var classNameArray = obj.className.split(' ');
	return classNameArray;
}

function addClassName(obj,cName){
  //if object already has a given classname, don't add it again.
  var exists = classNameExists(obj, cName);

  if(!exists){
    obj.className += (obj.className=='') ? cName : ' ' + cName;
  }
}

function removeClassName(obj,cName){
  //if object doesn't have a given classname, don't attempt to remove it.
  var exists = classNameExists(obj, cName);
  if (!exists) return;

  if(obj.className.indexOf(' ' + cName) > -1){ //if there is a space before classname
    obj.className = obj.className.replace(eval('/ ' + cName + '/g'),'');
  }
  else{
    obj.className = obj.className.replace(eval('/' + cName + '/g'),'');
  }
}

function replaceClassName(obj,oCname,nCname){
  removeClassName(obj,oCname);
  addClassName(obj,nCname);
}


/*-------------------------------------------
| Query string and URL manipulation
---------------------------------------------*/
// This is the array/object containing the GET data.
// Retrieve information with 'var myData = QueryData[key];'
var QueryDataArray = new Array();
var QueryData = createRequestObject();

function createRequestObject(){
  //This function parses the entire query string and generates an object for each name/value pair
  QueryData = new Object();
  var separator = ','; // The token used to separate data from multi-select inputs
  var query = '' + this.location;
  var qu = query
    // Get the current URL so we can parse out the data.
    // Adding a null-string '' forces an implicit type cast
    // from property to string, for NS2 compatibility.

  query = query.substring((query.indexOf('?')) + 1);
    // Keep everything after the question mark.

  if (query.length < 1){
    // Perhaps we got some bad data?
    return false;
  }

  var keypairs = new Object();
  var numKP = 1;
    // Local vars used to store and keep track of name/value pairs
    // as we parse them back into a usable form.

  while (query.indexOf('&') > -1){
    keypairs[numKP] = query.substring(0,query.indexOf('&'));
    query = query.substring((query.indexOf('&')) + 1);
    numKP++;
      // Split the query string at each '&', storing the left-hand side
      // of the split in a new keypairs[] holder, and chopping the query
      // so that it gets the value of the right-hand string.
  }

  keypairs[numKP] = query;
    // Store what's left in the query string as the final keypairs[] data.

  for (i in keypairs){
    keyName = keypairs[i].substring(0,keypairs[i].indexOf('='));
      // Left of '=' is name.
    keyValue = keypairs[i].substring((keypairs[i].indexOf('=')) + 1);
      // Right of '=' is value.
    while (keyValue.indexOf('+') > -1){
      keyValue = keyValue.substring(0,keyValue.indexOf('+')) + ' ' + keyValue.substring(keyValue.indexOf('+') + 1);
        // Replace each '+' in data string with a space.
    }

    keyValue = unescape(keyValue);
      // Unescape non-alphanumerics

    if (QueryData[keyName]){
      QueryData[keyName] = QueryData[keyName] + separator + keyValue;
        // Object already exists, it is probably a multi-select input,
        // and we need to generate a separator-delimited string
        // by appending to what we already have stored.
    }
    else{
      QueryData[keyName] = keyValue;
        // Normal case: name gets value.
    }
    QueryDataArray[QueryDataArray.length] = QueryData[keyName];
  }
  return QueryData;
}

function setParamInUrl(url, param, value){
/* This function takes a url, checks to see if the parameter/value pair already
exists in the url, and updates or appends the url accordingly. */
  var paramPos = url.indexOf(param+'=');

  if (paramPos < 0) {
    //param doesn't exist in the url at all, so add it
    addParamToUrl(url, param, value);
  } else {
    //param already exists, so lets change its value.
    var xistingValPos = paramPos + param.length + 1;
    var startStr      = url.substring(0, xistingValPos);
    var endStr        = url.substring(xistingValPos,url.length);
    var nextParamPos  = endStr.indexOf('&');

    if (nextParamPos >= 0) {
      endStr = endStr.substring(nextParamPos,endStr.length);
    } else {
      endStr = "";
    }
    url = startStr + value + endStr;
  }
  return url;
}

function addParamToUrl(url, param, value){
/* This function takes a url and adds the param/value to it.  Unlike
setParamInUrl, this function adds the param/value pair to the url
even if such a param/value pair already exists.  The use of such a
URL depends, of course, on the app server's ability to create an array
of param/value pairs when duplicate params are  passed in the request. */

  var query = (url.indexOf('?')>0) ? '&' : '?';
  url = url + query + param + '=' + value;
  return url;
}

/*-------------------------------------------
| Event binding - cross-browser
---------------------------------------------*/
function addEvent(el,strEvent,eventHandler){
	//first, remove any identical previous binding
	removeEvent(el,strEvent,eventHandler);
	//then create a new binding
  if (typeof attachEvent != 'undefined')  {
    el.attachEvent('on' + strEvent,eventHandler);
  }
  else{
    el.addEventListener(strEvent,eventHandler,true);
  }
}

function removeEvent(el,strEvent,eventHandler){
  if (typeof detachEvent != 'undefined') {
    el.detachEvent('on' + strEvent,eventHandler);
  }
  else {
    el.removeEventListener(strEvent,eventHandler,true);
  }
}

function cancelEventPropagation(e){
	if (typeof e.stopPropagation != 'undefined') {
		//DOM2-compliant
    e.stopPropagation();
    e.preventDefault();
	}
  else {
		//IE
    e.cancelBubble = true;
    e.cancel;
    e.returnValue = false;
  }
}

/*-------------------------------------------
| MISC
---------------------------------------------*/
function popWin (url,name,w,h) {
	var props = "";
	props += "width=" + (w ? w : 620) + ",";
	props += "height=" + (h ? h : 500) + ",";
	props += "alwaysLowered=0,alwaysRaised=0,channelmode=0,dependent=1,directories=0,fullscreen=0,hotkeys=1,location=0,menubar=0,resizable=1,scrollbars=1,status=0,titlebar=1,toolbar=1,z-lock=0";
	var newWin = window.open(url, name, props);
	newWin.focus();
	return newWin;
}

