/* This file contains three separate Javascript libraries:
/* ajax.js, behavior.js and glossary.js
/*
/*
 * Copyright 2006 SitePoint Pty. Ltd, www.sitepoint.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
function Ajax() {
  this.req = null;
  this.url = null;
  this.status = null;
  this.statusText = '';
  this.method = 'GET';
  this.async = true;
  this.dataPayload = null;
  this.readyState = null;
  this.responseText = null;
  this.responseXML = null;
  this.handleResp = null;
  this.responseFormat = 'text', // 'text', 'xml', 'object'
  this.mimeType = null;
  this.headers = [];

  
  this.init = function() {
    var i = 0;
    var reqTry = [ 
      function() { return new XMLHttpRequest(); },
      function() { return new ActiveXObject('Msxml2.XMLHTTP') },
      function() { return new ActiveXObject('Microsoft.XMLHTTP' )} ];
      
    while (!this.req && (i < reqTry.length)) {
      try { 
        this.req = reqTry[i++]();
      } 
      catch(e) {}
    }
    return true;
  };
  this.doGet = function(url, hand, format) {
    this.url = url;
    this.handleResp = hand;
    this.responseFormat = format || 'text';
    this.doReq();
  };
  this.doPost = function(url, dataPayload, hand, format) {
    this.url = url;
    this.dataPayload = dataPayload;
    this.handleResp = hand;
    this.responseFormat = format || 'text';
    this.method = 'POST';
    this.doReq();
  };
  this.doReq = function() {
    var self = null;
    var req = null;
    var headArr = [];
    
    if (!this.init()) {
      alert('Could not create XMLHttpRequest object.');
      return;
    }
    req = this.req;
    req.open(this.method, this.url, this.async);
    if (this.method == "POST") {
      this.req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    }
    if (this.method == 'POST') {
      req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    }
    self = this;
    req.onreadystatechange = function() {
      var resp = null;
      self.readyState = req.readyState;
      if (req.readyState == 4) {
        
        self.status = req.status;
        self.statusText = req.statusText;
        self.responseText = req.responseText;
        self.responseXML = req.responseXML;
        
        switch(self.responseFormat) {
          case 'text':
            resp = self.responseText;
            break;
          case 'xml':
            resp = self.responseXML;
            break;
          case 'object':
            resp = req;
            break;
        }
        
        if (self.status > 199 && self.status < 300) {
          if (!self.handleResp) {
            alert('No response handler defined ' +
              'for this XMLHttpRequest object.');
            return;
          }
          else {
   			pageTracker._trackPageview("/glossary");
			self.handleResp(resp);
          }
        }
        
        else {
          self.handleErr(resp);
        }
      }
    }
    req.send(this.dataPayload);
  };
  this.abort = function() {
    if (this.req) {
      this.req.onreadystatechange = function() { };
      this.req.abort();
      this.req = null;
    }
  };
  this.handleErr = function() {
    var errorWin;
    // Create new window and display error
    try {
      errorWin = window.open('', 'errorWin');
      errorWin.document.body.innerHTML = this.responseText;
    }
    // If pop-up gets blocked, inform user
    catch(e) {
      alert('An error occurred, but the error message cannot be' +
      ' displayed because of your browser\'s pop-up blocker.\n' +
      'Please allow pop-ups from this Web site.');
    }
  };
  this.setMimeType = function(mimeType) {
    this.mimeType = mimeType;
  };
  this.setHandlerResp = function(funcRef) {
    this.handleResp = funcRef;
  };
  this.setHandlerErr = function(funcRef) {
    this.handleErr = funcRef; 
  };
  this.setHandlerBoth = function(funcRef) {
    this.handleResp = funcRef;
    this.handleErr = funcRef;
  };
  this.setRequestHeader = function(headerName, headerValue) {
    this.headers.push(headerName + ': ' + headerValue);
  };
  
}
/*
   Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
   of Simon Willison (see comments by Simon below).

   Description:
   	
   	Uses css selectors to apply javascript behaviours to enable
   	unobtrusive javascript in html documents.
   	
   Usage:   
   
	var myrules = {
		'b.someclass' : function(element){
			element.onclick = function(){
				alert(this.innerHTML);
			}
		},
		'#someid u' : function(element){
			element.onmouseover = function(){
				this.innerHTML = "BLAH!";
			}
		}
	};
	
	Behaviour.register(myrules);
	
	// Call Behaviour.apply() to re-apply the rules (if you
	// update the dom, etc).

   License:
   
   	This file is entirely BSD licensed.
   	
   More information:
   	
   	http://ripcord.co.nz/behaviour/
   
*/   

var Behaviour = {
	list : new Array,
	
	register : function(sheet){
		Behaviour.list.push(sheet);
	},
	
	start : function(){
		Behaviour.addLoadEvent(function(){
			Behaviour.apply();
		});
	},
	
	apply : function(){
		for (h=0;sheet=Behaviour.list[h];h++){
			for (selector in sheet){
				list = document.getElementsBySelector(selector);
				
				if (!list){
					continue;
				}

				for (i=0;element=list[i];i++){
					sheet[selector](element);
				}
			}
		}
	},
	
	addLoadEvent : function(func){
		var oldonload = window.onload;
		
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	}
}

Behaviour.start();

/*
   The following code is Copyright (C) Simon Willison 2004.

   document.getElementsBySelector(selector)
   - returns an array of element objects from the current document
     matching the CSS selector. Selectors can contain element names, 
     class names and ids and can be nested. For example:
     
       elements = document.getElementsBySelect('div#main p a.external')
     
     Will return an array of all 'a' elements with 'external' in their 
     class attribute that are contained inside 'p' elements that are 
     contained inside the 'div' element which has id="main"

   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
   See http://www.w3.org/TR/css3-selectors/#attribute-selectors

   Version 0.4 - Simon Willison, March 25th 2003
   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
   -- Opera 7 fails 
*/

function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function(selector) {
  // Attempt to fail gracefully in lesser browsers
  if (!document.getElementsByTagName) {
    return new Array();
  }
  // Split selector in to tokens
  var tokens = selector.split(' ');
  var currentContext = new Array(document);
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById(id);
	  if (element!=undefined) {
		  if (tagName && element.nodeName.toLowerCase() != tagName) {
			// tag with that ID not found, return false
			return new Array();
		  }
	  }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf('.') > -1) {
      // Token contains a class selector
      var bits = token.split('.');
      var tagName = bits[0];
      var className = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words 
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
      continue; // Skip to next token
    }
    
    if (!currentContext[0]){
    	return;
    }
    
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained 
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute 
   Tag
*/
/*
vuDAT - Michigan State University
written by:  Nathan Lounds
*/
vuDAT_glossary_css = window.vuDAT_glossary_css || "glossary/glossary.css";
vuDAT_glossary = window.vuDAT_glossary || "glossary/glossary.txt";
section = window.section || "";  // set section = "" if section hasn't been defined
var timer;
var tmp_word = "";
var ajaxHandlers = {
	start : function(){
		ajaxHandlers.addLoadEvent(function(){
			// code in here gets executed once the page loads // begin section
			
			//<![CDATA[
			// loading the stylesheet into the document header
			if(document.createStyleSheet) { // non-standard IE way of doing it
				document.createStyleSheet(vuDAT_glossary_css);
			} else { // do it the W3C DOM way
				var newCSS=document.createElement('link');
				newCSS.rel='stylesheet';
				newCSS.href=vuDAT_glossary_css;
				newCSS.type='text/css';
				document.getElementsByTagName("head")[0].appendChild(newCSS);
			}
			//]]>
			
			var self = ajaxHandlers;
			self.ajax = new Ajax();
			var the_gloss = document.getElementsBySelector(".glossary");
			if(the_gloss) {
				for (i = 0; i < the_gloss.length; i++) {
					the_gloss[i].className = "highlightSpan";	
				}
			}
			the_words = document.getElementsBySelector(".highlightSpan");
			if(the_words) {
				var cur_word = "";
				for (i = 0; i < the_words.length; i++) {
					cur_word = the_words[i];
					cur_word.onmouseover = function() {
						tmp_word = this;
						stopper();
						self.getDefinition();
					}
					cur_word.onmouseout = function() {
						var the_div = document.getElementById("clickPosText");
						if(the_div) {
							timer = setTimeout("clickPosTextKill()",1200);
							//trace("timeout to kill");
						}
					}
					cur_word.onclick = function() {
						var me = this;
						var the_div = document.getElementById("clickPosText");
						the_div.title = "click to close";
						tmp_word = me;
						self.getDefinition();
					}
				}
			}
			ajaxHandlers.getGlossary();
			// code in here gets executed once the page loads // end section
		});
	},
	getDefinition : function() {
		//trace("getDefinition");
		clickPosText(tmp_word,"...looking for definition...");
		var self = ajaxHandlers;
		self.ajax.doGet(vuDAT_glossary,self.handleDefinition);
		//alert(vuDAT_glossary);
	},
	handleDefinition : function(str) {
		//trace("handleDefinition");
		var the_cont = document.getElementById("clickPosText");
		var the_words = str.split("\n");
		for (i = 0; i < the_words.length; i++) {
			var the_word = the_words[i].split("|");
			var the_term = tmp_word.childNodes[0].nodeValue;
			if(the_word[0].toUpperCase()==the_term.toUpperCase()) {
				if((the_word[1].toUpperCase()==section.toUpperCase())&&(the_word.length==3)) {
					the_cont.innerHTML = the_word[2];
					var my_diff = document.body.clientWidth-document.body.scrollWidth;
					if(my_diff!=0) {
						moveIt(the_cont,my_diff);
					}
					return true;
				} else if (the_word.length==2) {
					the_cont.innerHTML = the_word[1];
					var my_diff = document.body.clientWidth-document.body.scrollWidth;
					if(my_diff!=0) {
						moveIt(the_cont,my_diff);
					}
					return true;
				}
			}
		}
		the_cont.innerHTML = "<span class=\"red\">not in glossary</span>";
		var my_diff = document.body.clientWidth-document.body.scrollWidth;
		if(my_diff!=0) {
			moveIt(the_cont,my_diff);
		}
	},
	getGlossary : function() {
		var the_cont = document.getElementById("glossary");
		if(the_cont) {
			var self = ajaxHandlers;
			self.ajax = new Ajax();
			self.ajax.doGet(vuDAT_glossary,self.handleGlossary);
		}
	},
	handleGlossary : function(str) {
		var the_cont = document.getElementById("glossary");
		var the_words = str.split("\n");
		var ul = document.createElement("ul");
		for (i = 0; i < the_words.length; i++) {
			var the_word_arr = the_words[i].split("|");
			if(the_word_arr) {
				var the_word = the_word_arr[0];
				var the_def = "";
				var the_section = "";
				var li = document.createElement("li");
				if(the_word_arr.length==3) {
					the_section = " (" + the_word_arr[1] + ")";
					the_def = the_word_arr[2];
				} else if (the_word_arr.length==2) {
					the_def = the_word_arr[1];
				}
				li.innerHTML = "<strong>" + the_word + the_section + "</strong>: " + the_def;
				ul.appendChild(li);
			}
		}
		the_cont.appendChild(ul);
	},
	addLoadEvent : function(func){
		var oldonload = window.onload;
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	}
}
ajaxHandlers.start();

function clickPosText(obj,txt) {
	clickPosTextKill();
	var container = document.createElement('div');
	var pos = findPos(obj);
	container.id = "clickPosText";
	container.style.top = (pos[1]+18) + "px";
	container.style.left = (pos[0]+obj.offsetWidth) + "px";
	container.innerHTML = txt;
	document.body.appendChild(container);
	container.onclick = function() {
		killMe(this);
	}
	container.onmouseover = function() {
		stopper();
	}
	container.onmouseout = function() {
		timer = setTimeout("clickPosTextKill()",1200);
		//trace("timeout to kill (cont)");
	}
}
function clickPosTextKill() {
	//trace("clickPosTextKill()");
	var att = document.getElementById("clickPosText");
	if(att) {
		att.parentNode.removeChild(att);
	}
}
function moveIt(obj,howFar) {
	//trace("moveIt("+obj+","+howFar+")");
	var pos = findPos(obj);
	var the_pos = parseInt(obj.style.left);
	obj.style.left = (the_pos+howFar) + "px";
}
function stopper() {
	//trace("stopper()");
	clearTimeout(timer);
}
function killMe(obj) {
	obj.parentNode.removeChild(obj);
}
/* 
Find Position of object
http://www.quirksmode.org/js/findpos.html
*/
function findPos(obj) {
	//trace("findPos("+obj+")");
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop];
}