/**
 * 资源缓存管理类，需要动态加载资源时，需要释放资源缓存时使用
 */
cc.Class({
    extends: cc.Component,

    properties: {
        _resCache: [],
        _resDirCache: [],
        _releaseResNextSenceMap: [], // 下个场景需要自动释放的资源
        _tempResMap: [], // 切换场景不释放的资源

        customerResName: [], // 厅主资源web端路径
        customerRes: [], // 厅主资源web端缓存
        fileServicePath: null, // 文件服务器地址
    },

    /**
     * 加载 url 图片为 spriteFrame
     * @param {string} 图片 url
     * @param {Function} callback 加载完回调函数
     * @param {Object} target 回调函数调用对象
     * @param {Boolean} isAutoRelease 是不是在下个场景自动释放
     */
    loadSpriteWithUrl(url, callback, target, isAutoRelease = true) {
        if (!url) { cc.log("loadSpriteWithUrl参数错误"); return; }
        cc.loader.load(url, (err, spData) => {
            if (err || spData.length <= 0) {
                cc.log("ResourcesManager: loadSpriteWithUrl: loadSprite error = %s", err);
                callback.call(target, null, err);
                return;
            }
            let spriteFrame = new cc.SpriteFrame(spData, cc.Rect(0, 0, spData.width, spData.height));
            let item = { urlPath: url, urlType: cc.SpriteFrame, data: spriteFrame };
            if (isAutoRelease) {
                this._releaseResNextSenceMap.splice(0, 0, item);
            } else {
                this._tempResMap.splice(0, 0, item);
            }
            if (callback) {
                callback.call(target, spriteFrame, null);
            }
        });
    },

    /**
     * 加载 url 音频 使用loadRes加载音频会报错
     * @param {string} 音频 url 后面需要带上后缀
     * @param {Function} callback 加载完回调函数
     * @param {Object} target 回调函数调用对象
     * @param {Boolean} isAutoRelease 是不是在下个场景自动释放
     */
    loadAudioWithUrl(url, callback, target, isAutoRelease = true) {
        if (!url) { cc.log("loadAudioWithUrl参数错误"); return; }
        cc.loader.load(cc.url.raw(url), (err, audioData) => {
            if (err || audioData.length <= 0) {
                cc.log("ResourcesManager: loadAudioWithUrl: loadAudio error = %s", err);
                return;
            }
            let item = { urlPath: url, urlType: cc.AudioClip, data: audioData };
            if (isAutoRelease) {
                this._releaseResNextSenceMap.splice(0, 0, item);
            } else {
                this._tempResMap.splice(0, 0, item);
            }
            if (callback) {
                callback.call(target, audioData);
            }
        });
    },

    /**
     * 加载单个资源（一次只能加载单个 Asset）
     * @param {string} path 资源路径 path（且路径的结尾处 不能 包含文件扩展名)
     * @param {Function} callback 加载完回调函数
     * @param {Object} target 回调函数调用对象
     * @param {urltype} type 资源类型 （最好传类型）
     * @param {Boolean} isAutoRelease 是不是在下个场景自动释放
     * @param {Function} progressFunc 进度回调
     */
    loadResByPath(path, callback, target, type, isAutoRelease = true, progressFunc = (completedCount, totalCount, item) => {}, errorCallBack) {
        if (!path || !type) { cc.log("loadResByPath参数错误"); return; }
        cc.loader.loadRes(path, type, progressFunc, (err, spData) => {
            let item = { urlPath: path, urlType: type, data: spData };
            if (isAutoRelease) {
                this._releaseResNextSenceMap.splice(0, 0, item);
            } else {
                this._tempResMap.splice(0, 0, item);
            }
            if (callback) {
                callback.call(target, spData);
            }
            if (err) {
                if (progressFunc) progressFunc(0, 0);
            }

            if (errorCallBack) {
                errorCallBack.call(target, err);
            }
        });
    },

    /**
     * @description  批量加载资源，加载文件夹中如果类型的资源
     * @param {string} 资源路径 path
     * @param {Function} 加载完回调函数 callback
     * @param {Object} 回调函数调用对象 target
     * @param {urltype} type 资源类型 （最好传类型）
     * @param {Boolean} isAutoRelease 是不是在下个场景自动释放
     * @param {Function} progressFunc 进度回调
     */
    loadResDirByPath(path, callback, target, type = null, isAutoRelease = true, progressFunc = (completedCount, totalCount, item) => {}, errorCallBack) {
        let self = this;
        if (!path) {
            cc.log("loadResDirByPath参数错误");
            return;
        }
        let loadCallBack = (err, spData, urls) => {
            if (err || spData.length <= 0) {
                cc.log("loadResDir no type error %s", err);
                progressFunc(0, 0);
                return;
            }
            for (let i = 0; i < urls.length; i++) {
                let item = { urlPath: urls[i], urlType: spData[i], data: spData[i] };
                if (isAutoRelease) {
                    self._releaseResNextSenceMap.splice(0, 0, item);
                } else {
                    self._tempResMap.splice(0, 0, item);
                }
            }
            if (callback) {
                callback.call(target, spData);
            }
            if (err && progressFunc) {
                progressFunc(0, 0);
            }
            if (errorCallBack) {
                errorCallBack.call(target, err);
            }
        };
        if (type) {
            cc.loader.loadResDir(path, type, progressFunc, loadCallBack);
        } else {
            cc.loader.loadResDir(path, progressFunc, loadCallBack);
        }
    },
    /**
     * @description 加载内存数据(如果内存无数据，则调用加载方法)
     * @param {String} path 数据地址
     * @param {cc.Asset} type 数据类型
     * @param {Function} callback 加载完毕数据回调
     * @param {Boolean} isAutoRelease 是不是在下个场景自动释放
     * @param {Function} progressFunc 进度回调
     */
    getLoaderData(path, type, target, callback, isAutoRelease = true, progressFunc) {
        if (!path) return;
        let data = cc.loader.getRes(path, type);
        if (data) {
            if (callback instanceof Function) callback.call(target, data);
        } else if (type instanceof cc.AudioClip) {
            this.loadAudioWithUrl(path, callback, target, isAutoRelease);
        } else {
            this.loadResByPath(path, callback, target, type, isAutoRelease, progressFunc);
        }
    },

    getLoaderSpriteFrame(path) {
        if (!path) return null;
        const texture = cc.loader.getRes(path);
        const spriteFrame = new cc.SpriteFrame();
        spriteFrame.initWithTexture(texture);
        return spriteFrame;
    },

    /**
     * @description 加载龙骨
     * @param {string} 龙骨地址 pth
    * @param {Function} 加载完回调函数 callback
     * @param {Object} 回调函数调用对象 target
     */
    loadDragonBoneAnimation(path, callback, target) {
        if (!path) {
            cc.error("龙骨参数错误");
            return;
        }

        cc.loader.loadResDir(path, (err, assets) => {
            if (err || assets.length <= 0) {
                cc.log("loadDragonBone error", err);
            } else {
                cc.log("DragonBoneData ", assets);
                // const animationDisplay = node.getComponent(dragonBones.ArmatureDisplay);
                // cc.loader.setAutoRelease(assets, true);
                // assets.forEach((asset) => {
                //     if (asset instanceof dragonBones.DragonBonesAsset) {
                //         animationDisplay.dragonAsset = asset;
                //     }
                //     if (asset instanceof dragonBones.DragonBonesAtlasAsset) {
                //         animationDisplay.dragonAtlasAsset = asset;
                //     }
                // });
                // animationDisplay.armatureName = armatureName;
                // animationDisplay.playAnimation(newAnimation, playTimes);
                // if (completeCallback) {
                //     animationDisplay.addEventListener(dragonBones.EventObject.COMPLETE, completeCallback);
                // }
                callback.call(target, assets);
            }
        });
    },

    releaseAsset(path, type) {
        cc.loader.release(path, type);
        cc.sys.garbageCollect();
    },
    /**
     * 释放一个资源（prefab或者atlas）以及所有它依赖的资源
     * @param {string} path 资源路径
     * @param {Object} type path资源类型
     * @param {Object} data path资源数据
     * @param {Array} exclude 需要剔除的不释放的资源（prefab或者atlas）
     */
    releaseDependsAsset(path, type, data, exclude) {
        let deps = null;
        deps = cc.loader.getDependsRecursively(data);
        if (exclude && exclude.length > 0) {
            for (let i = 0; i < exclude.length; i++) {
                let excludeDeps = cc.loader.getDependsRecursively(exclude[i]);
                if (excludeDeps && excludeDeps.length > 0) {
                    for (let ei = 0; ei < excludeDeps.length; ei++) {
                        let index = deps.indexOf(excludeDeps[ei]);
                        if (index !== -1) {
                            deps.splice(index, 1);
                        }
                    }
                }
            }
            for (let i = this._tempResMap.length - 1; i >= 0; i--) {
                let element = this._tempResMap[i];
                if (element.data instanceof cc.SpriteAtlas || element.data instanceof cc.Prefab) {
                    let excludeDeps = cc.loader.getDependsRecursively(element.data);
                    if (excludeDeps && excludeDeps.length > 0) {
                        for (let ei = 0; ei < excludeDeps.length; ei++) {
                            let index = deps.indexOf(excludeDeps[ei]);
                            if (index !== -1) {
                                deps.splice(index, 1);
                            }
                        }
                    }
                } else {
                    let index = deps.indexOf(element.data);
                    if (index !== -1) {
                        deps.splice(index, 1);
                    }
                }
            }
        }
        // cc.log("释放path资源释放的资源 %s数, %s,%s,", path, deps.length, deps);
        cc.loader.release(deps);
    },
    /**
     * 释放一个场景依赖的资源
     * @param {Array} curDpes 当前场景依赖资源，可释放
     * @param {Array} nextDeps 下一个场景依赖资源，不可释放
     */
    releaseSenceAssets(curDpes, nextDeps) {
        let deps = curDpes;
        if (nextDeps && nextDeps.length > 0) {
            for (let i = 0; i < nextDeps.length; i++) {
                let index = deps.indexOf(nextDeps[i]);
                if (index !== -1) {
                    deps.splice(index, 1);
                }
            }
        }
        for (let i = this._tempResMap.length - 1; i >= 0; i--) {
            let element = this._tempResMap[i];
            if (element.data instanceof cc.SpriteAtlas || element.data instanceof cc.Prefab) {
                let excludeDeps = cc.loader.getDependsRecursively(element.data);
                if (excludeDeps && excludeDeps.length > 0) {
                    for (let ei = 0; ei < excludeDeps.length; ei++) {
                        let index = deps.indexOf(excludeDeps[ei]);
                        if (index !== -1) {
                            deps.splice(index, 1);
                        }
                    }
                }
            } else {
                let index = deps.indexOf(element.data);
                if (index !== -1) {
                    deps.splice(index, 1);
                }
            }
        }
        // cc.log("释放path资源释放的资源 %s数, %s,", deps.length, deps);
        cc.loader.release(deps);
    },

    autoReleaseRes(nextDeps) {
        for (let i = this._releaseResNextSenceMap.length - 1; i >= 0; i--) {
            let element = this._releaseResNextSenceMap[i];
            this.releaseDependsAsset(element.urlPath, element.urlType, element.data, nextDeps);
        }
        this._releaseResNextSenceMap = [];
    },

    /**
     * 获取所有需要手动释放的资源
     */
    getTempRes() {
        return this._tempResMap;
    },

    releaseRes() {
        if (CC_EDITOR) return;

        const self = this;
        self._resCache.forEach((element) => {
            cc.loader.release(element);
        });
        self._resDirCache.forEach((element) => {
            cc.loader.releaseResDir(element);
        });
    },

    /**
     * web端加载厅主资源
     */
    // 大厅音乐
    loadCustomerHallMusic(callback, target) {
        if (this.customerRes.hallMusic || !this.customerResName.hallMusic || !this.fileServicePath) {
            if (callback) {
                callback.call(target, this.customerRes.hallMusic);
            }
        } else {
            cc.loader.load(`${this.fileServicePath}${this.customerResName.hallMusic}`, (err, clip) => {
                this.customerRes.hallMusic = clip;
                if (callback) {
                    callback.call(target, clip);
                }
            });
        }
    },

    // 登录logo
    loadCustomerLogo(callback, target) {
        if (this.customerRes.hallLogo || !this.customerResName.hallLogo || !this.fileServicePath) {
            if (callback) {
                callback.call(target, this.customerRes.hallLogo);
            }
        } else {
            this.loadSpriteWithUrl(`${this.fileServicePath}${this.customerResName.hallLogo}`, (spData) => {
                this.customerRes.hallLogo = spData;
                if (callback) {
                    callback.call(target, spData);
                }
            }, this, false);
        }
    },

    // 登录背景图
    loadCustomerLoginBg(callback, target) {
        let loginRes = this.customerResName.loginScen.split(",");
        let loginBg = null;
        for (let i = 0; i < loginRes.length; i++) {
            if (loginRes[i].match("LoginBGP.jpg")) {
                loginBg = loginRes[i];
            }
        }
        if (this.customerRes.loginBg || !loginBg || !this.fileServicePath) {
            if (callback) {
                callback.call(target, this.customerRes.loginBg);
            }
        } else {
            this.loadSpriteWithUrl(`${this.fileServicePath}${loginBg}`, (spData) => {
                this.customerRes.loginBg = spData;
                if (callback) {
                    callback.call(target, spData);
                }
            }, this, false);
        }
    },

    loadCustomerHallBg(callback, target) {
        let hallRes = this.customerResName.hallScene.split(",");
        let hallBg = null;
        for (let i = 0; i < hallRes.length; i++) {
            if (hallRes[i].match("HallBGP.jpg")) {
                hallBg = hallRes[i];
            }
        }
        if (this.customerRes.hallBg || !hallBg || !this.fileServicePath) {
            if (callback) {
                callback.call(target, this.customerRes.hallBg);
            }
        } else {
            this.loadSpriteWithUrl(`${this.fileServicePath}${hallBg}`, (spData) => {
                this.customerRes.hallBg = spData;
                if (callback) {
                    callback.call(target, spData);
                }
            }, this, false);
        }
    },
    // 登录特效
    loadCustomerLoginSpine(callback, target) {
        let loginRes = this.customerResName.loginScen.split(",");
        if (this.customerRes.loginSpine || loginRes.length <= 1 || !this.fileServicePath) {
            if (callback) {
                callback.call(target, this.customerRes.loginSpine);
            }
        } else {
            this.loadCustomerSpine("Login", callback, target);
        }
    },

    // 大厅特效
    loadCustomerHallSpine(callback, target) {
        let hallRes = this.customerResName.hallScene.split(",");
        if (this.customerRes.hallSpine || hallRes.length <= 1 || !this.fileServicePath) {
            if (callback) {
                callback.call(target, this.customerRes.hallSpine);
            }
        } else {
            this.loadCustomerSpine("Hall", callback, target);
        }
    },

    // 特效加载
    loadCustomerSpine(path, callback, target) {
        let spineRes = null;
        if (path === "Login") {
            spineRes = this.customerResName.loginScen.split(",");
        } else if (path === "Hall") {
            spineRes = this.customerResName.hallScene.split(",");
        }

        let jsonFile = null;
        let atlasFile = null;
        let pngFile = null;
        let png2File = null;
        let pngNumber = 0;
        for (let i = 0; i < spineRes.length; i++) {
            if (spineRes[i].match(`${path}BG.json`)) {
                jsonFile = spineRes[i];
            } else if (spineRes[i].match(`${path}BG.atlas`)) {
                atlasFile = spineRes[i];
            } else if (spineRes[i].match(`${path}BG.png`)) {
                pngFile = spineRes[i];
                pngNumber++;
            } else if (spineRes[i].match(`${path}BG2.png`)) {
                png2File = spineRes[i];
                pngNumber++;
            }
        }
        if (!jsonFile || !atlasFile || (!pngFile && !png2File)) {
            if (callback) {
                if (path === "Login") {
                    callback.call(target, this.customerRes.loginSpine);
                } else if (path === "Hall") {
                    callback.call(target, this.customerRes.hallSpine);
                }
            }
        } else {
            let promise1 = new Promise((resolve, reject) => {
                cc.loader.load({ url: `${this.fileServicePath}${jsonFile}`, type: "txt" }, (err, spData) => {
                    if (err) {
                        reject(err);
                    }
                    resolve(spData);
                });
            });
            let promise2 = new Promise((resolve, reject) => {
                cc.loader.load({ url: `${this.fileServicePath}${atlasFile}`, type: "txt" }, (err, spData) => {
                    if (err) {
                        reject(err);
                    }
                    resolve(spData);
                });
            });
            let promise3 = new Promise((resolve, reject) => {
                cc.loader.load(`${this.fileServicePath}${pngFile}`, (err, spData) => {
                    if (err) {
                        reject(err);
                    }
                    resolve(spData);
                });
            });
            let promise4 = null;
            if (pngNumber > 1) {
                promise4 = new Promise((resolve, reject) => {
                    cc.loader.load(`${this.fileServicePath}${png2File}`, (err, spData) => {
                        if (err) {
                            reject(err);
                        }
                        resolve(spData);
                    });
                });
            } else {
                promise4 = Promise.resolve(null);
            }
            Promise.all([promise1, promise2, promise3, promise4]).then((values) => {
                let asset = new sp.SkeletonData();
                asset.skeletonJson = values[0];
                asset.atlasText = values[1];
                asset.textures = [values[2]];
                asset.textureNames = [`${path}BG.png`];
                if (values[3]) {
                    asset.textures = [values[2], values[3]];
                    asset.textureNames = [`${path}BG.png`, `${path}BG2.png`];
                }
                if (path === "Login") {
                    this.customerRes.loginSpine = asset;
                } else if (path === "Hall") {
                    this.customerRes.hallSpine = asset;
                }
                if (callback) {
                    callback.call(target, asset);
                }
            });
        }
    },
});
