(function() {
	this.php = {
		// http://phpjs.org/functions/parse_url
		parse_url: function(str, component) {
			var  o   = {
				strictMode: false,
				key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
				q:   {
					name:   "queryKey",
					parser: /(?:^|&)([^&=]*)=?([^&]*)/g
				},
				parser: {
					strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
					loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/\/?)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
				}
			};

			var m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
			uri = {},
			i   = 14;
			while (i--) {uri[o.key[i]] = m[i] || "";}

			switch (component) {
				case 'PHP_URL_SCHEME':
					return uri.protocol;
				case 'PHP_URL_HOST':
					return uri.host;
				case 'PHP_URL_PORT':
					return uri.port;
				case 'PHP_URL_USER':
					return uri.user;
				case 'PHP_URL_PASS':
					return uri.password;
				case 'PHP_URL_PATH':
					return uri.path;
				case 'PHP_URL_QUERY':
					return uri.query;
				case 'PHP_URL_FRAGMENT':
					return uri.anchor;
				default:
					var retArr = {};
					if (uri.protocol !== '') {retArr.scheme=uri.protocol;}
					if (uri.host !== '') {retArr.host=uri.host;}
					if (uri.port !== '') {retArr.port=uri.port;}
					if (uri.user !== '') {retArr.user=uri.user;}
					if (uri.password !== '') {retArr.pass=uri.password;}
					if (uri.path !== '') {retArr.path=uri.path;}
					if (uri.query !== '') {retArr.query=uri.query;}
					if (uri.anchor !== '') {retArr.fragment=uri.anchor;}
					return retArr;
			}
		},

		// http://phpjs.org/functions/parse_str
		parse_str: function(str, array) {
			var glue1 = '=', glue2 = '&', array2 = String(str).replace(/^&?([\s\S]*?)&?$/, '$1').split(glue2),
			i, j, chr, tmp, key, value, bracket, keys, evalStr, that = this,
			fixStr = function (str) {
				return that.urldecode(str).replace(/([\\"'])/g, '\\$1').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
			};

			if (!array) {
				array = this.window;
			}

			for (i = 0; i < array2.length; i++) {
				tmp = array2[i].split(glue1);
				if (tmp.length < 2) {
					tmp = [tmp, ''];
				}
				key   = fixStr(tmp[0]);
				value = fixStr(tmp[1]);
				while (key.charAt(0) === ' ') {
					key = key.substr(1);
				}
				if (key.indexOf('\0') !== -1) {
					key = key.substr(0, key.indexOf('\0'));
				}
				if (key && key.charAt(0) !== '[') {
					keys    = [];
					bracket = 0;
					for (j = 0; j < key.length; j++) {
						if (key.charAt(j) === '[' && !bracket) {
							bracket = j + 1;
						}
						else if (key.charAt(j) === ']') {
							if (bracket) {
								if (!keys.length) {
									keys.push(key.substr(0, bracket - 1));
								}
								keys.push(key.substr(bracket, j - bracket));
								bracket = 0;
								if (key.charAt(j + 1) !== '[') {
									break;
								}
							}
						}
					}
					if (!keys.length) {
						keys = [key];
					}
					for (j = 0; j < keys[0].length; j++) {
						chr = keys[0].charAt(j);
						if (chr === ' ' || chr === '.' || chr === '[') {
							keys[0] = keys[0].substr(0, j) + '_' + keys[0].substr(j + 1);
						}
						if (chr === '[') {
							break;
						}
					}
					evalStr = 'array';
					for (j = 0; j < keys.length; j++) {
						key = keys[j];
						if ((key !== '' && key !== ' ') || j === 0) {
							key = "'" + key + "'";
						}
						else {
							key = eval(evalStr + '.push([]);') - 1;
						}
						evalStr += '[' + key + ']';
						if (j !== keys.length - 1 && eval('typeof ' + evalStr) === 'undefined') {
							eval(evalStr + ' = [];');
						}
					}
					evalStr += " = '" + value + "';\n";
					eval(evalStr);
				}
			}
		},

		// http://phpjs.org/functions/urldecode
		urldecode: function(str) {
			return decodeURIComponent((str+'').replace(/\+/g, '%20'));
		},

		// http://phpjs.org/functions/http_build_query
		http_build_query: function(formdata, numeric_prefix, arg_separator) {
			var value, key, tmp = [];

			var _http_build_query_helper = function (key, val, arg_separator) {
				var k, tmp = [];
				if (val === true) {
					val = "1";
				} else if (val === false) {
					val = "0";
				}
				if (val !== null && typeof(val) === "object") {
					for (k in val) {
						if (val[k] !== null) {
							tmp.push(_http_build_query_helper(key + "[" + k + "]", val[k], arg_separator));
						}
					}
					return tmp.join(arg_separator);
				} else if (typeof(val) !== "function") {
					return php.urlencode(key) + "=" + php.urlencode(val);
				} else {
					throw new Error('There was an error processing for http_build_query().');
				}
			};

			if (!arg_separator) {
				arg_separator = "&";
			}
			for (key in formdata) {
				value = formdata[key];
				if (numeric_prefix && !isNaN(key)) {
					key = String(numeric_prefix) + key;
				}
				tmp.push(_http_build_query_helper(key, value, arg_separator));
			}

			return tmp.join(arg_separator);
		},

		// http://phpjs.org/functions/urlencode
		urlencode: function(str) {
			str = (str+'').toString();

			// Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current
			// PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.
			return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
		}
	};
})();

