(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;
    },	
    
    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');
			} else {
				el.className = el.className.replace(/hidden/, '');
				oye(el).addClass('show');
			}
		});
		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++){
    			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;
    },
    
    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;
    	});
    }
  };
  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)
};


// 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;
				
				default:
					elem.setAttribute(o, options[o]);
				break;
			}
		}
    },
	
	append:function(parent, elem){
		$(parent).appendChild(this.checkElem(elem));
	},

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

	remove:function(el){
		el = $(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
	}	
});



// 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;
	}
});


/* 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;

	}
	
});
