var Url = $.inherit({
	consts: {
		re0: /(?:([\w]+):\/\/)?(?:([\w]+)(?::([\w]+))?@)?([^\/:#\?]+)?(?::(\d+))?(.*)?/,
		re1: /^((?:[^\/]*\/)+)?([^#?]*)(\?[^#]*)?(?:#(.+))?/,
		fields: new Array('proto', 'user', 'password','host','path','file','anchor')
	},
	__constructor: function(url, full) {
		if (url)
			this.parse(url, full);
	},
	parse: function(url, full) {
		var $, i, a = this.consts.fields;
		for (i = 0; i < 7; ++i) delete this[a[i]];
		this.params = {};
		if (!url) return true;
		url = String(url);
		if (full === void 0) full = url.charAt(0) !== '/';
		if (full) {
			if ($ = this.consts.re0.exec(url)) {
				for (i = 0; i < 4; ++i) if ($[i + 1]) this[a[i]] = $[i + 1];
				url = $[6];
			} else return false;
		}
		if (!url) return true;
		$ = this.consts.re1.exec(url);
		if (full && $[1].charAt(0) !== '/') return false;
		if ($[1]) this.path = $[1];
		if ($[2]) this.file = $[2];
		if ($[3]) this.parseParams($[3]);
		if ($[4]) this.anchor = $[4];
		return true;
	},
	parseParams: function(params) {
		var p = params.lastIndexOf('?');
		if (p !== -1) params = params.substr(p + 1);
		this.params = {};
		var params = params.split('&');
		if(params.length){
			for (var i = 0, v = [], l = params.length; i < l; ++i){
				v = params[i].split('=', 2);
				this.params[decodeURIComponent(v[0])] = decodeURIComponent(v[1]);
			}
		}
		return this.params;
	},

	format: function(host, params) {
		if (host === void 0) host = !!this.host;
		var r = [];
		if (host) {
			if (this.proto) r.push(this.proto, '://'); else r.push(window.location.protocol, '//');
			if (this.host) {
				if (this.user) {
					r.push(this.user);
					if (this.password) r.push(':', this.password);
					r.push('@');
				}
				r.push(this.getHost());
			} else r.push(window.location.host);
		}
		if (this.path) r.push(this.path);
		if (this.file) r.push(this.file);
		if (params !== false) r.push(this.formatParams(true));
		if (this.anchor) r.push('#', this.anchor);
		return r.join('');
	},
	toString: function() { return this.format(); },
	getHost: function() {
		if (!this.host) return window.location.host;
		var r = this.host;
		if (this.port) r += ':' + this.port;
		return r;
	},
	getPath: function() {
		if (!this.path) return this.host ? '/' : window.location.pathname.replace(/[^\/]*$/, '');
		if (this.path.charAt(0) === '/') return this.path;
		return (window.location.pathname.replace(/[^\/]*$/, '')) + this.path;
	},
	setParam: function(name, value) {
		this.params[name] = value;
		return this;
	},
	setParams: function(params){
		if(params instanceof Object){
			for(var k in params){
				if(params[k] !== void 0){
					this.params[k] = params[k];
				}
			}
		}
		return this;
	},
	addParams: function(params) {
		if (arguments.length < 2) set = true;
		this.params = new Wak.Hash(this.params).set(params, set).h;
		return this;
	},
	formatParams: function(qmark) {
		if (!this.params) return '';
		if (qmark === void 0) qmark = true;
		var r = [], i = 0;
		for(var k in this.params){
			r[i] = encodeURIComponent(k) + '=' + encodeURIComponent(this.params[k]);
			i++;
		}
		r = r.join('&');
		if (qmark && r) r = '?' + r;
		return r;
	}
});
