/**
 * 扩展
 */
const extend = {
    /**
     * 添加存储
     * @param {string} key 
     * @param {object} value 
     * @returns 
     */
    addStorage(key, value) {
        let res = false;
        if (this.isEmptyString(key) || this.isNull(value)) {
            return res;
        }
        if (this.isObject(value)) {
            value = JSON.stringify(value);
        }
        uni.setStorageSync(key, value);
        res = true;
        return res;
    },

    /**
     * 创建 GUID
     * @returns 
     */
    createGUID() {
        let date = new Date().getTime();
        let guid = 'xxxxxxxx-xxxx-zxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            let random = (date + Math.random() * 16) % 16 | 0;
            date = Math.floor(date / 16);
            return (c == 'x' ? random : (random & 0x3 | 0x8)).toString(16);
        });
        guid = guid.replace('z', (parseInt(Math.random() * 16)).toString(16));
        return guid;
    },

    /**
     * 日期格式化
     * @param {Date} date 被格式化日期类，必选
     * @param {string} key 格式字符串，可选，默认 yyyy-MM-dd HH:mm:ss.ms
     */
    dateFormatter(date, format) {
        if (this.isDate(date)) {
            var hours = date.getHours();
            format = this.isNonEmptyString(format) ? format : 'yyyy-MM-dd HH:mm:ss.ms';
            format = format.replace(/yyyy|YYYY/, date.getFullYear().toString());
            format = format.replace(/yy|YY/, this.padLeft(date.getYear() % 100, 2, '0'));
            format = format.replace(/MM/, this.padLeft(date.getMonth() + 1, 2, '0'));
            format = format.replace(/M/g, (date.getMonth() + 1).toString());
            format = format.replace(/dd|DD/, this.padLeft(date.getDate(), 2, '0'));
            format = format.replace(/d|D/g, date.getDate().toString());
            format = format.replace(/HH/g, this.padLeft(hours, 2, '0'));
            format = format.replace(/hh/g, hours >= 12 ? '下午' + this.padLeft(hours - 12, 2, '0') : '上午' + this
                .padLeft(
                    hours,
                    2, '0'));
            format = format.replace(/H/g, hours);
            format = format.replace(/h/g, hours >= 12 ? '下午' + (hours - 12).toString() : '上午' + hours.toString());
            format = format.replace(/mm/g, this.padLeft(date.getMinutes(), 2, '0'));
            format = format.replace(/m/g, date.getMinutes().toString());
            format = format.replace(/ss/g, this.padLeft(date.getSeconds(), 2, '0'));
            format = format.replace(/s/g, date.getSeconds().toString());
            format = format.replace(/ms/g, date.getMilliseconds().toString());
            return format;
        } else if (this.isNonEmptyString(date)) {
            return this.dateFormatter(this.dateParse(date), format);
        } else {
            return '';
        }
    },

    /**
     * 日期字符串转换成日期对象
     * @param {string} date 被转换字符串，必选
     */
    dateParse(date) {
        let newDate = null;
        if (this.isNumber(date)) {
            if (date.toString().length === 10) {
                date *= 1000;
            }
            date = 'Date(' + date + ')';
        }
        if (this.isNonEmptyString(date)) {
            if (date.indexOf('Date') > 0) {
                date = "new " + date.replace(/\//g, '');
            }
            date = date.replace(/-/g, '/');
            date = date.replace(/T/g, ' ');
            if (date.indexOf('Date') >= 0) {
                newDate = this.eval(date);
            } else {
                let ms = 0;
                let msIndex = value.indexOf('.');
                if (msIndex > -1) {
                    ms = parseInt(value.substring(msIndex + 1));
                    value = value.substring(0, msIndex);
                }
                newDate = new Date(value);
                if (!isNaN(ms)) {
                    newDate.setMilliseconds(ms);
                }
            }
        }
        return newDate;
    },

    /**
     * 删除结尾换行符
     * @param {string} str 要处理的字符串
     */
    deleteEndLineFeed(str) {
        let res = '';
        if (this.isNonEmptyString(str)) {
            let crIndex = str.lastIndexOf('\r');
            let lfIndex = str.lastIndexOf('\n');
            let crlfIndex = str.lastIndexOf('\r\n');
            let index = crlfIndex >= 0 ? crlfIndex : crIndex >= 0 ? crIndex : lfIndex > 0 ? lfIndex : -1;
            if (index > 0) {
                res = str.substring(0, index);
            } else {
                res = str;
            }
        }
        return res;
    },

    /**
     * 将对象编码成url字符串
     * @param {object} param 被编码对象，必选
     * @param {string} url 被编码url，可选
     */
    encodeUrl(param, url) {
        let result = '';
        if (this.isObject(param)) {
            result = Parse(param);
            if (!this.isNonEmptyString(result)) {
                return url;
            } else if (this.isNonEmptyString(url)) {
                if (url.indexOf('?') >= 0) {
                    result = url + '&' + result;
                } else {
                    result = url + '?' + result;
                }
            }
        } else {
            return this.isNonEmptyString(url) ? url : result;
        }
        return result;

        /**
         * 转换方法
         * @param {object} value 
         */
        function Parse(value, perfix) {
            let result = '';
            perfix = extend.isNonEmptyString(perfix) ? perfix : '';
            if (typeof value !== 'object') {
                return result += perfix + '=' + value;
            }
            let data = extend.toFormObject(value);
            let count = 0;
            for (let n in data) {
                if (count === 0) {
                    result += n + '=' + data[n];
                } else {
                    result += '&' + n + '=' + data[n];
                }
                count++;
            }
            return result;
        }
    },

    /**
     * 返回格式化后的报错内容
     * @param {any} ex 要格式化的对象
     */
    errorFormatter(ex) {
        let result = {
            status: null,
            success: false,
            message: ''
        };
        if (typeof ex === 'string') {
            result.message = ex;
        } else if (typeof ex === 'object') {
            if (this.isNonEmptyString(ex.data) && ex.data.indexOf('{') === 0) {
                ex.data = JSON.parse(ex.data);
                if (this.isNonEmptyString(ex.data.ExceptionMessage)) {
                    ex.message = ex.data.ExceptionMessage;
                } else if (this.isNonEmptyString(ex.data.Message)) {
                    ex.message = ex.data.Message;
                } else if (this.isNonEmptyString(ex.data.error_description)) {
                    ex.message = ex.data.error_description;
                }
            }
            if (this.isNonEmptyString(ex.stack)) {
                result.message = ex.stack;
            } else if (this.isNonEmptyString(ex.responseText)) {
                result.message = ex.responseText;
            } else if (this.isNonEmptyString(ex.statusText)) {
                result.message = ex.statusText;
            } else if (this.isNonEmptyString(ex.errMsg)) {
                result.message = ex.errMsg;
            } else if (this.isNonEmptyString(ex.msg)) {
                result.message = ex.msg;
            } else if (this.isNonEmptyString(ex.message)) {
                result.message = ex.message;
            } else if (this.isNonEmptyString(ex.Message)) {
                result.message = ex.Message;
            } else if (this.isNonEmptyString(ex.title)) {
                result.message = ex.title;
            } else if (this.isNonEmptyString(ex.error_description)) {
                result.message = ex.error_description;
            } else if (this.isNonEmptyString(ex.data)) {
                result.message = ex.data;
            } else if (this.isObject(ex.data)) {
                if (this.isNonEmptyString(ex.data.error)) {
                    result.message = ex.data.error;
                }
            } else if (this.isNonEmptyString(ex.errMsg)) {
                result.message = ex.errMsg;
            }
        }
        var statusMessage = {
            0: '网络连接失败，请检查本地网络设置。',
            400: '请求无效。',
            401: '未授权。',
            403: '禁止访问。',
            404: '访问地址不存在。',
            405: '不允许此方法。',
            406: '不可接受。',
            407: '需要代理身份验证。',
            412: '前提条件失败。',
            414: 'Request-URI 太长',
            415: '不支持的媒体类型。',
            500: '内部服务器错误。',
            502: '网关错误。',
            600: '不可解析的响应标头。',
        };
        if (this.isNumber(ex.statusCode)) {
            result.status = ex.statusCode;
        } else if (this.isNumber(ex.status)) {
            result.status = ex.status;
        }

        if (result.status !== null && result.status !== 200 && (!this.isNonEmptyString(result.message) || result
                .message === 'error') ||
            result.message === 'request:ok') {
            result.message = result.status.toString() + ' ' + (statusMessage[result.status] || '');
        }
        if (result.message === 'invalid_username_or_password') {
            result.message = this.lang.errorUsernameOrPassword;
        }
        return result;
    },

    /**
     * eval
     * @param {string} str 
     * @returns 
     */
    eval(str) {
        let res = null;
        try {
            if (this.isJsonString(str)) {
                res = JSON.parse(str);
            } else if (this.isNumberString(str)) {
                res = parseFloat(str);
            } else {
                res = str;
            }
            if (this.isNonEmptyString(str) && this.isNull(res)) {
                res = str;
            }
        } catch (ex) {
            res = str;
        }
        return res;
    },

    /**
     * 获取字符长度
     * @param {string} value 
     */
    getUTF8Length(value) {
        let length = 0;
        let code = 0;
        if (this.isNonEmptyString(value)) {
            for (let i = 0; i < value.length; i++) {
                code = value[i].charCodeAt();
                if (code < 128) {
                    length++;
                } else if (code >= 128 && code <= 2047) {
                    length += 2;
                } else if (code >= 2047 && code <= 65535) {
                    length += 3;
                } else {
                    length += 4;
                }
            }
        }
        return length;
    },

    /**
     * 获取窗口高度
     */
    getWindowHeight() {
        let height = uni.getWindowInfo().windowHeight;
        return height;
    },

    /**
     * 是否为空
     * @param {any} value 
     * @returns 
     */
    isNull(value) {
        return value === null || value === undefined;
    },

    /**
     * 是否是字符串
     * @param {string} str 
     * @returns 
     */
    isString(str) {
        return typeof str === 'string';
    },

    /**
     * 是否是空字符串
     * @param {string} str 
     * @returns 
     */
    isEmptyString(str) {
        return !this.isNonEmptyString(str);
    },

    /**
     * 是否是非空字符串
     * @param {string} str 
     * @returns 
     */
    isNonEmptyString(str) {
        return this.isString(str) && str.length > 0;
    },

    /**
     * 是否是数字
     * @param {number} num
     * @returns
     */
    isNumber(num) {
        return typeof num === 'number' && !isNaN(num);
    },

    /**
     * 是否是数字字符串
     * @param {string} str 
     * @returns 
     */
    isNumberString(str) {
        return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?this/.test(str);
    },

    /**
     * 是否是布尔值
     * @param {boolean} bool
     * @returns
     */
    isBool(bool) {
        return typeof bool === 'boolean';
    },

    /**
     * 是否是对象
     * @param {object} obj 
     * @returns 
     */
    isObject(obj) {
        return !this.isNull(obj) && typeof obj === 'object';
    },

    /**
     * 是否是日期对象
     * @param {Date} date 
     * @returns 
     */
    isDate(date) {
        return this.isObject(date) && date instanceof Date && !isNaN(date.getTime());
    },

    /**
     * 是否是日期字符串
     * @param {string} str 
     * @returns 
     */
    isDateString(str) {
        return !/Invalid|NaN/.test(new Date(value).toString());
    },

    /**
     * 是否是 ISO 日期字符串
     * @param {string} str 
     * @returns 
     */
    isISODateString(str) {
        return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])this/.test(value);
    },

    /**
     * 是否是正则表达式
     * @param {RegExp} reg 
     * @returns 
     */
    isRegExp(reg) {
        return this.isObject(reg) && reg instanceof RegExp;
    },

    /**
     * 是否是数组
     * @param {Array} arr 
     * @returns 
     */
    isArray(arr) {
        // #ifdef APP
        return this.isLikeArray(arr);
        // #endif
        
        return this.isObject(arr) && arr instanceof Array;
    },

    /**
     * 是否是类数组
     * @param {object} arr 
     * @returns 
     */
    isLikeArray(arr) {
        return this.isObject(arr) && arr !== window && this.isNumber(arr.length) && (arr.length > 0 && !this.isNull(
            arr[
                arr.length - 1]) || arr.length === 0);
    },

    /**
     * 是否是数组字符串
     * @param {string} str 
     * @returns 
     */
    isArrayString(str) {
        return this.isString(str) && str.length > 1 && str.substring(0, 1) === '[' && str.substring(str.length -
                1) ===
            ']';
    },

    /**
     * 是否是方法
     * @param {Function} value 
     * @returns 
     */
    isFunction(value) {
        return typeof value === 'function';
    },

    /**
     * 是否是 HTML 字符串
     * @param {string} str 
     * @returns 
     */
    isHTML(str) {
        return this.isString(str) && str.length >= 3 && str.charAt(0) === '<' && str.charAt(str.length - 1) === '>';
    },

    /**
     * 是否是 XML 字符串
     * @param {string} str 
     * @returns 
     */
    isXML(str) {
        return this.isHTML(str) && (str.indexOf('<?xml') === 0 || str.indexOf('<!DOCTYPE') === 0);
    },

    /**
     * 是否是 Json 字符串
     * @param {string} str 
     * @returns 
     */
    isJsonString(str) {
        return this.isString(str) && str.length > 1 && str.substring(0, 1) === '{' && str.substring(str.length -
                1) ===
            '}';
    },

    /**
     * 是否是邮箱
     * @param {string} str 
     * @returns 
     */
    isEmail(str) {
        return /^[a-zA-Z0-9.!#this%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*this/
            .test(value);
    },

    /**
     * 是否是手机号
     * @param {string} str 
     * @returns 
     */
    isPhone(str) {
        return /^1(3|4|5|7|8|9)\d{9}this/.test(value);
    },

    /**
     * 是否是身份证
     * @param {string} str 
     * @returns 
     */
    isIDCard(str) {
        return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}this/.test(value);
    },

    /**
     * 是否是密码
     * @param {string} value 
     * @param {number} min 
     * @param {number} max 
     * @returns 
     */
    isPassword(value, min, max) {
        value = value === undefined ? '' : value;
        min = this.isNumber(min) ? min : 1;
        max = this.isNumber(max) ? max : 256;
        var regexp = '/^([a-z]|[A-Z]|[0-9]|[_-]){' + min + ',' + max + '}this/';
        return regexp.test(value);
    },

    /**
     * 是否是 URL
     * @param {string} url 被验证的字符串
     * @returns {boolean} 验证结果
     */
    isUrl(url) {
        if (this.isNonEmptyString(url)) {
            let key = '://';
            if (url.indexOf(key) > 0 && url.indexOf(key) < 10) {
                return true;
            }
        }
        return false;
    },

    /**
     * 验证特殊字符，或者验证指定的字符 key
     * @param {string | number} value 被验证的字符串，必选
     * @param {string} key 验证关键字，必选
     */
    isSpecialChars(value, key) {
        var msg = '';
        value = this.isNonEmptyString(value) ? value : '';
        key = this.isNonEmptyString(key) ? key : '';
        for (var i = 0; i < value.length; ++i) {
            var code = value[i].charCodeAt();
            if (code < 32 || (code > 8399 && code < 12288) || (code > 12350 && code < 19968) || (code > 40907 &&
                    code <
                    65280) || code > 65519) {
                msg += msg.length > 0 ? ',' : '';
                msg += value[i];
            } else {
                for (var j = 0; j < key.length; ++j) {
                    if (value[i] === key[j]) {
                        msg += msg.length > 0 ? ',' : '';
                        msg += value[i];
                    }
                }
            }
        }
        return msg.length === 0 ? false : msg;
    },

    /**
     * 判断是否是Map对象
     * @param {Map} map Map对象
     */
    isMap(map) {
        return this.isObject(map) && map instanceof Map;
    },

    /**
     * Map对象键转数组。
     * @param {Map} map Map对象
     * @returns 
     */
    mapKeysToArray(map) {
        let arr = [];
        if (this.isMap(map)) {
            for (let [name, value] of map) {
                arr.push(name);
            }
        }
        return arr;
    },

    /**
     * Map对象值转数组。
     * @param {Map} map Map对象
     * @returns 
     */
    mapValuesToArray(map) {
        let arr = [];
        if (this.isMap(map)) {
            for (let [name, value] of map) {
                console.log(name, value);
                arr.push(value);
            }
        }
        return arr;
    },

    /**
     * 字符串前缀拼接
     * @param {string | number} value 要拼接的值
     * @param {number} length 补位字符
     * @param {string} prefix 拼接长度， 默认值 0
     * value 值的长度 length 不够时， 将以前缀 prefix 填充， 比如： 001
     */
    padLeft(value, length, prefix) {
        if (this.isNumber(value)) {
            value = value.toString();
        }
        if (!this.isNonEmptyString(value)) {
            value = '';
        }
        if (!this.isNumber(length) || value.length > length) {
            length = value.length;
        }
        if (!this.isNonEmptyString(prefix)) {
            prefix = '0';
        }
        return (Array(length).join(prefix) + (value.length === 0 ? prefix : value)).slice(-length);
    },

    /**
     * 读取存储
     * @param {string} key 
     * @returns 
     */
    readStorage(key) {
        let res = null;
        if (this.isNonEmptyString(key)) {
            let data = uni.getStorageSync(key);
            if (this.isJsonString(data)) {
                res = JSON.parse(data);
            } else if (this.isNumberString(data)) {
                res = parseFloat(data) || '';
            } else if (this.isNumber(data) || this.isBool(data) || this.isNonEmptyString(data)) {
                res = data;
            }
        }
        return res;
    },

    /**
     * 删除存储
     * @param {string} key 
     * @returns 
     */
    removeStorage(key) {
        let res = false;
        if (this.isNonEmptyString(key)) {
            uni.removeStorageSync(key);
            res = true;
        }
        return res;
    },

    /**
     * 截取末尾字符串
     * @param {string} str 被截取字符串
     * @param {number} length 截取长度
     */
    subEndString(str, length) {
        let res = '';
        if (this.isString(str)) {
            if (!this.isNumber(length)) {
                length = str.length;
            }
            res = str.substring(str.length - length, str.length);
        }
        return res;
    },

    /**
     * 截取开头字符串
     * @param {string} str 被截取字符串
     * @param {number} length 截取长度
     */
    subStartString(str, length) {
        let res = '';
        if (this.isString(str)) {
            if (!this.isNumber(length)) {
                length = str.length;
            }
            res = str.substring(0, length);
        }
        return res;
    },

    /**
     * 转换成 Form 键值对
     * @param {object} value 
     * @param {string} name 
     * @returns 
     */
    toFormObject(value, name) {
        let res = {};
        let cres = null;
        let isEmpty = true;
        if (!this.isObject(value)) {
            return value;
        }
        if (this.isNull(name)) {
            name = '';
        }

        if (this.isLikeArray(value)) {
            for (let i in value) {
                isEmpty = false;
                cres = this.toFormObject(value[i], name + '[' + i + ']');
                if (this.isObject(cres)) {
                    for (let m in cres) {
                        res[m] = cres[m];
                    }
                } else if (!this.isNull(cres)) {
                    res[name + '[' + i + ']'] = cres;
                }
            }
            if (isEmpty && this.isNonEmptyString(name)) {
                res[name] = [];
            }
        } else {
            for (let n in value) {
                isEmpty = false;
                cres = this.toFormObject(value[n], this.isEmptyString(name) ? n : name + '.' + n);
                if (this.isObject(cres)) {
                    for (let o in cres) {
                        res[o] = cres[o];
                    }
                } else if (!this.isNull(cres)) {
                    res[this.isEmptyString(name) ? n : name + '.' + n] = cres;
                }
            }
            if (isEmpty && this.isNonEmptyString(name)) {
                res[name] = {};
            }
        }
        return res;
    },

    /**
     * 将url参数解码成对象
     * @param {string} url 统一资源定位符
     */
    urlToObject(url) {
        var result = null;
        if (this.isNonEmptyString(url)) {
            url = decodeURI(url);
            var arr = null;
            var temp = url.substring(url.indexOf('?'));
            if (temp.indexOf('?') >= 0) {
                temp = temp.substring(1);
                arr = temp.split('&');
                result = {};
                for (var i = 0; i < arr.length; i++) {
                    temp = arr[i].split('=');
                    result[temp[0]] = temp[1];
                }
            }
        }
        return result;
    }
}

export default extend;