import { GlobalLoader } from "../engine/2d/loader";
import Texture from "../engine/2d/texture/Texture";
import BaseTexture from "../engine/2d/texture/BaseTexture";
import { createTextureSheet } from "../engine/2d/texture/createTextureSheet";
import { VideoEntity } from "../engine/2d/svga";
import { TextureCache } from "../engine/2d/utils";
import { Howl, Howler } from 'howler';
// import { Sound, WebAudioDecode, HtmlSound, WebAudioSound } from "../engine/sound";
import { Event } from "../engine/2d/events";

// let canUseWebAudio = window["AudioContext"] || window["webkitAudioContext"] || window["mozAudioContext"];
// if (canUseWebAudio) {
//     try {
//         //防止某些chrome版本创建异常问题
//         WebAudioDecode.ctx = new (window["AudioContext"] || window["webkitAudioContext"] || window["mozAudioContext"])();
//     }
//     catch (e) {
//         canUseWebAudio = false;
//     }
// }
// let useSoundClass = HtmlSound;
// //@ts-ignore
// if(canUseWebAudio) useSoundClass = WebAudioSound

interface ResData {
    /**
     * 分组数据
     */
    groups: GroupInt[];
    //暂时没有工具，不用
    resources?: any
}

interface GroupInt {
    /**
     * 所有的资源名字，根据,分割，根据后缀区分类型
     * 
     */
    keys: string;//"aa.png,bb.jpg,name.json"
    /**
     * 文件夹名字吧
     */
    name: string;
    /**
     * 图集
     * 线上打包合图可能有多张，暂时发现texturePacker版本问题只有一张
     */
    atlas: string;//"name.json"
}

/**
 * 简单点，有工具的话像egret那样玩，可以自动生成图片组数据
 */
export namespace RES {
    let resData: ResData
    /**
     * 资源路径
     */
    export let resPath: string;
    /**
     * movieClip的ve数据
     */
    let videoEntityHash: {
        [name: string]: VideoEntity
    } = {};
    /**
     * 音频的加载
     */
    let soundHash: {
        [name: string]: Howl//Sound
    } = {}
    /**
     * 记录组加载完成
     */
    let groupsCompleteHash: {
        [name: string]: boolean
    } = {}
    /**
     * 记录加载的promise
     */
    let groupsPromiseHash: {
        [name: string]: Promise<any>
    } = {}
    /**
     * 单独资源加载的promise记录
     */
    let singleResPromiseHash: {
        [name: string]: Promise<any>
    } = {}
    /**
     * 
     * @param res 资源数据文件名字
     * @param path 
     */
    export function loadConfig(res: string, path?: string): Promise<any> {
        resPath = path || "../resource/"
        //加载res
        return new Promise((resolve, reject) => {
            GlobalLoader.loadJson((s, data) => {
                if (s) {
                    resData = data;
                    resolve()
                } else {
                    reject();
                }
            }, resPath + res)
        })
    }
    /**
     * 根据组名加载一组资源，通常用于加载一个视图的的所有资源
     * 里的promise的resolve并没有返回值
     * @param name 
     */
    export function loadGroup(name: string): Promise<any> {
        //已经加载完成的直接返回
        if (groupsCompleteHash[name]) {
            return new Promise((resolve) => {
                resolve()
            })
        }
        //如果是正在加载中的，返回正在加载中的promise
        if (groupsPromiseHash[name]) {
            return groupsPromiseHash[name];
        }
        //如果首次加载
        //获取资源组
        let arr = getGroupResByName(name);
        //如果不存在arr，直接返回空p，且标记完成
        if (!arr || !arr.length) {
            groupsCompleteHash[name] = true;
            return new Promise((resolve) => {
                resolve()
            })
        }
        // 建一个promise
        let p = new Promise((resolve, reject) => {
            loadResList((allLoaded: boolean) => {
                //移除
                delete groupsPromiseHash[name];
                if (allLoaded) {
                    groupsCompleteHash[name] = true;//都加载完成就标记
                    resolve()
                } else {
                    reject();
                }
            }, arr/*, resPath + name*/)
        })
        groupsPromiseHash[name] = p;
        return p;
    }
    /**
     * var textue = await RES.getResAsync(str);//考虑有资源的时候是否也要套Promise
     * 以后考虑这个方法和loadResList结合，暂时先不用这个方法，是图片，且该资源在图集里面的情况
     * @param str 可以是网络图片路径或键值
     * @param comFun 加载回调
     * @param thisObj this指向
     */
    export function getResAsync(str: string, comFun?: (res: any, str: string) => void, thisObj?: any): Promise<any> {
        // var arr = str.split(".");
        var type = str.substring(str.lastIndexOf(".") + 1, str.length);
        //如果是图片
        if (type == "png" || type == "jpg") {
            //原先就有了，加载过的，且已加载完成的
            if (TextureCache[str]) {
                //回调形式
                comFun && comFun.call(thisObj, TextureCache[str], str)
                return new Promise((r) => {
                    r(TextureCache[str])
                })
            }
            //未加载完成的
            else if (singleResPromiseHash[str]) {
                return returnSingleResPromise(str, comFun, thisObj)
            }
            else {
                //判断是否在资源里，判断是否要加载图集，注意已排除jpg
                var groupName = hasRes(str);
                if (groupName && type != "jpg") {
                    var group = getGroupByName(groupName);
                    if (group && group.atlas) {
                        //加载图集，现在就一张，以后有机会改
                        var json = group.atlas.split(",")[0];
                        //找json是否在加载中
                        if (singleResPromiseHash[json]) {
                            return singleResPromiseHash[json].then(
                                (r) => {
                                    //只返回需要的
                                    comFun && comFun.call(thisObj, TextureCache[str], str)
                                    return TextureCache[str]
                                },
                                () => {
                                    comFun && comFun.call(thisObj, null, str)
                                    return null
                                }
                            )
                        } else {
                            return getResAsync(json)
                                .then(() => {
                                    comFun && comFun.call(thisObj, TextureCache[str], str)
                                    return TextureCache[str]
                                }, () => {
                                    comFun && comFun.call(thisObj, null, str)
                                    return null
                                })
                        }
                    }
                }
                var src = groupName ? resPath + groupName + "/" + str : str;
                var p = new Promise((resolve, reject) => {
                    GlobalLoader.loadImage((s, image) => {
                        //移除
                        delete singleResPromiseHash[str];
                        //入缓存
                        if (s) {
                            Texture.addToCache(Texture.from(image), str);
                            comFun && comFun.call(thisObj, TextureCache[str], str)
                            resolve(TextureCache[str])
                        } else {
                            comFun && comFun.call(thisObj, null, str)
                            reject()
                        }
                    }, src)
                })
                singleResPromiseHash[str] = p
                return p
            }
        }
        else if (type == "svga") {
            if (videoEntityHash[str]) {
                comFun && comFun.call(thisObj, videoEntityHash[str], str)
                return new Promise((r) => {
                    r(videoEntityHash[str])
                })
            }
            //未加载完成的
            else if (singleResPromiseHash[str]) {
                return returnSingleResPromise(str, comFun, thisObj)
            } else {
                var groupName = hasRes(str);
                var src = groupName ? resPath + groupName + "/" + str : str;
                var p = new Promise((resolve, reject) => {
                    GlobalLoader.loadSvga((s, v) => {
                        //移除
                        delete singleResPromiseHash[str];
                        //入缓存
                        if (s) {
                            if (s) videoEntityHash[str] = v;
                            comFun && comFun.call(thisObj, v, str)
                            resolve(v)
                        } else {
                            comFun && comFun.call(thisObj, null, str)
                            reject()
                        }
                    }, src)
                })
                singleResPromiseHash[str] = p;
                return p
            }
        }
        //json图集的话，不晓得用啥判断加载完成，所以不删除promise吧，其实json可能只是数据，不管先
        else if (type == "json") {
            if (singleResPromiseHash[str]) {
                return returnSingleResPromise(str, comFun, thisObj)
            } else {
                var groupName = hasRes(str);
                var src = groupName ? resPath + groupName + "/" + str : str;
                var p = new Promise((resolve, reject) => {
                    GlobalLoader.loadSheet((s, data) => {
                        if (s) {
                            var t = createTextureSheet(new BaseTexture(data.img), data.json)
                            comFun && comFun.call(thisObj, t, str)
                            resolve(t)
                        } else {
                            comFun && comFun.call(thisObj, null, str)
                            reject()
                        }
                    }, src)
                })
                singleResPromiseHash[str] = p
                return p
            }
        }
        //音频格式，还可以加，
        else if (type == "mp3") {
            if (soundHash[str]) {
                comFun && comFun.call(thisObj, soundHash[str], str)
                return new Promise((r) => {
                    r(soundHash[str])
                })
            }
            //未加载完成的
            else if (singleResPromiseHash[str]) {
                return returnSingleResPromise(str, comFun, thisObj)
            } else {
                var groupName = hasRes(str);
                var src = groupName ? resPath + groupName + "/" + str : str;
                var p = new Promise((resolve, reject) => {
                    //加载让Howl处理，保证链接正确先
                    let sound = new Howl({ src: [src], preload: true });
                    soundHash[str] = sound
                    comFun && comFun.call(thisObj, soundHash[str], str)
                    resolve(soundHash[str])
                    // let sound = new useSoundClass();
                    // sound.load(src);
                    // let onSuccess = () => {
                    //     delete singleResPromiseHash[str];
                    //     soundHash[str] = sound
                    //     comFun && comFun.call(thisObj, soundHash[str], str)
                    //     resolve(soundHash[str])
                    // }
                    // let onError = () => {
                    //     delete singleResPromiseHash[str];
                    //     comFun && comFun.call(thisObj, null, str)
                    //     reject()
                    // }
                    // sound.addEventListener(Event.COMPLETE, onSuccess, this);
                    // sound.addEventListener(Event.ERROR, onError, this);
                    // GlobalLoader.loadAudio((s, data) => {
                    //     //移除
                    //     delete singleResPromiseHash[str];
                    //     if (s) {
                    //         soundHash[str] = new Sound(data)
                    //         comFun && comFun.call(thisObj, soundHash[str], str)
                    //         resolve(soundHash[str])
                    //     } else {
                    //         comFun && comFun.call(thisObj, null, str)
                    //         reject()
                    //     }
                    // }, src)
                })
                singleResPromiseHash[str] = p
                return p
            }
        }
    }

    /**
     * 待写，根据网络路径加载图片
     */
    export function getResByUrl() {

    }

    /**
     * 获取素材，
     * @param str 
     * @return 已加载好得素材或null
     */
    export function getRes(str: string)/*: Texture | VideoEntity*/ {
        var type = str.substring(str.lastIndexOf(".") + 1, str.length);
        if (type == "png" || type == "jpg") {
            return TextureCache[str] || null;
        }
        else if (type == "svga") {
            return videoEntityHash[str] || null;
        }
        else if (type == "mp3") {
            return soundHash[str] || null;
        }
    }

    /**
     * 判断是否在资源组里
     * 考虑是否init就做表
     * 有就返回组名，为了加载路径，不然以后有工具可以放入resources
     */
    function hasRes(str: string): string {
        for (var i = 0; i < resData.groups.length; i++) {
            var group = resData.groups[i];
            var keys = group.keys;
            if (keys && keys.split(",").indexOf(str) > -1) {
                return group.name;
            }
            //如果是图集的json
            if (group.atlas == str) {
                return group.name;
            }
        }
        return null
    }

    /**
     * 处理数据，获得所有资源单项
     * @param name 
     */
    function getGroupResByName(name: string) {
        var group: GroupInt = getGroupByName(name);
        if (!group) return null;
        //判断加载图集还是单图
        if (group.atlas) {
            var arr: string[] = [].concat(group.atlas.split(","));
            //再添加非图片的资源，和图集已排除jpg
            if (group.keys) {
                arr = arr.concat(group.keys.split(",").filter((k: string) => {
                    return k.substr(-4) != ".png" //&& k.substr(-4) != ".jpg"
                }))
            }
            return arr
        }
        else if (group.keys) {
            return group.keys.split(",")
        } else {
            return null
        }
    }

    /**
     * 根据名字找组
     * @param name 
     */
    function getGroupByName(name: string): GroupInt {
        var groups = resData.groups;
        var group: GroupInt;
        for (var i = 0; i < groups.length; i++) {
            if (groups[i].name === name) {
                group = groups[i];
                break;
            }
        }
        return group
    }

    /**
     * 新版的加载一列资源
     * @param callback 
     * @param arr 
     */
    function loadResList(callback: (allLoaded: boolean) => void, arr: string[]) {
        let count = 0;
        let countAll = arr.length;
        if (!countAll) callback(true);
        let mark = true
        for (var i = 0; i < countAll; i++) {
            let resName = arr[i];
            getResAsync(resName, (res) => {
                //标记失败，如果有一项资源加载失败，标记下
                if (!res) mark = false
                if (++count == countAll) callback(mark);
            }, this)
        }
    }
    /**
     * 暂不用，老版
     * @param callback 
     * @param arr 
     * @param path 
     */
    function loadResListOld(callback: Function, arr: string[], path: string) {
        let count = 0;
        let countAll = arr.length;
        if (!countAll) callback();
        for (var i = 0; i < arr.length; i++) {
            let res = arr[i];
            //取后缀类型
            var type = res.substring(res.lastIndexOf(".") + 1, res.length);
            let truePath = path + "/" + res;
            switch (type) {
                case "jpg":
                case "png":
                    GlobalLoader.loadImage((s, image) => {
                        //入缓存
                        if (s) Texture.addToCache(Texture.from(image), res)
                        //检查
                        if (++count == countAll) callback();
                    }, truePath)
                    break;
                //图集，
                case "json":
                    GlobalLoader.loadSheet((s, data) => {
                        //拆图集
                        if (s) createTextureSheet(new BaseTexture(data.img), data.json)
                        //用TextureCache[name]取
                        if (++count == countAll) callback();
                    }, truePath)
                    break;
                case "svga":
                    GlobalLoader.loadSvga((s, v: VideoEntity) => {
                        if (s) videoEntityHash[res] = v;
                        if (++count == countAll) callback();
                    }, truePath)
                    break;
                //其他比如音频啥不加载先
                case "mp3":
                    //加载让Howl处理
                    let sound = new Howl({ src: [truePath] });
                    soundHash[res] = sound;
                    if (++count == countAll) callback();
                    // let sound = new useSoundClass();
                    // sound.load(truePath);
                    // let onSuccess = () => {
                    //     soundHash[res] = sound;
                    //     if (++count == countAll) callback();
                    // }
                    // let onError = () => {
                    //     if (++count == countAll) callback();
                    // }
                    // sound.addEventListener(Event.COMPLETE, onSuccess, this);
                    // sound.addEventListener(Event.ERROR, onError, this);
                    // GlobalLoader.loadAudio((s, a: any) => {
                    //     if (s) soundHash[res] = new Sound(a);
                    //     if (++count == countAll) callback();
                    // }, truePath)
                    break;
            }
        }
    }
    /**
     * 
     * @param str 
     * @param comFun 
     * @param thisObj 
     */
    function returnSingleResPromise(str: string, comFun?: (res: any, str: string) => void, thisObj?: any) {
        //已判断是否存在
        singleResPromiseHash[str].then(
            (r) => {
                comFun && comFun.call(thisObj, r, str)
            },
            () => {
                comFun && comFun.call(thisObj, null, str)
            }
        )
        return singleResPromiseHash[str];
    }
}


