/**
 * 数据请求处理类
 * @Author: huangjq
 * @Date:   2019-02-26
 * @Project jz
 */
import baseApi from "../api/jz-base";

export default {
    /**
     * code/enum 缓存数组
     */
    codeCaches: [],

    /**
     * 请求等待池
     */
    waitPools: [],

    get(url, params) {
        return baseApi.getData(url, params);
    },
    post(url, data) {
        return baseApi.postData(url, data);
    },
    put(url, data) {
        return baseApi.putData(url, data);
    },
    delete(url, params) {
        return baseApi.deleteData(url, params);
    },

    /**
     * 根据传入参数判断返回什么格式的数据
     * @param {Object} props 组件属性
     * @param {Function} callback 回调函数
     * @param {String} type 返回数据类型
     */
    fetchData: function(props, callback, type = "data") {
        if (type === "codeArr") {
            this.getCodeArr(props, callback);
        } else if (type === "codeObj") {
            this.getCodeObj(props, callback);
        } else if (type === "data") {
            this.reqData.apply(this, [props, callback]);
        } else {
            console.log(`没有符合${type}的请求方法，请确认type是否填写正确`);
        }
    },

    /**
     * 获取请求的类型
     * @param {Object} props 转换参数(code,enum,url,valueName,labelName)
     * @return {string} 类型关键字
     */
    getKey: props => {
        let module = props.module || "";
        if (props.code) return "code_" + module + "_" + props.code;
        if (props.enum) return "enum_" + module + "_" + props.enum;
        return "";
    },

    /**
     * 获取需要调用的请求方法
     * @param {Object} props 转换参数(code,enum,url,valueName,labelName)
     * @return {*} {function} 数据请求函数
     */
    getReqFun: props => {
        if (props.code) return baseApi.fetchCode;
        if (props.enum) return baseApi.fetchEnum;
        if (props.url) return baseApi.fetchUrl;
        return () =>
            new Promise(resolve => {
                resolve({ data: props.data });
            });
    },

    /**
     * 获取请求的关键字
     * @param {Object} props 转换参数(code,enum,url,valueName,labelName)
     * @return {*} {String} 请求的关键字
     */
    getReqKeyWord: props => {
        if (props.code) return props.code;
        if (props.enum) return props.enum;
        if (props.url) return props.url;
    },

    /**
     * 将表码、枚举、url转换为数据
     * @param {Object} props 组件参数
     * @param {function} callback 回调函数
     * @return {Promise<any>} 请求数据的Promise对象
     */
    reqData: function(props, callback) {
        let key = this.getKey(props);
        if (key.startsWith("code_") || key.startsWith("enum_")) {
            this.getCodeArr(props, callback);
        } else {
            let reqFun = this.getReqFun(props);
            let reqKeyWord = this.getReqKeyWord(props);

            return reqFun
                .apply(baseApi, [reqKeyWord, props.module])
                .then(({ data }) => {
                    callback(data);
                })
                .catch(error => {
                    console.error(error);
                });
        }
    },

    /**
     * 获取表码、枚举、url数据对象
     * @param {Object} props 组件参数
     * @param {Function} callback
     */
    getCodeObj: function(props, callback) {
        this.getCodeArr(props, data => {
            callback(this.arr2Obj(data, props.valueName, props.labelName));
        });
    },

    /**
     * 获取表码、枚举、url数据数组
     * @param {Object} props 组件参数
     * @param {Function} callback 回调函数
     */
    getCodeArr: function(props, callback) {
        let waitPools = this.waitPools;
        let key = this.getKey(props);
        let noCache = props.noCache;
        if (!noCache) {
            let code = this.searchCodeOfCaches(key);
            if (code) {
                callback(code);
                return;
            }
        }
        let waitPool = waitPools[key];
        if (waitPool) {
            // 等待池返回后再执行操作
            waitPool
                .then(function(map) {
                    callback(map);
                })
                .catch(err => {
                    console.error(err);
                });
        } else {
            waitPool = new Promise((resolve, reject) => {
                let reqFun = this.getReqFun(props);
                let reqParam = this.getReqKeyWord(props);

                reqFun
                    .apply(baseApi, [reqParam, props.module])
                    .then(({ data }) => {
                        if (key.startsWith("code_") || key.startsWith("enum_")) {
                            this.bufferCode(key, data);
                        }
                        delete waitPools[key];
                        resolve(data);
                        callback(data);
                    })
                    .catch(error => {
                        console.error(error);
                    });
            });
            waitPools[key] = waitPool;
        }
    },

    /**
     * 查询缓存中是否有code/enum的缓存
     * @param key 关键字
     * @return {*} code/enum或者undefined
     */
    searchCodeOfCaches: function(key) {
        return this.codeCaches[key];
    },

    /**
     * 将数组转为对象
     * @param arr 待转换数组
     * @param codeName 对象的key名
     * @param valueName 对象的value名
     * @return 对象
     */
    arr2Obj: function(arr, valueName, labelName) {
        let tmpObj = {};
        if (!valueName) valueName = "value";
        if (!labelName) labelName = "label";
        arr.map(function(item) {
            tmpObj[item[valueName]] = item[labelName];
        });
        return tmpObj;
    },

    /**
     * 将code/enum放进缓存
     * @param key 表码/枚举名
     * @param data code/enum数组
     * @return code/enum对象
     */
    bufferCode: function(key, data) {
        this.codeCaches[key] = data;
        return data;
    },

    /**
     * 请求表格数据
     * @param {Object} props 组件参数
     * @param {Object} params 请求参数
     * @return {Promise<any>} 请求数据的Promise对象
     */
    reqTableData: function(props, params) {
        let url = props.url;
        let result = {};
        if (url) {
            result = baseApi.reqTableData(url, params, props.module);
        } else {
            result = Promise.resolve({ data: props.data });
        }
        return result;
    },

    /**
     * 将扁平化的数据转为树结构数据
     * @param arr 待转换数据数组
     * @param idStr id字段名称
     * @param pidStr pid字段名称
     * @param childrenStr 转换后的children字段名称
     * @return {Array} 转换后的树结构数据
     */
    toTreeData: function(arr, idStr, pidStr, childrenStr) {
        let r = [],
            hash = {},
            id = idStr,
            pid = pidStr,
            children = childrenStr,
            i = 0,
            j = 0,
            len = arr.length;
        for (; i < len; i++) {
            hash[arr[i][id]] = arr[i];
        }
        for (; j < len; j++) {
            let aVal = arr[j],
                hashVP = hash[aVal[pid]];
            if (hashVP) {
                !hashVP[children] && (hashVP[children] = []);
                hashVP[children].push(aVal);
            } else {
                r.push(aVal);
            }
        }
        return r;
    }
};
