/**
 * Executes the given function when the document is done loading.
 * Use this to add onload events.
 * @param onload_function pointer to the function to be executed
 */
function add_onload(onload_function) {
  Event.observe(window, 'load', onload_function);
}

/***** Form temporary default input data *****/
function setup_temporaries() {
  var temporaries = document.getElementsByTagName('input');
  for (var i = 0; i < temporaries.length; i++) {
    if (!temporaries[i]._tset && (temporaries[i].type == 'text' || temporaries[i].type == 'password'))
      inputTemporarySetup(temporaries[i]);
  }
  
  temporaries = document.getElementsByTagName('textarea');
  for (var i = 0; i < temporaries.length; i++) {
    if (!temporaries[i]._tset)
      inputTemporarySetup(temporaries[i]);
  }
}

function inputTemporarySetup(elem) {
  elem = z(elem);
  if (elem) {
    var text = elem.getAttribute("temporary") || elem.temporary;
    elem._tset = true;

    if (text && !text.match(/^\s*$/)) {
      elem.use_temporary_class = (elem.className && elem.className.match(/temporary/)) ? true : false;
      elem.prev_onfocus = elem.onfocus;
      elem.prev_onblur = elem.onblur;
      elem.temporary = text;
      
      // if the input is a password field, we want the temporary text to be visible.
      // this means we need to create a temporary input with value equal to the temporary,
      // and switch between the password and the text field.  setting password.type = 'text'
      // does not work in Internet Explorer (read-only property).
      if (elem.type == 'password') {
        var p_input = document.createElement('input');
        p_input._tset = true;
        p_input.elem = elem;
        p_input.value = text;
        p_input.type = 'text';
        p_input.className = elem.className;
        p_input.onfocus = passTemporaryFocus;
        if (elem.id) p_input.id = elem.id + '_t';
        p_input.style.width = elem.style.width;
        p_input.style.display = elem.style.display;
        p_input.style.visibility = elem.style.visibility;
        
        hide(elem);
        elem.p_input = p_input;
        elem.onhide = passTemporaryHide;
        elem.onshow = passTemporaryShow;
        elem.onblur = passTemporaryBlur;
        remove_class(elem, 'temporary');
        elem.parentNode.insertBefore(p_input, elem);
      } else {
        if (!elem.value) elem.value = text;
        else if (elem.use_temporary_class && elem.value != text) remove_class(elem, 'temporary');
        
        elem.onfocus = textTemporaryFocus;
        elem.onblur = textTemporaryBlur;
      }
    }
    
    var onEnter = elem.getAttribute("onenter") || elem.getAttribute("onEnter") || elem.onenter || elem.onEnter;
    if (onEnter) Event.observe(elem, 'keypress', onEnterFunction(elem, onEnter));
  }
}

function textTemporaryFocus() {
  if (this.temporary && this.value == this.temporary) {
    this.value = '';
    if (this.use_temporary_class && this.className)
      remove_class(this, 'temporary');
  }
  
  if (this.prev_onfocus) return this.prev_onfocus();
}

function textTemporaryBlur() {
  if (this.temporary && (this.value == "" || this.value == this.temporary)) {
    if (this.use_temporary_class) add_class(this, 'temporary');
    this.value = this.temporary;
  }
  
  if (this.prev_onblur) return this.prev_onblur();
}

function passTemporaryFocus() {
  this.style.display = 'none';
  this.style.visibility = 'hidden';
  this.elem.style.display = '';
  this.elem.style.visibility = 'visible';
  this.elem.focus();
  this.elem.select();
  
  if (this.elem.prev_onfocus) return this.elem.prev_onfocus();
}

function passTemporaryBlur() {
  passTemporaryShow.call(this);
  if (this.prev_onblur) return this.prev_onblur();
}

function passTemporaryHide() {
  this.p_input.style.display = 'none';
  this.p_input.style.visibility = 'hidden';
}

function passTemporaryShow() {
  if (this.value == '' || this.value == this.temporary) {
    this.value = '';
    this.style.display = 'none';
    this.style.visibility = 'hidden';
    this.p_input.style.display = '';
    this.p_input.style.visibility = 'visible';
  }
}

function onEnterFunction(elem, onEnter) {
  elem.onEnter = onEnter;
  return function(e) {
    e = window.event || e;
    if (e.keyCode == 13) {
      if (typeof onEnter == 'function')
        return this.onEnter();
      else
        return eval(this.onEnter);
    }
  }.bind(elem);
}

add_onload(setup_temporaries);

/**
 * Adds the given style class to the given element, ensuring that it does not already exist.
 * @param elem the element to classify.
 * @param className the style class to be added.
 */
function add_class(elem, className) {
  if (elem) {
    if (!elem.className || elem.className.length == 0)
      elem.className = className;
    else if (!elem.className.match('(^' + className + '$)|(^' + className + ' )|( ' + className + '$)|( ' + className + ' )'))
      elem.className += ' ' + className;
  }
}

/**
 * Removes the given style class from the given element.
 * @param elem the element to declassify.
 * @param className the style class to be removed.
 */
function remove_class(elem, className) {
  if (elem && elem.className) {
    elem.className = elem.className.replace(new RegExp('^' + className + '()()$'), '$2')
                                   .replace(new RegExp('^' + className + '( )()'), '$2')
                                   .replace(new RegExp('( )' + className + '( )'), '$2')
                                   .replace(new RegExp('( )' + className + '()$'), '$2');
  }
}

/**
 * Returns whether the given element has the given style class
 * @param elem the element to classify.
 * @param className the style class to be probe for existence
 */
function has_class(elem, className) {
  if (elem) {
    if (!elem.className || elem.className.length == 0)
      return false;
    else 
      return (elem.className.match('(^' + className + '$)|(^' + className + ' )|( ' + className + '$)|( ' + className + ' )'))
  } else {
    return false;
  }
}

/**
 * Returns the last stylesheet rule matching the selector
 * @param selector style selector declaration
 */
function getStylesheetRule(selector) {
  var r = document.styleSheets[0].cssRules ? 'cssRules' : 'rules';
  
  for (var i = document.styleSheets.length - 1; i >= 0; i--)
    for (var j = document.styleSheets[i][r].length - 1; j >= 0; j--)
      if (document.styleSheets[i][r][j].selectorText == selector) return document.styleSheets[i][r][j];
  
  return null;
}

/**
 * Copy of prototype.js $(), but without Element.extend() overhead.
 * This helps prevent IE6 memory leaks, and decreases overall execution time.
 */
function z() {
  var results = [], e;
  for (var i = 0; i < arguments.length; i++) {
    e = arguments[i];
    if (typeof e == 'string')
      e = document.getElementById(e);
    results.push(e);
  }
  return results.length < 2 ? results[0] : results;
}

/**
 * Copy of Element.hide(), but uses z() instead of $().
 * Also changes style.visibility property to overcome some IE flaws.
 */
function hide() {
  var e = null;
  
  for (var i = 0; i < arguments.length; i++) {
    e = z(arguments[i]);
    if (e) {
      e.style.visibility = 'hidden';
      e.style.display = 'none';
      if (e.onhide) e.onhide();
    }
  }
  
  for (var i = 0; i < Element.hideListeners.length; i++)
    Element.hideListeners[i].call(e);
  
  return e;
}

/**
 * Copy of Element.show(), but uses z() instead of $().
 * Also changes style.visibility property to overcome some IE flaws.
 */
function show() {
  var e = null;
  
  for (var i = 0; i < arguments.length; i++) {
    e = z(arguments[i]);
    if (e) {
      e.style.visibility = 'visible';
      e.style.display = '';
      if (e.onshow) e.onshow();
    }
  }
  
  for (var i = 0; i < Element.showListeners.length; i++)
    Element.hideListeners[i].call(e);
  
  return e;
}

/**
 * Copy of Element.visible(), but uses z() instead of $().
 */
function visible(e) {
  return z(e).style.display != 'none';
}

/**
 * Copy of Element.toggle(), but uses z() instead of $().
 */
function toggle() {
  for (var i = 0; i < arguments.length; i++) {
    var e = z(arguments[i]);
    visible(e) ? hide(e) : show(e);
  }
}
  
Element.top = function(elem) {
  return elem ? ((Prototype.Browser.IE ? elem.clientTop + elem.offsetTop : elem.offsetTop) + Element.top(elem.offsetParent)) : 0;
},

// replace Element methods to account for style.visibility property changes
Element.show = show;
Element.hide = hide;
Element.toggle = toggle;
Element.visible = visible;
Element.Methods['show'] = show;
Element.Methods['hide'] = hide;
Element.Methods['toggle'] = toggle;
Element.Methods['visible'] = visible;

// allow element to register for show/hide events, since these often cause
// a browser resize, but dont trigger onresize() in IE.
Element.hideListeners = [];
Element.showListeners = [];