(function() {

	// private constructor
	function _oye(els) {			
		var str = els[0];
		if(typeof str == 'object'){
			this.elements = [];
			for(var i=0; i<els.length; i++){
				var element = els[i];
				if(typeof element == 'string'){
					element = $(element);
				}
				this.elements.push(element);
			}
		} else {
			this.elements = oye.getSelectors(str);
		}
		return this;
		
  }

  _oye.prototype = {    
    each: function(fn) {          	
      for ( var i = 0, len = this.elements.length; i<len; ++i ) {
        fn.call(this, this.elements[i]);
      }
      return this;
    },
    
    id:function(els){
    	var elements = [];
    	for(var i=0; i<els.length; i++){
    		element = els[i];
    		if(typeof element == 'string') element = document.getElementById(element);
    		elements.push(element);
    	}
    	return this;
    },	
    
    attr: function(prop, val) {
      this.each(function(el) {
        el.prop = val;
      });
      return this;
    },
    
    setStyle: function(prop, val) {
      this.each(function(el) {
        el.style[prop] = val;
      });
      return this;
    },
    
   	toggle:function(el){
   		this.each(function(el) {
			if(el.style.display == 'block' || el.className.match(/show/)){
				el.className = el.className.replace(/show/, '');
				oye(el).addClass('hidden');
				el.style.display = 'none';
			} else {
				el.className = el.className.replace(/hidden/, '');
				oye(el).addClass('show');
				el.style.display = 'block';
			}
		});
		return this;
	},
	
	hasClass: function(className){
  		var pattern = new RegExp("(^| )" + className + "( |$)");  		
  		this.each(function(el){
  			if(pattern.test(el.className)) return 'yep';
  			else return false;
  		});
  		return this;
    },
 
    addClass: function(className) {
      this.each(function(el) {
        el.className += ' '+className;
      });
      return this;
    },    
    
    removeClass:function(className){
    	this.each(function(el){
    		el.className = el.className.replace(className, '');
    	});
    	return this;
    },
    
    hide:function(el){
    	this.each(function(el){
    		oye.hide(el);
    	});
    },
    
    show:function(el){
    	this.each(function(el){
    		oye.show(el);
    	});
    },
    
    on: function(type, fn) {
    	if(type == 'click'){
    		for(a=0; a<this.elements.length; a++){
    			if(this.elements[a]){
    				this.elements[a].onclick = function(){
    					fn.apply(this);
    					return false;
    				}  	
    			}		
    		}    		
    	} else {
	      var listen = function(el) {
	        if (window.addEventListener) {
	          el.addEventListener(type, fn, false);  
	        } else if (window.attachEvent) {
	          el.attachEvent('on'+type, function() {
	            fn.call(el, window.event);
	          });
	        }
	      };
      
      	this.each(function(el) {
      	  listen(el);
      	});
      }
      return this;
    },  
    
    css: function(o) {
      var that = this;
      this.each(function(el) {
        for (var prop in o) {
          that.setStyle(prop, o[prop]);
        }
      });
      return this;
    },
    
    html:function(o){
    	this.each(function(el){
    		el.innerHTML = o;
    	});
    },
    
    inject:function(o){
    	this.each(function(el){
    		var val = el.innerHTML.replace(o, '');
    		el.innerHTML = val + o;
    	});
    },
    
    removeHTML:function(o){
    	this.each(function(el){
    		el.innerHTML = el.innerHTML.replace(o, '');
    	});
    },
    
    setValue: function(o){
    	this.each(function(el){
    		el.value = o;
    	});
    }, 
    
    fadeIn:function(o){
    	var that = this;
    	this.each(function(el){
    		// get starting position
    		var startX 	= oye.parentX(el);
    		var endX	= o['x'] || 0;
    		var startY 	= oye.parentY(el);
    		var endY 	= o['y'] || 0;
	   		var ntime = o['time']*100 || 100;    		    		
   
    		if(window.movement) clearTimeout(window.movement);
    		
    		if(endX == startX) return true;
    		
			if(startX < endX){
			  var distance = Math.ceil((endX - startX)/10);
			  startX = startX + distance;
			}	
			if(startX > endX){
			  var distance = Math.ceil((startX - endX)/10);
			  startX = startX - distance;
			}
			
			$(el).style.left = startX+'px';
			window.movement = setTimeout( function(){
				oye(el).fadeIn({x:endX, y:endY, time:o['time']})
				}, o['time']);
			
	  	});
	  }
  };
  var oye = window.oye = function() {
    return new _oye(arguments);
  }
})();


oye.extend = function() {

	// copy reference to target object
	var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false;

	// Handle a deep copy situation
	if ( target.constructor == Boolean ) {
		deep = target;
		target = arguments[1] || {};
	}

	// extend oye itself if only one argument is passed
	if ( al == 1 ) {
		target = this;
		a = 0;
	}

	var prop;

	for ( ; a < al; a++ )
		// Only deal with non-null/undefined values
		if ( (prop = arguments[a]) != null )
			// Extend the base object
			for ( var i in prop ) {
				// Prevent never-ending loop
				if ( target == prop[i] )
					continue;

				// Recurse if we're merging object values
				if ( deep && typeof prop[i] == 'object' && target[i] )
					oye.extend( target[i], prop[i] );

				// Don't bring in undefined values
				else if ( prop[i] != undefined )
					target[i] = prop[i];
			}
	// Return the modified object
	return target;
};

var userAgent = navigator.userAgent.toLowerCase();

// Figure out what browser is being used
oye.browser = {
	version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1],
	safari: /webkit/.test(userAgent),
	opera: /opera/.test(userAgent),
	msie: /msie/.test(userAgent) && !/opera/.test(userAgent),
	mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent)
};

// ELEMENT PROPERTIES
oye.extend({
	
	getStyle:function(elem, name){	
	    if(elem.style[name]) {	    	
	    	return elem.style[name];
	    } else if (elem.currentStyle) {
	    	return elem.currentStyle[name];
		} else if (document.defaultView && document.defaultView.getComputedStyle){
	    	name = name.replace(/([A-Z])/g, "-&1");
	    	name = name.toLowerCase();
	    	
	    	var s = document.defaultView.getComputedStyle(elem, "");
	    	return s && s.getPropertyValue(name);
	    } else
	    	return null;			    
	},	
	
	getHeight:function(elem){
    	return parseInt(oye.getStyle(elem, 'height'));
	},

	getWidth:function(elem){
	    return parseInt(getStyle($(elem), 'width'));
	},

	fullHeight:function(elem){
	    if(oye.getStyle(elem, 'display') != 'none')
	    	return elem.offsetHeight || oye.getHeight(elem);	    
			    
	    // style is set to display none. reset the CSS	    
	    var old = oye.resetCSS(elem, {
	    	display:'',
	    	visibility:'hidden',
	    	position:'absolute'
	    });	    
	    var h = elem.clientHeight || oye.getHeight(elem);	    	    
	    oye.restoreCSS(elem, old);
	    return h;	    
	},

	fullWidth:function(elem){
		if(getStyle(elem, 'display') != 'none')
			return elem.offsetWidth || getWidth(elem);
		
		var old = resetCSS(elem, {
			display : '',
			visibility:'hidden',
			position:'absolute'
		});
		
		var w = elem.clientWidth || getWidth(elem);
		oye.restoreCSS(elem, old);
		return w;
	},
	
	resetCSS:function(elem, prop){
	    var old = {};
	    for(var i in prop){
	    	old[i] = elem.style[i];
	    	elem.style[i] = prop[i];
	    }
	    
	    return old;
	},
	
	restoreCSS:function(elem, prop){
	    for(var i in prop) elem.style[i] = prop[i];
	}	
	
});

// ANIMATIONS
oye.extend({
	slideDown:function(elem, h){
	    if(!elem) return false;	    	    
	    
	    // IF NO h SPECIFIED, h IS THE FULL POTENTIAL HEIGHT OF ELEMENT. 
	    // SET HEIGHT OF ELEMENT TO 0px
		if(!h) h = oye.fullHeight(elem);		
	    elem.style.height = '0px';
	
	    var regex = new RegExp("(^|\\s)(hidden)(\\s|$)");    
		if(regex.test(elem.className)){
			elem.className = elem.className.replace('hidden', 'show');			
		} else {
			oye(elem).setStyle('display', 'block');
		}
		   
	    for(var i=0; i<=100; i += 10){
	    	(function(){
	    		var pos = i;
	    		setTimeout( function(){
	    			elem.style.height = ((pos/100)*h)+"px"
	    		}, (pos +1)*10);
	    	})();
	    }        
	},

	slideUp:function(elem, h){
		if(!$(elem)) return false;
		var elem = $(elem);
		if(!h) h = fullHeight(elem);				
		
		for(var i=100; i>=0; i-=10) {
			(function(){
				var pos = i;
				setTimeout( function(){								
					if(pos == 100)
						oye(elem).hide();
					else
						elem.style.height = (h-((pos/100)*h))+'px'					
				}, (pos+1)*10);
			})();	
		}
		
	}

});

// BASIC DOM MANIPULATION
oye.extend({
	log: function(o){
		console.log(o);
	},
	
    create:function(elem, options){
		var elem = document.createElementNS ? 
			document.createElementNS('http://www.w3.org/1999/xhtml', elem) : 
			document.createElement(elem);
		
		for(var o in options){
			switch(o){
				case 'parent':
					oye.append(options[o], elem);
				break;
				
				case 'innerHTML':
					elem.innerHTML = options[o];
				break;
				
				case 'className':
					oye(elem).addClass(options[o]);
				break;
				
				default:
					elem.setAttribute(o, options[o]);
				break;
			}
		}
    },
	
	append:function(parent, elem){
		var parent = $(parent);
		parent.appendChild(this.checkElem(elem));
	},

	checkElem:function (elem){
		return elem && elem.constructor == String ? 
		document.createTextNode(elem) : elem;
	},

	remove:function(el){
		el = $(el);
		if(el) el.parentNode.removeChild(el);
	},
	
	show:function(el){
		if(!el) return false;
		el.style.display = 'block';
		if(el.className.match(/hidden/)) oye(el).removeClass('hidden'); // remove hidden class
		oye(el).addClass('show');	   // add show class
	},
	
	hide:function(el){
		if(!el) return false;
		if(el.style.display !== 'none')   el.style.display = 'none';
		if(el.className.match(/show/)) 	  oye(el).removeClass('show'); // remove show class
		if(!el.className.match(/hidden/)) oye(el).addClass('hidden');  // add hidden class
	},
	
	nextItem : function(item) {
		var item = $(item);
		if (item == null) return
		var next = item.nextSibling
		while (next != null) {
			if (next.nodeName.toLowerCase() == item.nodeName.toLowerCase()) return next
			next = next.nextSibling
		}
		return null
	},

	previousItem : function(item) {
		var item = $(item);
		var previous = item.previousSibling
		while (previous != null) {
			if (previous.nodeName.toLowerCase() == item.nodeName.toLowerCase()){ 	
				return previous			
			}
			previous = previous.previousSibling
		}
		return null
	},

	moveBefore : function(item1, item2) {
		var item1 = $(item1);
		var item2 = $(item2);
		var parent = item1.parentNode
		parent.removeChild(item1)
		parent.insertBefore(item1, item2)
	},

	moveAfter : function(item1, item2) {
		var item1 = $(item1);
		var item2 = $(item2);
		var parent = item1.parentNode
		parent.removeChild(item1)
		parent.insertBefore(item1, item2 ? item2.nextSibling : null)
	},
	
	hasClass:function(el, theClass){	
		var pattern = new RegExp("(^| )" + theClass + "( |$)");
		
		if (pattern.test(el.className)){
		  return true;
		}		
		return false;
	}
});


// AJAX CLASS
oye.extend({
	get: function (url, options) {
		this.options = options;
		var xml;
		
		if(!url) return false;
		if(!this.options.method)	{ 
			this.options.method = 'post';
		} else {		
			url = (this.options.method == 'get') ? url + '?'+this.options.parameters : url;			
		}
		try { xml = new XMLHttpRequest(); }
		catch(e) {
			var versions = new Array('MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.5.0','MSXML2.HTTP.4.0','MSXML.HTTP.3.0','MSXML2.HTTP','Microsoft.XMLHTTP');
			for(var i=0; i<versions.length && !xml; i++) {
				try { xml = new ActiveXObject(versions[i]); }
				catch(e) { console.log(e); } // ignore potential errors
			}
		}		
		if(xml) { // make the request	
			this.xml = xml;								
			xml.onreadystatechange = function() { oye.handler(); }			
			xml.open(this.options.method, url, true);
			if(this.options.method == 'post'){				
				xml.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
				xml.setRequestHeader('Content-length', this.options.parameters.length);
				xml.setRequestHeader('Connection', 'close');
				xml.send(this.options.parameters);
			} else {				
				xml.send(null);
			}			
		} else {
			console.log('no xml');
		}
	}, 
	
	handler: function() {	
		if(this.options.loading){
			if(this.xml.readyState < 4) this.options.loading.apply(this);
		}	
				
		if(this.xml.readyState == 4 && this.xml.status == 200){
			this.options.success.call(this, this.xml.responseText);
		}
	}
});



function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
}

/*
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com
*/

function getElementsByClassName(oElm, strTagName, strClassName){
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;
    for(var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];      
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }   
    }
    return (arrReturnElements)
}

// COOKIE FUNCTIONS
function getCookie( name ) {
	var start = document.cookie.indexOf( name + "=" );
	var len = start + name.length + 1;
	if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) {
		return null;
	}
	if ( start == -1 ) return null;
	var end = document.cookie.indexOf( ';', len );
	if ( end == -1 ) end = document.cookie.length;
	return unescape( document.cookie.substring( len, end ) );
}

function setCookie( name, value, expires, path, domain, secure ) {
	var today = new Date();
	today.setTime( today.getTime() );
	if ( expires ) {
		expires = expires * 1000 * 60 * 60 * 24;
	}
	var expires_date = new Date( today.getTime() + (expires) );
	document.cookie = name+'='+escape( value ) +
		( ( expires ) ? ';expires='+expires_date.toGMTString() : '' ) + //expires.toGMTString()
		( ( path ) ? ';path=' + path : '' ) +
		( ( domain ) ? ';domain=' + domain : '' ) +
		( ( secure ) ? ';secure' : '' );
}

function deleteCookie( name, path, domain ) {
	if ( getCookie( name ) ) document.cookie = name + '=' +
			( ( path ) ? ';path=' + path : '') +
			( ( domain ) ? ';domain=' + domain : '' ) +
			';expires=Thu, 01-Jan-1970 00:00:01 GMT';
}

// PAGE POSITIONING
oye.extend({ 
	pageX:function(elem){
		return elem.offsetParent ? elem.offsetLeft + oye.pageX(elem.offsetParent) : elem.offsetLeft;
	},
	
	pageY:function(elem){
		return elem.offsetParent ? elem.offsetTop + oye.pageY(elem.offsetParent) : elem.offsetTop;
	},
	
	parentX:function(elem){
		elem = $(elem);
		return elem.parentNode === elem.offsetParent ? elem.offsetLeft : pageX(elem)-pageX(elem.parentNode);
	},

	parentY:function(elem){
		elem = $(elem);
		return elem.parentNode === elem.offsetParent ? elem.offsetTop : pageY(elem)-pageY(elem.parentNode);
	}
	
});

// SLIDE UP/DOWN
var slideInUse = new Array();

function Slide(objId, options) {	
	this.obj = document.getElementById(objId);
	this.duration = 1;
	this.height = parseInt(this.obj.style.height);

	if(typeof options != 'undefined') { this.options = options; } else { this.options = {}; }
	if(this.options.duration) { this.duration = this.options.duration; }
		
	this.up = function() {
		this.curHeight = this.height;
		this.newHeight = '1';
		if(slideInUse[objId] != true) {
			var finishTime = this.slide();
			window.setTimeout("Slide('"+objId+"').finishup("+this.height+");",finishTime);
		}
	}
	
	this.down = function() {
		this.newHeight = this.height;
		this.curHeight = '1';
		if(slideInUse[objId] != true) {
			this.obj.style.height = '1px';
			this.obj.style.display = 'block';
			this.slide();
		}
	}
	
	this.slide = function() {
		slideInUse[objId] = true;
		var frames = 30 * duration; // Running at 30 fps

		var tIncrement = (duration*1000) / frames;
		tIncrement = Math.round(tIncrement);
		var sIncrement = (this.curHeight-this.newHeight) / frames;

		var frameSizes = new Array();
		for(var i=0; i < frames; i++) {
			if(i < frames/2) {
				frameSizes[i] = (sIncrement * (i/frames))*4;
			} else {
				frameSizes[i] = (sIncrement * (1-(i/frames)))*4;
			}
		}
		
		for(var i=0; i < frames; i++) {
			this.curHeight = this.curHeight - frameSizes[i];
			window.setTimeout("document.getElementById('"+objId+"').style.height='"+Math.round(this.curHeight)+"px';",tIncrement * i);
		}
		
		window.setTimeout("delete(slideInUse['"+objId+"']);",tIncrement * i);
		
		if(this.options.onComplete) {
			window.setTimeout(this.options.onComplete, tIncrement * (i-2));
		}
		
		return tIncrement * i;
	}
	
	this.finishup = function(height) {
		this.obj.style.display = 'none';
		this.obj.style.height = height + 'px';
	}
	
	return this;
}

/* document.getElementsBySelector(selector)
   Version 0.4 - Simon Willison, March 25th 2003
*/
function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

oye.extend({
	
	getSelectors:function(selector){
		if(selector == 'window') {
			console.log('window');
			return 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 (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 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;

	}
	
});
