import { GDispatcher } from "../src";


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

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

interface SkinInt {
    name: string,
    x: 0,
    y: 0,
    type: 'container' | 'text' | 'button' | 'sprite' | 'rect' | 'item',//item的不初始化进节点，只作为数据
    children?: SkinInt[],
    id?: string,
    alpha: number,
    props?: {
        source?: string,

        text: string,
        size: number,
        fillColor: string,
        textAlpha: number,

        width: number,
        height: number,

        tUp: string,
        tDown: string,
        tDisable: string
    }
}

/**
 * 简单点，有工具的话像egret那样玩，可以自动生成图片组数据
 */
export namespace RES {
    let resData: ResData
    /**
     * 资源路径
     */
    export let resPath: string;
    /**
     * RES单独缓存一下纹理，全局的FYGE缓存纹理对于多page有覆盖的问题；
     */
    let textureHash: {
        [name: string]: FYGE.Texture;
    } = {};
    /**
     * movieClip的ve数据
     */
    let videoEntityHash: {
        [name: string]: SvgaParser.VideoEntity
    } = {};
    /**
     * 音频的加载
     */
    let soundHash = {}
    /**
     * 记录组加载完成
     */
    let groupsCompleteHash: {
        [name: string]: boolean
    } = {}
    /**
     * 记录加载的promise
     */
    let groupsPromiseHash: {
        [name: string]: Promise<any>
    } = {}
    /**
     * 单独资源加载的promise记录
     */
    let singleResPromiseHash: {
        [name: string]: Promise<any>
    } = {}

    /**
     *
     * @param res 资源数据，就是对象，不考虑加载json先
     * res格式{
     * path:1111/
     * groups: [
     * {
     *
     * }
     * ];
     * }
     */
    export function loadConfig(res) {
        resData = res;
        resPath = res.path;
    }
    /**
     * 根据组名加载一组资源，通常用于加载一个视图的的所有资源
     * 里的promise的resolve并没有返回值
     * @param name
     */
    export function loadGroup(name: string): Promise<void> {
        //已经加载完成的直接返回
        if (groupsCompleteHash[name]) {//其实直接return就行
            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: Promise<void> = new Promise((resolve, reject) => {
            loadResList((s) => {
                //移除
                delete groupsPromiseHash[name];
                if (s) {
                    groupsCompleteHash[name] = true;
                    resolve()
                } else {
                    reject();
                }
            }, arr/*, resPath + name*/)
        })
        groupsPromiseHash[name] = p;
        return p;
    }
    /**
     * var textue = await RES.getResAsync(str);
     * @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") {
            //原先就有了，加载过的，且已加载完成的
            let cached = textureHash[str] || FYGE.TextureCache[str];
            if (cached) {
                //回调形式
                comFun && comFun.call(thisObj, cached, str)
                // return cached;
                return new Promise((r) => { //为了能.then
                    r(cached)
                })
            }
            //未加载完成的
            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 = groupName + ".json"//group.atlas.split(",")[0];
                        //找json是否在加载中
                        if (singleResPromiseHash[json]) {
                            return singleResPromiseHash[json].then(
                                (r) => {
                                    //正在加载中，getResAsync首次加载的回调会缓存，完成后返回需要的，
                                    let cached = textureHash[str] || FYGE.TextureCache[str]
                                    comFun && comFun.call(thisObj, cached, str)
                                    return cached;
                                },
                                () => {
                                    comFun && comFun.call(thisObj, null, str)
                                    return null
                                }
                            )
                        } else {
                            return getResAsync(json)
                                .then(() => {
                                    let cached = textureHash[str] || FYGE.TextureCache[str]
                                    comFun && comFun.call(thisObj, cached, str)
                                    return cached
                                }, () => {
                                    comFun && comFun.call(thisObj, null, str)
                                    return null
                                })
                        }
                    }
                }
                var src = groupName ? resPath + groupName + "/" + str : str;
                var p = new Promise((resolve, reject) => {
                    FYGE.GlobalLoader.loadImage((s, image) => {
                        //移除
                        delete singleResPromiseHash[str];
                        //入缓存
                        if (s) {
                            let cached = FYGE.Texture.from(image);
                            //入RES,
                            textureHash[str] = cached;
                            //入全局
                            FYGE.Texture.addToCache(cached, str);
                            comFun && comFun.call(thisObj, cached, str)
                            resolve(cached)
                        } 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) => {
                    SvgaParser.loadSvga(
                        src,
                        (v) => {
                            delete singleResPromiseHash[str];
                            videoEntityHash[str] = v;
                            comFun && comFun.call(thisObj, v, str)
                            resolve(v)
                        },
                        (err) => {
                            delete singleResPromiseHash[str];
                            comFun && comFun.call(thisObj, null, str)
                            reject(err)
                        }
                    )
                })
                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);//json现在肯定在内，暂时不能加载其他域名的json
                var src = groupName ? resPath + groupName + "/" + str : str;
                var p = new Promise((resolve, reject) => {
                    var jsonData = getGroupByName(groupName).atlas
                    FYGE.GlobalLoader.loadImage((s, data) => {
                        if (s) {
                            //createTextureSheet会自行缓存全局
                            var t = FYGE.createTextureSheet(new FYGE.BaseTexture(data/*.img*/), jsonData)
                            //缓存进RES
                            for (let key in t) textureHash[key] = t[key];
                            comFun && comFun.call(thisObj, t, str)
                            resolve(t)
                        } else {
                            //加载失败，移除要，否则再次触发加载会出问题
                            delete singleResPromiseHash[str];
                            comFun && comFun.call(thisObj, null, str)
                            reject()
                        }
                    }, src.replace("json", "png"))
                })
                singleResPromiseHash[str] = p
                return p
            }
        }
    }

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

    }

    /**
     * 获取素材，
     * @param str
     * @return 已加载好得素材或null
     */
    export function getRes(str: string)/*: Texture | VideoEntity*/ {
        if (!str) return null;
        var type = str.substring(str.lastIndexOf(".") + 1, str.length);
        if (type == "png" || type == "jpg") {
            return textureHash[str] || FYGE.TextureCache[str] || null;
        }
        else if (type == "svga") {
            return videoEntityHash[str] || null;
        }
        else if (type == "mp3") {
            return soundHash[str] || null;
        }
    }
    /**
     * 偷懒的方法，加载配置里所有的资源，基本也不用
     */
    export function loadAllGroup() {
        var groups = resData.groups;
        var p = []
        groups.forEach((g) => {
            p.push(loadGroup(g.name))
        })
        return Promise.all(p)
    }

    /***乱改 */
    export function loadAllGroupForProgress() {
        return new Promise(r => {
            var groups = resData.groups;
            let index = 0
            groups.forEach(async (g) => {
                await loadGroup(g.name)
                index++
                GDispatcher.dispatchEvent("loadPer", index / (groups.length - 1))
                if (index == groups.length - 1) {
                    r(0)
                }
            })

        })
    }

    /**
     * 判断是否在资源组里
     * 考虑是否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,altas现在是图集
            if (group.atlas && group.name + ".json" == 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(","));
            var arr = [name + ".json"]
            //再添加非图片的资源，和图集已排除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, str) => {
                //标记失败，如果有一项资源加载失败，标记下
                if (!res) mark = false
                if (++count == countAll) callback(mark);
            }, this)
        }
    }

    /**
     *
     * @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];
    }

    //皮肤相关的也放在RES吧
    let skinData: SkinInt
    /**
     * 添加皮肤配置文件
     */
    export function loadSkinConfig(skinJson) {
        skinData = skinJson;
    }
    /**
     * 根据
     * @param con 添加显示对象的容器
     * @param skin 皮肤名字或数据
     * @param root 根容器，为了添加自定义引用
     */
    export function initSkinDisplay(con: FYGE.Container, skin: string | SkinInt, root?: FYGE.Container) {
        //@ts-ignore
        var data: SkinInt = typeof (skin) == 'string' ? getSkinDataByName(skin) : skin;
        if (!data.children || !data.children.length) return;
        // for (var i = data.children.length - 1; i >= 0; i--) {
        for (var i = 0; i < data.children.length; i++) {
            var child = data.children[i];
            if (child.type == "item") continue;
            var dis = con.addChild(getDisplayByData(child));
            if (root && child.id) root[child.id] = dis;
            if (child.type == "container") initSkinDisplay(dis, child, root);
        }
    }
    /**
     * 遍历根据名字找节点数据，只会是container的
     * @param skinName
     */
    export function getSkinDataByName(skinName: string, skinNode: SkinInt = skinData): SkinInt {
        if (!skinNode || !skinNode.children || !skinNode.children.length) return null;
        for (var i = 0; i < skinNode.children.length; i++) {
            var child = skinNode.children[i];
            if (child.name == skinName && (child.type == "container" || child.type == "item")) return child;
            var gson = getSkinDataByName(skinName, child);
            if (gson) return gson
        }
        return null;
    }


    /**
     * 通过数据创建显示对象
     * @param data
     */
    function getDisplayByData(data: SkinInt): FYGE.Container {
        var dis: FYGE.Container;
        switch (data.type) {
            case "container":
                dis = new FYGE.Container();
                break;
            case "button":
                dis = new FYGE.Button(
                    getRes(data.props.tUp),
                    data.props.tDown ? getRes(data.props.tDown) : null,
                    data.props.tDisable ? getRes(data.props.tDisable) : null,
                );
                break;
            case "text":
                dis = new FYGE.TextField();
                for (let key in data.props) dis[key] = data.props[key];
                break;
            case "sprite":
                dis = new FYGE.Sprite(getRes(data.props.source));
                break;
            case "rect":
                // dis = new FYGE.Graphics()
                //     .beginFill(data.props.fillColor)
                //     .drawRect(0, 0, data.props.width, data.props.height)
                //     .endFill();
                dis = new FYGE.Shape()
                //@ts-ignore
                dis.beginFill(FYGE.string2hex(data.props.fillColor))
                //@ts-ignore
                dis.drawRect(0, 0, data.props.width, data.props.height)
                //@ts-ignore
                dis.endFill();
                break;
        }
        dis.name = data.name;
        dis.alpha = data.alpha || 1;
        dis.position.set(data.x, data.y);
        // if (data.type == "text") dis.y -= 4;//文本莫名偏下，移动下，手机调试的时候也试试
        return dis;
    }

    /**
     * 销毁组纹理
     * 线上才有用，待测试，TODO
     * @param name
     */
    export function destroyGroup(name: string) {
        var group: GroupInt = getGroupByName(name);
        if (!group) return;
        var arr = [];
        if (group.keys) {
            arr = group.keys.split(",")
        }
        var removedBase = [];
        //散图清除
        for (var i = 0; i < arr.length; i++) {
            var t: FYGE.Texture = getRes(arr[i]);
            if (t) {
                //base的清除，不要重复清除
                if (removedBase.indexOf(t.baseTexture) == -1) {
                    t.baseTexture.destroy();
                    removedBase.push(t.baseTexture)
                }
                //自己纹理清除
                t.destroy();
            }
            //RES里单独缓存的清除
            delete textureHash[arr[i]]
        }
    }

    //貌似不需要，为了加载过一次的资源不用重新加载
    function destroyRES() {

    }
}


