
URLUTF8Encoder = function() {

	this.unreserved = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~";
	this.reserved = "!*'();:@&=+$,/?%#[]";
	this.allowed = this.unreserved + this.reserved;
	this.hexchars = "0123456789ABCDEFabcdef";

	this.gethex = function(decimal) {
		return "%" + this.hexchars.charAt(decimal >> 4) + this.hexchars.charAt(decimal & 0xF);
	};
	
	this.getdec = function (hexencoded) {
		if (hexencoded.length == 3) {
			if (hexencoded.charAt(0) == "%") {
				if (this.hexchars.indexOf(hexencoded.charAt(1)) != -1 && this.hexchars.indexOf(hexencoded.charAt(2)) != -1) {
					return parseInt(hexencoded.substr(1,2),16);
				}
			}
		}
		return 256;
	};
};


Xercel.escape = function(decoded) {
	if (! decoded) {
		return decoded;
	}
	
	if ( ! Xercel._encoder) {
		Xercel._encoder = new URLUTF8Encoder();
	}

	var encoded = "";
	
	for (var i = 0; i < decoded.length; i=i+1 ) {
		var ch = decoded.charAt(i);
		if (Xercel._encoder.unreserved.indexOf(ch) != -1) {
			encoded = encoded + ch;
		} else {
			var charcode = decoded.charCodeAt(i);
			if (charcode < 128) {
				encoded = encoded + Xercel._encoder.gethex(charcode);
			}
			
			if (charcode > 127 && charcode < 2048) {
				encoded = encoded + Xercel._encoder.gethex((charcode >> 6) | 0xC0);
				encoded = encoded + Xercel._encoder.gethex((charcode & 0x3F) | 0x80);
			}
			
			if (charcode > 2047 && charcode < 65536) {
				encoded = encoded + Xercel._encoder.gethex((charcode >> 12) | 0xE0);
				encoded = encoded + Xercel._encoder.gethex(((charcode >> 6) & 0x3F) | 0x80);
				encoded = encoded + Xercel._encoder.gethex((charcode & 0x3F) | 0x80);
			}
		
			if (charcode > 65535) {
				encoded = encoded + Xercel._encoder.gethex((charcode >> 18) | 0xF0);
				encoded = encoded + Xercel._encoder.gethex(((charcode >> 12) & 0x3F) | 0x80);
				encoded = encoded + Xercel._encoder.gethex(((charcode >> 6) & 0x3F) | 0x80);
				encoded = encoded + Xercel._encoder.gethex((charcode & 0x3F) | 0x80);
			}
		}
	}
	return encoded;
};


Xercel.unescape = function(encoded) {
	if (! encoded) {
		return encoded;
	}
	
	if ( ! Xercel._encoder) {
		Xercel._encoder = new URLUTF8Encoder();
	}
	
	var decoded = "";
	var notallowed = "";
	var illegalencoding = "";
	var byte1, byte2, byte3, byte4 = 0;

	var i = 0;
	while (i < encoded.length) {
		var ch = encoded.charAt(i);
		if (ch == "%") {
			if (Xercel._encoder.getdec(encoded.substr(i,3)) < 255) {
				byte1 = Xercel._encoder.getdec(encoded.substr(i,3));
				byte2 = Xercel._encoder.getdec(encoded.substr(i+3,3));
				byte3 = Xercel._encoder.getdec(encoded.substr(i+6,3));
				byte4 = Xercel._encoder.getdec(encoded.substr(i+9,3));
				if (byte1 < 128) {
					decoded = decoded + String.fromCharCode(byte1);
					i = i + 3;
				}
				if (byte1 > 127 && byte1 < 192) {
					decoded = decoded + encoded.substr(i,3);
					illegalencoding = illegalencoding + encoded.substr(i,3) + " ";
					i = i + 3;
				}
				if (byte1 > 191 && byte1 < 224) {
					if (byte2 > 127 && byte2 < 192) {
						decoded = decoded + String.fromCharCode(((byte1 & 0x1F) << 6) | (byte2 & 0x3F));
					} else {
						decoded = decoded + encoded.substr(i,6);
						illegalencoding = illegalencoding + encoded.substr(i,6) + " ";
					}
					i = i + 6;
				}
				if (byte1 > 223 && byte1 < 240) {
				if (byte2 > 127 && byte2 < 192) {
				if (byte3 > 127 && byte3 < 192) {
					decoded = decoded + String.fromCharCode(((byte1 & 0xF) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F));
				} else {
					decoded = decoded + encoded.substr(i,9);
					illegalencoding = illegalencoding + encoded.substr(i,9) + " ";
				}
				} else {
					decoded = decoded + encoded.substr(i,9);
					illegalencoding = illegalencoding + encoded.substr(i,9) + " ";
				}
					i = i + 9;
				}
				if (byte1 > 239) {
					if (byte2 > 127 && byte2 < 192) {
						if (byte3 > 127 && byte3 < 192) {
							if (byte4 > 127 && byte4 < 192) {
								decoded = decoded + String.fromCharCode(((byte1 & 0x7) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F));
							} else {
								decoded = decoded + encoded.substr(i,12);
								illegalencoding = illegalencoding + encoded.substr(i,12) + " ";
							}
						} else {
							decoded = decoded + encoded.substr(i,12);
							illegalencoding = illegalencoding + encoded.substr(i,12) + " ";
						}
					} else {
						decoded = decoded + encoded.substr(i,12);
						illegalencoding = illegalencoding + encoded.substr(i,12) + " ";
					}
					i = i + 12;
				}
			} else {
				decoded = decoded + encoded.substr(i,3);
				illegalencoding = illegalencoding + encoded.substr(i,3) + " ";
				i = i + 3;
			}
		} else {
			if (Xercel._encoder.allowed.indexOf(ch) == -1) {
				notallowed = notallowed + ch + " ";
			}
			decoded = decoded + ch;
			i = i + 1;
		}
	}
	return decoded;
};

