export module Encoding.UTF8 {

	export function GetBytes(str: string) {
		let len = str.length, resPos = -1;
		let resArr = new Uint8Array(len * 3);
		for (let point = 0, nextcode = 0, i = 0; i !== len;) {
			point = str.charCodeAt(i), i += 1;
			if (point >= 0xD800 && point <= 0xDBFF) {
				if (i === len) {
					resArr[resPos += 1] = 0xef;
					resArr[resPos += 1] = 0xbf;
					resArr[resPos += 1] = 0xbd;
					break;
				}

				nextcode = str.charCodeAt(i);
				if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) {
					point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000;
					i += 1;
					if (point > 0xffff) {
						resArr[resPos += 1] = (0x1e << 3) | (point >>> 18);
						resArr[resPos += 1] = (0x2 << 6) | ((point >>> 12) & 0x3f);
						resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f);
						resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f);
						continue;
					}
				} else {
					resArr[resPos += 1] = 0xef;
					resArr[resPos += 1] = 0xbf;
					resArr[resPos += 1] = 0xbd;
					continue;
				}
			}
			if (point <= 0x007f) {
				resArr[resPos += 1] = (0x0 << 7) | point;
			} else if (point <= 0x07ff) {
				resArr[resPos += 1] = (0x6 << 5) | (point >>> 6);
				resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f);
			} else {
				resArr[resPos += 1] = (0xe << 4) | (point >>> 12);
				resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f);
				resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f);
			}
		}
		return resArr.subarray(0, resPos + 1);
	}

	export function GetString(array: Uint8Array) {
		var charCache = new Array(128);
		var codePt, byte1;
		var result = [];
		var buffLen = array.length;
		var charFromCodePt = String.fromCodePoint || String.fromCharCode;
		for (var i = 0; i < buffLen;) {
            byte1 = array[i++];

            if (byte1 <= 0x7F) {
                codePt = byte1;
            } else if (byte1 <= 0xDF) {
                codePt = ((byte1 & 0x1F) << 6) | (array[i++] & 0x3F);
            } else if (byte1 <= 0xEF) {
                codePt = ((byte1 & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
            } else if (String.fromCodePoint) {
                codePt = ((byte1 & 0x07) << 18) | ((array[i++] & 0x3F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
            } else {
                codePt = 63;    // Cannot convert four byte code points, so use "?" instead
                i += 3;
            }
            result.push(charCache[codePt] || (charCache[codePt] = charFromCodePt(codePt)));
        }
		return result.join('');
	}

	/**
	 * 是否非中英文
	 * @param {string} msg 訊息
	 */
	export function IsNotChineseOrEnglish(str: string): boolean {
		var regExp: RegExp = /^[\u3105-\u312c\u4e00-\u9fff\uff10-\uff19\uFF21-\uFF3AA-Za-z0-9_]+$/;
		if (str.match(regExp)) {
			return true;
		} else {
			return false;
		}
	}

	export function b64EncodeUnicode(str) {
		return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
			//@ts-ignore
			return String.fromCharCode('0x' + p1);
		}));
	}
	export function b64DecodeUnicode(str) {
		return decodeURIComponent(atob(str).split('').map(function (c) {
			return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
		}).join(''));
	}
	export function isBase64(str) {
		if (str === '' || str.trim() === '') { return false; }
		try {
			return btoa(atob(str)) == str;
		} catch (err) {
			return false;
		}
	}
}