(function($){

$.url = function( url ) {
	if( typeof(this) == 'function' ) {
		return new $.url(url);
	} else {
		if( url == null ) {
			url = new String(window.location);
		}
		this._protocol   = null;
		this._hostname   = null;
		this._port       = null;
		this._path       = null;
		this._parameters = null;
		this._hash       = null;
		
		if( url != null ) {
			this._parse(url);
		}
		return this;
	}
	
}

$.url.prototype = {
	_parse : function(url) {
		var match = url.match(/^(([a-z]+):\/\/([^\/]+)(:[0-8+])?\/)?([^?#]*)(\?[^?#]*)?(#.*)?/);
		
		this._protocol   = match[2];
		this._hostname   = match[3];
		this._port       = match[4];
		this._path       = match[5];
		if( match[6] != null && match[6] != '' ) {
			this._parameters = this._parseParameters((match[6]||'?').substr(1)+"&");
		}
		if( match[7] != null && match[7] != '' ) {
			this._hash       = decodeURIComponent((match[7]||'#').substr(1));
		}
		
		this._path = this._makeAbsolute(this._path);
		
	},
	
	
	_makeAbsolute : function(path) {
		var sPath = path.split('/');
		var fPath = new Array();
		var i = 0;
		$.each( sPath , function() {
			if( this == '..' && i>0 && fPath[i-1] != '..') {
				i--;
				delete fPath[i];
			} else {
				fPath[i] = this;
				i++;
			}
		});
		
		return fPath.join('/');

	},
	
	_parseParameters : function( params ) {
		var match = null;
		var result = {};
		do {
			match = params.match(/^([^=&]*)(=([^&]*))?&/);
			if( match != null ) {
				params = params.substr(match[0].length);
				if( match[0] != '&' ) {
					var val = match[3]||null;
					if ( val ) val = decodeURIComponent(val);
					result[decodeURIComponent(match[1])] = val;
				}
			}
		
		} while( match != null );
		return result;
	},
	
	setBase : function( url ) {
		if( !this._hostname ) {
			if( !(url instanceof this.constructor)) {
				url = $.url(url);
			}
			this._hostname = url._hostname;
			this._protocol = url._protocol;
		
			var base = url.getPath().split('/');
			base.pop();
			this._path = this._makeAbsolute(base.join('/')+'/'+this._path);
		}
		return this;
	},
	
	getPath : function() {
		return this._path;
	},
	
	assemble : function() {
		var url = '';
		if( this._protocol && this._hostname ) {
			url += this._protocol +'://'+ this._hostname+'/';
		}
		
		url += this._path;
		
		if( this._parameters ) {
			var tParams = new Array();
			for( name in this._parameters ) {
				var pair = encodeURIComponent(name);
				if( this._parameters[name] != null ) {
					pair += '='+encodeURIComponent(this._parameters[name]);
				}
				tParams.push(pair);
			}
			url += '?'+tParams.join('&');
		}
		
		if( this._hash ) {
			url += "#"+encodeURIComponent(this._hash); 
		}
		
		return url;
	}
};

})(jQuery);
