/*
 * @Description: 公共函数
 * @Author: asheng
 * @Date: 2018-12-07 11:36:27
 * @LastEditors: asheng
 * @LastEditTime: 2018-12-12 15:22:04
 */

export default class Utils {

    public static getInstance(...args: any[]): any {
        let Class: any = this;
        if (!Class._instance) {
            let argsLen: number = args.length;
            if (argsLen === 0) {
                Class._instance = new Class();
            } else {
                Class._instance = new Class(...args);
            }
        }
        return Class._instance;
    }

    /**
     * 数组去重
     * @param arr
     */
    public uniqueArray(arr: any): any[] {
        let newA = arr;
        newA.sort();
        let result = [newA[0]];
        for (let i = 1; i < newA.length; i++) {
            if (newA[i] !== result[result.length - 1]) {
                result.push(newA[i]);
            }
        }
        return result;
    }

    /**
     * 二维数组转置
     * @param arr
     */
    public transposition(arr: any[][]): any[][] {
        let newArr: any[][] = [];
        let len0 = arr.length;
        let len1 = arr[0].length;
        for (let i = 0; i < len0; i++) {
            for (let j = 0; j < len1; j++) {
                if (newArr[j] === undefined) {
                    newArr[j] = [];
                    newArr[j] = [];
                }
                newArr[j][i] = arr[i][j];
            }
        }
        return newArr;
    }

    /**
     * 转驼峰命名
     * @param {string} str
     * @returns {string}
     */
    public nameToTF(str: string): string {
        let arr: string[] = [];
        if (str.indexOf('_') !== -1) {
            arr = str.split('_');
        } else if (str.indexOf('-') !== -1) {
            arr = str.split('-');
        }

        for (let i = 1; i < arr.length; i++) {
            arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
        }
        return arr.join('');
    }

    /**
     * 随机数组
     * @param len
     * @param start
     * @param end
     * @returns {Array<number>}
     */
    public random(len: number, start: number, end: number): number[] {
        let arr = [];

        while (arr.length < len) {
            let num = this.randomNum(start, end);
            // if (arr.indexOf(num) == -1) {
            //     arr.push(num);
            // }
            // @ts-ignore
            arr.push(num);
        }
        return arr;
    }

    /**
     * 随机数
     * @param start
     * @param end
     * @returns {number}
     */
    public randomNum(start: number, end: number) {
        let span = end - start;
        return Math.round(Math.random() * span + start);
    }

    /**
     * 洗牌
     * @param arr
     */
    public sortRand(arr: any[][]) {
        let len0 = arr.length;
        let len1 = arr[0].length;
        for (let i = 0; i < arr.length * arr[0].length; i++) {
            let x1 = this.randomNum(0, len0 - 1);
            let y1 = this.randomNum(0, len1 - 1);
            let x2 = this.randomNum(0, len0 - 1);
            let y2 = this.randomNum(0, len1 - 1);
            [arr[x1][y1], arr[x2][y2]] = [arr[x2][y2], arr[x1][y1]];
        }
        return arr;
    }

    /**
     * 获取url中参数
     * @param url
     */
    public getParams(url: string) {
        if (url.indexOf('?') === -1) {
            return {};
        }
        const keyValueArr = url.split('?')[1].split('&');
        let paramObj: any = {};
        keyValueArr.forEach(item => {
            const keyValue = item.split('=');
            paramObj[keyValue[0]] = keyValue[1];
        });
        return paramObj;
    }

    /**
     * 判断一个对象是否存在key，
     * 如果传入第二个参数key，则是判断这个obj对象是否存在key这个属性
     * 如果没有传入key这个参数，则判断obj对象是否有键值对
     * @param obj
     * @param key
     */
    public hasKey(obj: any, key: string | number) {
        if (key) {
            return key in obj;
        } else {
            const keysArr = Object.keys(obj);
            return keysArr.length;
        }
    };

    /**
     * 时间格式化
     * @param fmt
     * @param date
     */
    public date(fmt: any, date?: Date) {
        let time = '';
        let datetime: any = date;
        if (!datetime) {
            datetime = new Date();
        }
        const o: any = {
            'Y+': datetime.getFullYear(), 'm+': datetime.getMonth() + 1, // 月份
            'd+': datetime.getDate(), // 日
            'H+': datetime.getHours(), // 小时
            'i+': datetime.getMinutes(), // 分
            's+': datetime.getSeconds(), // 秒
            'q+': Math.floor((datetime.getMonth() + 3) / 3), // 季度
            'ms': datetime.getMilliseconds() // 毫秒
        };
        for (const k in o) {
            if (new RegExp('(' + k + ')').test(fmt)) {
                time = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
            }
        }
        return time;
    };

    /**
     * 中文字符串截取
     * @param str
     * @param sliceLen
     */
    public sliceStr(str: any, sliceLen: number) {
        if (!str) {
            return '';
        }
        let realLength = 0;
        const len = str.length;
        let charCode = -1;
        for (let i = 0; i < len; i++) {
            charCode = str.charCodeAt(i);
            if (charCode >= 0 && charCode <= 128) {
                realLength += 1;
            } else {
                realLength += 2;
            }
            if (realLength > sliceLen) {
                return `${str.slice(0, i)}...`;
            }
        }

        return str;
    }

    /**
     * 对象克隆
     * @param jsonObj
     */
    public objClone(jsonObj: any) {
        let buf: any;
        if (jsonObj instanceof Array) {
            buf = [];
            let i = jsonObj.length;
            while (i--) {
                buf[i] = this.objClone(jsonObj[i]);
            }
            return buf;
        } else if (jsonObj instanceof Object) {
            buf = {};
            for (let k in jsonObj) {
                buf[k] = this.objClone(jsonObj[k]);
            }
            return buf;
        } else {
            return jsonObj;
        }
    }

    /**
     * 验证手机号
     * @param mobile
     */
    public isMobile(mobile: string) {
        return /^1[3|4|5|6|7|8|9][0-9]\d{8}$/i.test(mobile);
    }

    /**
     * 判断目标是否在数组中
     * @param needle
     * @param array
     */
    public inArray(needle: any, array: any[]) {
        for (let i in array) {
            if (array[i] === needle) {
                return i;
            }
        }
        return false;
    }

    /**
     * 获取当前相对路径
     */
    public getUrlRelativePath() {
        let url = document.location.toString();
        let arrUrl = url.split('//');

        let start = arrUrl[1].indexOf('/');
        // stop省略，截取从start开始到结尾的所有字符
        let relUrl = arrUrl[1].substring(start);
        if (relUrl.indexOf('?') !== -1) {
            relUrl = relUrl.split('?')[0];
        }
        return relUrl;
    }

    /**
     * 表单序列化
     * @param formBox
     * @param type
     */
    public serialize(formBox: HTMLFormElement, type: string = 'json') {
        let res: any = {};
        for (let item of formBox.elements) {
            // @ts-ignore
            if (item.disabled) {
                continue;
            }
            // @ts-ignore
            switch (item.type) {
                case 'file':    // 文件输入类型
                case 'submit':  // 提交按钮
                case 'button':  // 一般按钮
                case 'image':   // 图像形式的提交按钮
                case 'reset':   // 重置按钮
                case undefined: // 未定义
                    break;
                // select控件
                case 'select-one':
                case 'select-multiple':
                    // @ts-ignore
                    if (item.name && item.name.length) {
                        // @ts-ignore
                        for (let option of item.options) {
                            let value = '';
                            if (option.selected) {
                                // @ts-ignore
                                res[item.name] = option.hasAttribute('value') ? option.value : option.text;
                                break;
                            }
                        }
                    }
                    break;

                // 单选，复选框
                case 'radio':
                case 'checkbox':
                    // 这里有个取巧 的写法，这里的判断是跟下面的default相互对应。
                    // 如果放在其他地方，则需要额外的判断取值
                    // @ts-ignore
                    if (!item.checked) {
                        break;
                    }
                default:
                    // 一般表单控件处理
                    // @ts-ignore
                    if (item.name && item.name.length) {
                        // @ts-ignore
                        res[item.name] = item.value;
                    }
            }
        }
        if (type === 'formData') {
            res = encodeURI(Object.keys(res).map((i) => {
                return i + '=' + res[i];
            }).join('&'));
        }
        return res;
    }

    /**
     * 从父元素中删除
     * @param el
     */
    public removeFromParent(el: HTMLElement) {
        if (el.parentElement) {
            el.parentElement.removeChild(el);
        }
    }

    /**
     * 添加子元素
     * @param parentEl
     * @param text
     */
    public append(parentEl: HTMLElement, text: string | HTMLElement) {
        if (typeof text === 'string') {
            let temp = document.createElement('div');
            temp.innerHTML = text;
            let frag = document.createDocumentFragment();
            while (temp.firstChild) {
                frag.appendChild(temp.firstChild);
            }
            parentEl.appendChild(frag);
        } else if (text instanceof HTMLElement) {
            parentEl.appendChild(text);
        }
    }

    /**
     * 数字零填充
     * @param num
     * @param n
     */
    public prefixInteger(num: number, n: number = 2) {
        return (Array(n).join('0') + num).slice(-n);
    }

    public setCookie(cname: string, cvalue: string, exdays: number) {
        let d = new Date();
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        let expires = 'expires=' + d.toUTCString();
        console.info(cname + '=' + cvalue + '; ' + expires);
        document.cookie = cname + '=' + cvalue + '; ' + expires;
    }

    public getCookie(cname: string) {
        let reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)');
        let arr = document.cookie.match(reg);
        if (arr) {
            return decodeURI(arr[2]);
        } else {
            return null;
        }

    }

    public clearCookie() {
        this.setCookie('username', '', -1);
    }
}
