function Router(){
	this.SET = function(params, place, encode){ //pass in false to encode to prevent encoding of values
		encode = (encode==undefined || encode);
		var s = window.location.search;
		if(s[0]=="?") s = s.substring(1); //lob off the question mark if its there in the beginning
		var url = {
			search: s,
			hash: this.hash()
		};
		var v;
		for(var name in params){
			url = this.SET_helper(name, params[name], url, place, encode);
		}
		if(url.search != window.location.search){
			window.location = window.location.pathname+(url.search ? '?'+url.search : '')+(url.hash ? '#'+url.hash : '');
		} else if(url.hash != this.hash()){
			this.hash(url.hash);
		}
	};
	this.SET_helper = function(name, value, url, place, encode){ //place = "hash" or "php", where to add it if it doesn't exist. defaults to the hash GET. pass in null if you want to remove a value.
		encode = (encode==undefined || encode);
		value = ((encode && value!=null) ? encodeURI(value) : value);
		if(this.GET[name] == undefined){ 	//if the value isn't in the url at all
			if(value == null) return url;	//if they are attempting to clear out the value then exit so you don't add name="null" to the url
			if(!place || place == "hash"){ 	//add it to the hash
				url.hash = url.hash + (url.hash.indexOf('=') < 0 ? (url.hash[url.hash.length-1] != "/" ? "/" : "" ) : "&") + name + '=' + value;
			} else {						//or add it to the php search string
				url.search = url.search + (url.search ? "&" : "") + name + '=' + value;
			}
		} else if(this.GET[name] != value){	//if the value is different
			var r = (value == null) ? "" : name + "=" + value; // the replacement string. Remove a parameter if null is passed in
			var f; //string to find
			if(place == "hash" || (!place && this.hash_GET[name] != undefined)){ //if the value is in the hash or the has is explicitly requested
				f = name + "=" + (encode ? encodeURI(this.hash_GET[name]) : this.hash_GET[name]); //string to find. You have to encode here or else they won't match up since router.hash_GET is automatically decoded
				if(value == null && url.hash.indexOf('&'+f) > -1){ //if the value is null and there was an & symbol attached with it then remove it when the replace happens
					f = '&'+f;
				}
				url.hash = url.hash.replace(f, r);
			} else { 						// change it in the PHP get
				f = name + "=" + (encode ? encodeURI(this.php_GET[name]) : this.php_GET[name]); //string to find
				if(value == null && url.search.indexOf('&'+f) > -1){ //if the value is null and there was an & symbol attached with it then remove it when the replace happens
					f = '&'+f;
				}
				url.search = url.search.replace(f, r);
			}
		}
		return url;
	};
	//param force - force a refresh even if the hash hasn't changed
	//param update - tells whether or not to update the hijax history. Had to add this in because of a Safari bug causing a looping script
	//persist_params - whether or not to wipe out the hash params when the hash section is changed
	this.hash = function(hash, force, persist_params){
		if(hash && ("#"+this.hash() != hash || force)){
			if(hash[0] != "/" && hash[0] != "#") hash = "/"+hash; //add a leading slash
			if(persist_params){
				if(hash[hash.length-1]!="/") hash += "/";
				hash += this.hash_search;
			}
			window.location.hash = hash;
			this.init(); //reparse GET and all of the other vars given the new hash
			return true;
		}
		else{
			var h = String(window.location).split("#")[1]; //have to grab this from window.location because window.location.hash returns unencoded which can add extra "=" if they're in there
			return h==undefined ?"":h;
		}
	};
	this.location = function(l){
		if(l){ //using reload because it will force refresh for the main search even if only the hash has changed. To change just the hash, use router.hash()
			window.location.assign(l);
			if(l.split("#")[0] == this.path) window.location.reload();
			return true;
		}
		else return String(window.location);
	};
	this.parse_GET = function(s){ 				//s = string input
		var r = {};							//r = the return var
		s = s.split("&");					//now that we have everything from hash and search, split at the &'s
		if(s[0]=="") s.shift();				//if the first entry is empty remove it
		for(var i in s){					//loop through the array and turn the name=value into name value pairs in the GET object
			v = s[i].split("=");			//split at the =
			r[v[0]] = unescape(v[1]);		//decode any url encoded characters and feed the value into GET
		}
		return r;
	};
	this.path 		= window.location.pathname;
	this.search 	= window.location.search;
	this.full_path	= window.location.href.split(window.location.host)[1]; //the full path without the host in it. split at the host name and then take the second item in the array
	this.subdomain	= window.location.hostname.split(".");
	this.subdomain	= (this.subdomain.length < 3) ? "" : this.subdomain[0]; //the subdomain the service is currently running on. If there's not a subdomain it returns an empty string. Used for various dev deployments.
	this.hash_search= ""; //the hash equivalent of window.location.search
	this.php_GET	= {}; //php GET variables
	this.hash_GET	= {}; //hash GET variables
	this.GET		= {}; //initialize / reset GET
	this.hover_entity={}; //initialize the hover entity

	// =====================
	// = PARSE PATH & HASH =
	// =====================
	var p = this.path.substr(1).split("/");	//grab the browser url and trim off the first "/"
	if(p[p.length-1]=="") p.pop();			//if the last entry is empty remove it

	var h = this.hash().split("/"); 		//grab the browser hash
	if(h[0]=="") h.shift();					//if the first entry is empty remove it

	// =================
	// = BUILD PHP GET =
	// =================
	this.php_GET = this.parse_GET(this.search.substr(1));

	// ==================
	// = BUILD HASH GET =
	// ==================
	for(var i in h){				//go through the hash, find any hash entries that have an =, assume they are GET vars, add them to GET and take them out of the hash
		if(h[i].indexOf("=")>-1){	//if there's an "=" in there somewhere
			this.hash_search += (i == 0 ? "" : "&")+h[i]; //add the item to the GET string
			h.splice(i,1); 			//remove the item from the hash
		}
	}
	this.hash_GET = this.parse_GET(this.hash_search);

	// ================
	// = COMBINE GETS =
	// ================
	this.GET = [];
	for(var j in this.hash_GET){
		this.GET[j] = this.php_GET[j]; 
	}
	for(var k in this.hash_GET){
		this.GET[k] = this.hash_GET[k]; 
	}
};

var router = new Router();