// VIVO JavaScript Framework 1.1
// Copyright (c) 2006 Jeremy Raadt (jraadt@hotmail.com)
// Copyright (c) 2006 Andy Altepeter (aaltepet@altepeter.net)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


var Vivo = {
  Version: '1.1',

  toolTypes: new Hashtable(),

  require: function(libraryName) {
    // inserting via DOM fails in Safari 2.0, so brute force approach
    document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
  },

  start: function() {
    if((typeof Prototype=='undefined') ||
      parseFloat(Prototype.Version.split(".")[0] + "." +
                 Prototype.Version.split(".")[1]) < 1.4)
      throw("VIVO requires the Prototype JavaScript framework >= 1.4.0");
    if((typeof Scriptaculous=='undefined') ||
      parseFloat(Scriptaculous.Version.split(".")[0] + "." +
                 Scriptaculous.Version.split(".")[1]) < 1.5)
      throw("VIVO requires the script.aculo.us >= 1.5.0");
    var scriptTags = document.getElementsByTagName("script");
    for(var i=0;i<scriptTags.length;i++) {
      if(scriptTags[i].src && scriptTags[i].src.match(/vivo\.js(\?.*)?$/)) {
        var path = scriptTags[i].src.replace(/vivo\.js(\?.*)?$/,'');
        //this.require(path + 'vivo-utils.js');
        //this.require(path + 'vivo-tools.js');
        break;
      }
    }

    this.addLoadEvent(function() {
      Vivo.apply();
    });
    this.toolTypes.put("vivo:collapsible", initCollapsibleTool);
    this.toolTypes.put("vivo:tab", initTabTool);
    this.toolTypes.put("vivo:draggable", initDraggableTool);
    this.toolTypes.put("vivo:droppable", initDroppableTool);
    this.toolTypes.put("vivo:autocomplete", initAutocompleteTool);
    this.toolTypes.put("vivo:inplaceeditor", initInPlaceEditorTool);
    this.toolTypes.put("vivo:batchlink", initBatchLinkTool);
    this.toolTypes.put("vivo:inpagetooltip", initInPageTooltipTool);
  },

  applyOnNode: function(node) {
    id = assignId(node);
    for (var j=0; j < this.toolTypes.keys.length; j++) {
      currentAttribute = this.toolTypes.keys[j];
      if(attr = node.getAttribute(currentAttribute)){ // IE5/Mac fix
	initFunction = this.toolTypes.get(currentAttribute);
	initFunction(id, node.getAttribute(currentAttribute));
      }
    }
  },

  generateXpathQuery: function() {
    var q  = "//xhtml:*[";
    for (j = 0; j < this.toolTypes.keys.length; j++) {
      q += "@" + this.toolTypes.keys[j];
	if (j < this.toolTypes.keys.length-1)  q += '|';
    }
    q += ']';
    return q;
  },

  isXHTML: function() {
    metas = document.getElementsByTagName('meta');
    for (i=0;i<metas.length;i++) {
      meta = metas[i];
      is_http = meta.getAttribute('http-equiv');
      content = meta.getAttribute('content');
      if (is_http && is_http.toLowerCase()=='content-type' &&
	content && content.toLowerCase().search(/xml/)>-1) {
	return true;
      }
    }
    return false;
  },

  apply: function(dom) {
    if (dom == null || dom.nodeType != 1) {
      dom = document;
    }
    
    //document.evaluate only works (in FF) if content-type is xhtml 
    //so, test document.evaluate and ct=xhtml
    if (this.isXHTML() && document.evaluate) {
      nsResolver = function(prefix) {
	if (prefix=='vivo') {
	  return 'http://www.bethel.edu/namespaces/vivo';
	} else if (prefix=='html') {
	  return 'http://www.w3.org/1999/xhtml'
	} else if (prefix=='xhtml') {
	  return 'http://www.w3.org/1999/xhtml'
	} else {  return 'http://www.w3.org/1999/xhtml'; }
      };

      //generate xpath
      xpathQuery = this.generateXpathQuery();
      /*Apparrently we can't use a node iterator, because some tools (e.g. collapsible 
       with initialstate=close, changing style.display is considered modifying the DOM,
       which invalidates the NodeList.  So, using a snapshot instead.  This has
       to be with the understanding that no elements acted on in the tools
       are removed (and perhaps other conditions?  Modified in any way? */
      var xpathResult = document.evaluate(xpathQuery, dom, nsResolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
      for (var z=0; z < xpathResult.snapshotLength; z++) {
	this.applyOnNode(xpathResult.snapshotItem(z));
      }
      /*var xpathResult = document.evaluate(xpathQuery, dom, nsResolver, XPathResult.UNORDERED_NODE_ITERATOR_TYPE,null);
      while(vivoItem = xpathResult.iterateNext()) {
	this.applyOnNode(vivoItem);
	}*/
    }
    else { // no mozilla xpath
      var elements = getElementsByVivoAttributes(this.toolTypes.keys, dom);
      var currentAttribute = null;
      for (var i=0; i < elements.length; i++) {
	//find which vivo tools are on this element
	for (var j=0; j < this.toolTypes.keys.length; j++) {
	  currentAttribute = this.toolTypes.keys[j];
	  if(attr = elements[i].getAttribute(currentAttribute)){ // IE5/Mac fix
	    id = assignId(elements[i]);
	    initFunction = this.toolTypes.get(currentAttribute);
	    initFunction(id, elements[i].getAttribute(currentAttribute));
	  }
	}
      }
    };
  },

  addLoadEvent: function(func) {
    /*silva's onload_registry*/
    if (window.onload_registry) {
      window.onload_registry.register(func);
    } else {
      var oldonload = window.onload;
      if (typeof window.onload != 'function') {
	window.onload = func;
      }
      else {
	window.onload = function() {
	  oldonload();
	  func();
	}
      }
    }
  }
}

Vivo.start();



// DEFAULT INIT FUNCTIONS

function initInPageTooltipTool(id, params) {
  var element = id;
  var tooltipElement = null;
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "tooltipElement") {
        eval(pName + " = pValue");
      }
      else if (pName == "extraCallback") {
        eval("var aFunction = function() { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element && tooltipElement) {
    eval("new InPageTooltip(element, tooltipElement, {" + parameters + "})");
  }
}


function initCollapsibleTool(id, params) {
  var element = id;
  var collapsibleElement = null;
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "collapsibleElement") {
        eval(pName + " = pValue");
      }
      else if (pName == "callback") {
        eval("var aFunction = function() { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element && collapsibleElement) {
    eval("new Collapsible(element, collapsibleElement, {" + parameters + "})");
  }
}

function initTabTool(id, params) {
  var element = id;
  var contentElement = null;
  var tabGroupElement = null;
  var url = "";
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "contentElement" || pName == "tabGroupElement" || pName == "url") {
        eval(pName + " = pValue");
      }
      else if (pName == "onComplete" || pName == "onLoading") {
        eval("var aFunction = function() { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element && contentElement && tabGroupElement && url) {
    eval("new Tab(element, contentElement, tabGroupElement, url, {" + parameters + "})");
  }
}

function initBatchLinkTool(id, params) {
  var element = id;
  var contentElement = null;
  var parameters = "";
  var paramsArray = params.split("|");
  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "contentElement") {
        eval(pName + " = pValue");
      }
      else if (pName == "onComplete" || pName == "onLoading") {
        eval("var aFunction = function() { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element && contentElement) {
    eval("new BatchLink(element, contentElement, {" + parameters + "})");
  }
}


function initDraggableTool(id, params) {
  var element = id;
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "change") {
        eval("var aFunction = function() { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element) {
    eval("new Draggable(element, {" + parameters + "})");
  }
}

function initDroppableTool(id, params) {
  var element = id;
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "onHover") {
        eval("var aFunction = function(dragElement, dropElement, overlapPercent) { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else if (pName == "onDrop") {
        eval("var aFunction = function(dragElement, dropElement) { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element) {
    eval("Droppables.add(element, {" + parameters + "})");
  }
}

function initAutocompleteTool(id, params) {
  var element = id;
  var resultsElement = null;
  var url = null;
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "resultsElement" || pName == "url") {
        eval(pName + " = pValue");
      }
      else if (pName == "afterUpdateElement") {
        eval("var aFunction = function(inputField, selectedItem) { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element && resultsElement && url) {
    eval("new Ajax.Autocompleter(element, resultsElement, url, {" + parameters + "})");
  }
}

function initInPlaceEditorTool(id, params) {
  var element = id;
  var url = null;
  var parameters = "";
  var paramsArray = params.split("|");

  for (var i = 0; i < paramsArray.length; i++) {
    var j = paramsArray[i].indexOf("=");
    if (j > 0) {
      var pName = paramsArray[i].substring(0,j);
      var pValue = paramsArray[i].substring(j+1);
      if (pName == "url") {
        eval(pName + " = pValue");
      }
      else if (pName == "callback") {
        eval("var aFunction = function() { eval(" + pValue + "); }");
        parameters += pName + ": " + aFunction + ", ";
      }
      else {
        parameters += pName + ": '" + pValue + "', ";
      }
    }
  }

  if (parameters.length > 0) {
    parameters = parameters.substring(0,parameters.lastIndexOf(","));
  }

  if (element && url) {
    eval("new Ajax.InPlaceEditor(element, url, {" + parameters + "})");
  }
}
