import Schema from "async-validator";
import { PanelContainerModel, PanelRawitemModel, PanelFieldModel, PanelControlModel, PanelButtonModel, PanelUserControlModel, PanelTabPanelModel, PanelTabPageModel, PanelCtrlPosModel } from '@/model/panel-detail';
import { PluralizeRule } from './pluralizeRule';
/**
 * 平台工具类
 * 
 * @export
 * @class Util
 */
export class Util {

    /**
     * @description PluralizeRule对象
     * @private
     * @type {PluralizeRule}
     * @memberof Util
     */
    public static pluralizeRule: PluralizeRule = new PluralizeRule();

    /**
     * 创建 UUID
     *
     * @static
     * @returns {string}
     * @memberof Util
     */
    public static createUUID(): string {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
        }
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
    }

    /**
     * 创建序列号
     *
     * @static
     * @returns {number}
     * @memberof Util
     */
    public static createSerialNumber(): number {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000);
        }
        return s4();
    }

    /**
     * 判断是否为一个函数
     *
     * @static
     * @param {*} func
     * @returns {boolean}
     * @memberof Util
     */
    public static isFunction(func: any): boolean {
        return typeof (func) === 'function';
    }

    /**
     *
     *
     * @static
     * @param {*} [o={}]
     * @memberof Util
     */
    public static processResult(o: any = {}): void {
        if (o.url != null && o.url !== '') {
            window.location.href = o.url;
        }
        if (o.code != null && o.code !== '') {
            // tslint:disable-next-line:no-eval
            eval(o.code);
        }

        if (o.downloadurl != null && o.downloadurl !== '') {
            const downloadurl = this.parseURL2(o.downloadurl, '');
            this.download(downloadurl);
        }
    }

    /**
     * 下载文件
     * 
     * @static
     * @param {string} url 
     * @memberof Util
     */
    public static download(url: string): void {
        window.open(url, '_blank');
    }

    /**
     * 
     * 
     * @static
     * @param {any} url 
     * @param {any} params 
     * @returns {string} 
     * @memberof Util
     */
    public static parseURL2(url: string, params: any): string {
        let tmpURL;
        if (url.indexOf('../../') !== -1) {
            tmpURL = url.substring(url.indexOf('../../') + 6, url.length);
        } else if (url.indexOf('/') === 0) {
            tmpURL = url.substring(url.indexOf('/') + 1, url.length);
        } else {
            tmpURL = url;
        }

        if (params) {
            return tmpURL + (url.indexOf('?') === -1 ? '?' : '&');
        } else {
            return tmpURL;
        }
    }

    /**
     * 是否是数字
     * 
     * @param {*} num 
     * @returns {boolean} 
     * @memberof Util
     */
    public static isNumberNaN(num: any): boolean {
        return Number.isNaN(num) || num !== num;
    }

    /**
     * 是否未定义
     * 
     * @static
     * @param {*} value 
     * @returns {boolean} 
     * @memberof Util
     */
    public static isUndefined(value: any): boolean {
        return typeof value === 'undefined';
    }

    /**
     * 是否为空
     * 
     * @static
     * @param {*} value 
     * @returns {boolean} 
     * @memberof Util
     */
    public static isEmpty(value: any): boolean {
        return this.isUndefined(value) || Object.is(value, '') || value === null || value !== value;
    }

    /**
     * 转换为矩阵参数
     *
     * @static
     * @param {*} obj
     * @returns {*}
     * @memberof Util
     */
    public static formatMatrixStringify(obj: any): any {
        let str: string = '';
        if (obj && !(obj instanceof Array) && (obj instanceof Object)) {
            const keys: string[] = Object.keys(obj);
            keys.forEach((key: string) => {
                if (!obj[key]) {
                    return;
                }
                if (!Object.is(str, '')) {
                    str += ';';
                }
                str += `${key}=${obj[key]}`;
            });
        }
        return Object.is(str, '') ? undefined : str;
    }

    /**
     * 准备路由参数
     *
     * @static
     * @param {*} { route: route, sourceNode: sourceNode, targetNode: targetNode, data: data }
     * @returns {*}
     * @memberof Util
     */
    public static prepareRouteParmas({ route: route, sourceNode: sourceNode, targetNode: targetNode, data: data }: any): any {
        const params: any = {};
        if (!sourceNode || (sourceNode && Object.is(sourceNode, ''))) {
            return params;
        }
        if (!targetNode || (targetNode && Object.is(targetNode, ''))) {
            return params;
        }
        const indexName = route.matched[0].name;
        Object.assign(params, { [indexName]: route.params[indexName] });
        Object.assign(params, { [targetNode]: this.formatMatrixStringify(data) });
        return params;
    }

    /**
     * 获取当前值类型
     *
     * @static
     * @param {*} obj
     * @returns
     * @memberof Util
     */
    public static typeOf(obj: any): string {
        const toString = Object.prototype.toString;
        const map: any = {
            '[object Boolean]': 'boolean',
            '[object Number]': 'number',
            '[object String]': 'string',
            '[object Function]': 'function',
            '[object Array]': 'array',
            '[object Date]': 'date',
            '[object RegExp]': 'regExp',
            '[object Undefined]': 'undefined',
            '[object Null]': 'null',
            '[object Object]': 'object'
        };
        return map[toString.call(obj)];
    }

    /**
     * 深拷贝(deepCopy)
     *
     * @static
     * @param {*} data
     * @returns {*}
     * @memberof Util
     */
    public static deepCopy(data: any): any {
        if(data && data._isVue ){
            return data;
        }
        const t = this.typeOf(data);
        let o: any;

        if (t === 'array') {
            o = [];
        } else if (t === 'object') {
            o = {};
        } else {
            return data;
        }

        if (t === 'array') {
            for (let i = 0; i < data.length; i++) {
                o.push(this.deepCopy(data[i]));
            }
        } else if (t === 'object') {
            for (let i in data) {
                o[i] = this.deepCopy(data[i]);
            }
        }
        return o;
    }

    /**
     * 名称格式化
     *
     * @static
     * @param {string} name
     * @returns {string}
     * @memberof Util
     */
    public static srfFilePath2(name: string): string {
        if (!name || (name && Object.is(name, ''))) {
            console.error("名称异常")
            return '';
        }
        name = name.replace(/[_]/g, '-');
        let state: number = 0;
        let _str = '';
        const uPattern = /^[A-Z]{1}$/;

        const str1 = name.substring(0, 1);
        const str2 = name.substring(1)
        state = uPattern.test(str1) ? 1 : 0;
        _str = `${_str}${str1.toLowerCase()}`;

        for (let chr of str2) {
            if (uPattern.test(chr)) {
                if (state === 1) {
                    _str = `${_str}${chr.toLowerCase()}`;
                } else {
                    _str = `${_str}-${chr.toLowerCase()}`;
                }
                state = 1
            } else {
                _str = `${_str}${chr.toLowerCase()}`;
                state = 0
            }
        }
        _str = _str.replace(/---/g, '-').replace(/--/g, '-');

        return _str;
    }

    /**
     * 计算单词复数
     *
     * @static
     * @returns {string}
     * @memberof Util
     */
    public static srfpluralize(word: string) {
        let wordStr = word.trim().toLowerCase();
        if (wordStr.length == 0) {
            return wordStr;
        }
        if (this.pluralizeRule.isUncountable(wordStr)) {
            return wordStr;
        }
        const newWordStr = this.pluralizeRule.irregularChange(wordStr);
        if (newWordStr) {
            return newWordStr;
        } else {
            return this.pluralizeRule.ruleChange(wordStr);
        }
    }

    /**
     * 附加参数格式化
     *
     * @static
     * @param {any} arg 表单数据
     * @param {any} parent 外层context或viewparams
     * @param {any} params 附加参数
     * @returns {any}
     * @memberof Util
     */
    public static formatData(arg: any, parent: any, params: any): any {
        let _data: any = {};
        Object.keys(params).forEach((name: string) => {
            if (!name) {
                return;
            }
            let value: string | null = params[name];
            if (value && value.startsWith('%') && value.endsWith('%')) {
                const key = value.substring(1, value.length - 1);
                if (arg && arg.hasOwnProperty(key)) {
                    if (arg[key] !== null && arg[key] !== undefined) {
                        value = arg[key];
                    } else if (parent[key] !== null && parent[key] !== undefined) {
                        value = parent[key];
                    } else {
                        value = null;
                    }
                } else {
                    value = null;
                }
            }
            Object.assign(_data, { [name]: value });
        });
        return _data;
    }

    /**
     * 计算导航数据
     * 先从当前数据目标计算，然后再从当前上下文计算，最后从当前视图参数计算，没有则为null
     * 
     * @static
     * @param {any} data 表单数据
     * @param {any} parentContext 外层context
     * @param {any} parentParam 外层param
     * @param {any} params 附加参数
     * @returns {any}
     * @memberof Util
     */
    public static computedNavData(data: any, parentContext: any, parentParam: any, params: any): any {
        let _data: any = {};
        if (params && Object.keys(params).length > 0) {
            Object.keys(params).forEach((name: string) => {
                if (!name) {
                    return;
                }
                let value: string | null = params[name];
                if (value && value.startsWith('%') && value.endsWith('%')) {
                    const key = value.substring(1, value.length - 1).toLowerCase();
                    if (data && data.hasOwnProperty(key)) {
                        value = data[key];
                    } else if (parentContext && parentContext[key]) {
                        value = parentContext[key];
                    } else if (parentParam && parentParam[key]) {
                        value = parentParam[key];
                    } else {
                        value = null;
                    }
                }
                Object.assign(_data, { [name.toLowerCase()]: value });
            });
        }
        return _data;
    }

    /**
     * 日期格式化
     *
     * @static
     * @param {string} fmt 格式化字符串
     * @param {any} date 日期对象
     * @returns {string}
     * @memberof Util
     */
    public static dateFormat(date: any, fmt: string = "YYYY-mm-dd HH:MM:SS"): string {
        let ret;
        const opt: any = {
            "Y+": date.getFullYear().toString(),        // 年
            "m+": (date.getMonth() + 1).toString(),     // 月
            "d+": date.getDate().toString(),            // 日
            "H+": date.getHours().toString(),           // 时
            "M+": date.getMinutes().toString(),         // 分
            "S+": date.getSeconds().toString()          // 秒
            // 有其他格式化字符需求可以继续添加，必须转化成字符串
        };
        for (let k in opt) {
            ret = new RegExp("(" + k + ")").exec(fmt);
            if (ret) {
                fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
            };
        };
        return fmt;
    }


    /**
     * 深度合并对象
     * 
     * @param FirstOBJ 目标对象
     * @param SecondOBJ 原对象
     * @returns {Object}
     * @memberof Util
     */
    public static deepObjectMerge(FirstOBJ: any, SecondOBJ: any) {
        for (var key in SecondOBJ) {
            FirstOBJ[key] = FirstOBJ[key] && FirstOBJ[key].toString() === "[object Object]" ?
                this.deepObjectMerge(FirstOBJ[key], SecondOBJ[key]) : FirstOBJ[key] = SecondOBJ[key];
        }
        return FirstOBJ;
    }


    /**
     * 表单项校验
     * 
     * @param property 表单项属性名
     * @param data 表单数据
     * @param rules 表单值规则
     * @returns {Promise}
     * @memberof Util
     */
    public static validateItem(property: string, data: any, rules: any) {
        // 1.获取数值和规则
        const value = data[property];
        const rule = rules[property];
        // 2.创建校验规则
        const schema = new Schema({ [property]: rule })
        // 校验返回Promise
        return schema.validate({ [property]: value })
    }


    /**
     * 设置cookie
     * 
     * @memberof Util
     */
    public static setCookie(name: any, value: any, day: any) {
        if (day !== 0) { //当设置的时间等于0时，不设置expires属性，cookie在浏览器关闭后删除
            let curDate = new Date();
            let curTamp = curDate.getTime();
            let curWeeHours = new Date(curDate.toLocaleDateString()).getTime() - 1;
            let passedTamp = curTamp - curWeeHours;
            let leftTamp = 24 * 60 * 60 * 1000 - passedTamp;
            let leftTime = new Date();
            leftTime.setTime(leftTamp + curTamp);
            document.cookie = name + "=" + escape(value) + ";expires=" + leftTime.toUTCString();
        } else {
            document.cookie = name + "=" + escape(value);
        }
    }

    /**
     * 获取cookie
     * 
     * @memberof Util
     */
    public static getCookie(name: any): any {
        let arr;
        let reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
        if (arr = document.cookie.match(reg))
            return unescape(arr[2]);
        else
            return null;
    }

    /**
     * 获取盒子大小（宽高模式针对面板项，按钮等项模型是控制的布局内容的宽高）
     * @param mode 模式 "WIDTH" | "HEIGHT"
     * @param style 样式 "FULL"(全部宽度) | "PX"（像素） | "PERCENTAGE"（百分比）
     * @param value 
     * @returns 
     */
    public static getBoxSize(mode: "WIDTH" | "HEIGHT", style: string, value: number) {
        if (!mode) {
            return {};
        }
        if (!style) {
            style = 'PX';
        }
        if (style === "FULL") {
            return { [mode.toLowerCase()]: "100%" };
        } else {
            if (!value) {
                return {};
            }
            else if (style === "PERCENTAGE") {
                return { [mode.toLowerCase()]: `${value}%` };
            } else {
                return { [mode.toLowerCase()]: `${value}px` };
            }
        }
    }

    /**
     * 获取项间隔样式
     *
     * @param {string} spacingType
     * @param {string} direction
     * @return {*} 
     */
    public static getItemSpacingStyle(spacingType: string, direction: string) {
        switch (spacingType) {
            case 'OUTERNONE':
                return { [`margin-${direction}`]: '0px' };
            case 'OUTERSMALL':
                return { [`margin-${direction}`]: '8px' };
            case 'OUTERMEDIUM':
                return { [`margin-${direction}`]: '16px' };
            case 'OUTERLARGE':
                return { [`margin-${direction}`]: '24px' };
            case 'INNERNONE':
                return { [`padding-${direction}`]: '0px' };
            case 'INNERSMALL':
                return { [`padding-${direction}`]: '8px' };
            case 'INNERMEDIUM':
                return { [`padding-${direction}`]: '16px' };
            case 'INNERLARGE':
                return { [`padding-${direction}`]: '24px' };
            default:
                return {};
        }
    }

    /**
     * 获取布局项实例
     *
     * @static
     * @param {*} layoutModelItem
     * @memberof Util
     */
    public static getLayoutItemInstance(layoutModelItem: any): any {
        if (!layoutModelItem || !layoutModelItem.itemType) {
            throw new Error('获取布局项实例异常');
        }
        switch (layoutModelItem.itemType) {
            case 'CONTAINER':
                return new PanelContainerModel(layoutModelItem);
            case 'RAWITEM':
                return new PanelRawitemModel(layoutModelItem);
            case 'FIELD':
                return new PanelFieldModel(layoutModelItem);
            case 'CONTROL':
                return new PanelControlModel(layoutModelItem);
            case 'BUTTON':
                return new PanelButtonModel(layoutModelItem);
            case 'USERCONTROL':
                return new PanelUserControlModel(layoutModelItem);
            case 'TABPANEL':
                return new PanelTabPanelModel(layoutModelItem);
            case 'CTRLPOS':
                return new PanelCtrlPosModel(layoutModelItem);
            case 'TABPAGE':
                return new PanelTabPageModel(layoutModelItem);
            default:
                throw new Error(`${layoutModelItem.itemType}暂不支持`);
        }
    }

    /**
     * 清除附加数据（源数据里面有的数据在目标数据中都清除）
     *
     * @param source 源数据
     * @param target 目标数据
     *
     * @memberof Util
     */
    public static clearAdditionalData(source: any, target: any) {
        if (target && (Object.keys(target).length > 0) && source && (Object.keys(source).length > 0)) {
            Object.keys(source).forEach((key: string) => {
                if (target.hasOwnProperty(key)) {
                    delete target[key];
                }
            })
        }
    }
}