/*
	Perform diff on any url/query param/cookie/get/post
	URI parser picked from: http://blog.stevenlevithan.com/archives/parseuri [(c) Steven Levithan <stevenlevithan.com>]

*/

(function(t){
	var keys = ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];

	t.diff = function(ua, ub){
		var r = {},
		ua = t.parse(ua),
		ub = t.parse(ub);
		for (var i = 0;i<keys.length;i++){
			var k = keys[i];
			if (k == "source" || k == "userInfo" || k == "authority"  || k == "relative"  || k == "directory")
				continue;
			if (k == "query"){
				var a = ua["params"], b = ub["params"];
				r["params"] = [];
				var ky = createKeys(a, b, true);
				for (var j = 0; j < ky.length; j++){
					r["params"].push({
						name: ky[j],
						value: compare(a?a[ky[j]]:"", b?b[ky[j]]:"")
					});
				}
				continue;
			} else if (k == "path"){
				var a = (ua["path"]||"").split("/"), b = (ub["path"]||"").split("/"), lng = a>b?a:b;
				r["path"] = [];
				for (var j = 0; j < lng.length; j++){
					var aa = a[j], bb = b[j];
					if (aa || bb)
						r["path"].push({
							name: false,
							value: compare(aa, bb)
						});
				}
				continue;
			}

			r[k] = compare(ua[k], ub[k])
		}
		return r;
	}

	t.parse = function(u){
		if (/.+=.+;\s/.test(u))
			return {query: "", params: parseCookie(u)};
		var uri = parseUri(u);
		if (uri.query == "" && /(^|&).+=.+/.test(u))
			uri = parseUri("?" + u);
		return uri;
	}

	function compare (f1, f2){
		if (typeof f1 == "undefined")
			f1 = false
		if (typeof f2 == "undefined")
			f2 = false
		if (!f1 && !f2)
			return false;

		return {
			"a": f1,
			"b": f2,
			equal: (f1 == f2)
		}
	}

	function createKeys(a, b, sort){
		var k = mergeArrays(getKeys(a), getKeys(b));
		if (k && sort)
			k = k.sort()
		return k;

		function getKeys (o){
			var keys = [];
			for (var k in o){
				keys.push(k);
			}
			return keys;
		}

		function mergeArrays(a, b){
			var c = a.concat(b);
			return c.filter(function (item, pos) {return c.indexOf(item) == pos});
		}
	}

	function parseUri (str) {
		var	o   = {
				strictMode: false,
				key: keys,
				q:   {
					name:   "params",//queryKey
					parser: /(?:^|&)([^&=]*)=?([^&]*)/g
				},
				parser: {
					strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
					loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
				}
			},
			m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
			uri = {},
			i   = 14;

		while (i--) uri[o.key[i]] = m[i] || "";

		uri[o.q.name] = {};
		uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
			if ($1) uri[o.q.name][$1] = $2;
		});

		return uri;
	};

	function parseCookie(c){
		var ck = c.split("; "), nr = {};
		for (var i = 0; i < ck.length; i++){
			var l = ck[i].split("=");
			if (l[0] && l[1])
				nr[l[0]] = l[1];
		}
		return nr;
	}

}(this.diffurl = this.diffurl || {}));