import MathUtil from "./MathUtil"



export default class GameUtil {
    private static globalIndex: number = 0
    public static get GIndex() { return this.globalIndex++ }

    //全局游戏的安全距离
    public static SAFE_OFFSET=cc.v2(40,40)


    public static createNode(nodeName: string, parent: cc.Node = null) {
        let node = new cc.Node(nodeName)
        if (parent) {
            node.parent = parent
        }
        else {
            cc.director.getScene().addChild(node)
        }
        return node
    }

    public static createComp<T extends cc.Component>(nodeName: string, parent: cc.Node = null, component: typeof cc.Component): T {
        let node = this.createNode(nodeName, parent)
        let comp = node.addComponent(component)
        return <T>comp
    }


    public static addComp<T extends cc.Component>(root: cc.Node, component: typeof cc.Component): T {
        let res = root.getComponent(component)
        if (!res) {
            res = root.addComponent(component)
        }
        return <T>res
    }

    //判断相交
    public static intersects(l:cc.Rect,r:cc.Rect):boolean{
        if(l.size.height<=0||l.size.width<=0||r.size.height<=0||r.size.width<=0) return false
        return l.intersects(r)
    }

    public static binarySearch(arr:number[],key:number):number{
        let lo=0,hi=arr.length-1
        while(lo<=hi){
            let mid=Math.floor(lo+(hi-lo)/2)
            if(arr[mid]>key){
                hi=mid-1
            }else if(arr[mid]<key){
                lo=mid+1
            }else{
                return mid
            }
        }
        return lo
    }

    /**
     * 将坐标限制在屏幕的安全范围内
     * 坐标轴是中心点是0,0
     * 修改pos本身
     * @param offset 向屏幕中间缩小offset距离
     * @param range 正真的屏幕范围是cc.winSzie
     */
    private static _viewRange
    public static screenSafeRange(pos:cc.Vec3,offset:cc.Vec2=this.SAFE_OFFSET,range:cc.Size=null):cc.Vec3{
        if(!GameUtil._viewRange){
            GameUtil._viewRange=cc.view.getDesignResolutionSize()
        }
        if(!range){
            range=GameUtil._viewRange
        }
        let halfH=range.height/2
        let halfW=range.width/2
        pos.x=Math.min(halfW-offset.x,pos.x)
        pos.x=Math.max(-halfW+offset.x,pos.x)
        pos.y=Math.min(halfH-offset.y,pos.y)
        pos.y=Math.max(-halfH+offset.y,pos.y)
        return pos
    }

    /** 获取屏幕中的安全点 */
    public static getScreenSafePosRnd(offset:cc.Vec2=this.SAFE_OFFSET):cc.Vec3{
        let size=cc.winSize
        let height=size.height/2-offset.y
        let width=size.width/2-offset.x
        let x=MathUtil.randIntRange(-width,width)
        let y=MathUtil.randIntRange(-height,height)
        let res=cc.v3(x,y)
        return res
    }

    public static setActive1(node:cc.Node,active:boolean){
        if(!node) return
        if(active){
            node.opacity=255
        }else{
            node.opacity=0
        }
    }

    public static setActive(node:cc.Node,active:boolean){
        if(!cc.isValid(node)) return
        node.active=active
    }

    /**
     * @param 计算对象数量
    */
    public static countObjNum(obj: Object): number {
        let n = 0
        for (let v in obj) { n++ }
        return n
    }

    public static contactStrLine(...strs: string[]): string {
        let res = ""
        for (let s of strs) {
            res.concat(s, "\r\n")
        }
        return res
    }

    //obj是否为空
    public static isEmptyObj(obj:Object):boolean{
        if(!obj) return true
        if(typeof obj == "object"){
            return JSON.stringify(obj)=="{}"
        }
        return false
    }

    /**
     * 分割ab名和资源名
     */
    public static splitResParams(str:string):{abName:string,resName:string}{
        let res=null
        if(str){
            let splits=str.split('|')
            if(splits&&splits.length>1){
                res={abName:splits[0],resName:splits[1]}
            }else{
                res={abName:splits[0],resName:""}
            }
        }
        return res
    }

    /**
     * 分割事件的参数
     * |线分割参数
     * ,号分割数组
     * {}包裹对象
     */
    public static splitEventParams(str:string):{event:string,params:any[]}{
        let splits=str.split('|')
        if(splits.length>=1){
            let res=null
            res={event:splits[0],params:null}
            if(splits.length>1){
                let p=new Array()
                for(let i=1;i<splits.length;++i){
                    this._parseParam(splits[i],p)
                }
                res.params=p
            }
            return res
        }else{
            return {event:str,params:undefined}
        }
    }

    /**
     * 组合出新的事件
     */
    public static combinationEventParams(...vals:any[]):string{
        let res=""
        for(let val of vals){
            if(typeof val == "object"){
                res+=(JSON.stringify(val)+"|")
            }else if(val instanceof Array){
                let arr=""
                for(let v of val){
                    arr+=(v+",")
                }
                res+=(arr+"|")
            }
            else{
                res+=(val+"|")
            }
        }
        return res
    }

    /**
     * ,分割出来的是数组，如果事件需要参数是数组，就需要加,在后面
    */
    private static _parseParam(param:string,res:Array<any>){
        if(param.search(',')>=0){
            let sp=param.split(',')
            let arr=new Array()
            for(let s of sp){
                this._parseParam(s,arr)
            }
            res.push(arr)
        }else if(param.search('{')>=0){
            let json=JSON.parse(param)
            res.push(json)
            return
        }
        //简单类型
        else{
            let p=Number.parseFloat(param)
            if(!isNaN(p)){
                res.push(p)
                return
            }                
            //string
            res.push(param)
            return
        }
    }

    public static isStringEmpty(str:string):boolean{
        return !str||str==""
    }


    /** 小游戏平台 */
    public static isSmallGame():boolean{
        return !cc.sys.isNative&&cc.sys.isMobile
    }

    public static createTypeFromObj<T>(json:Object,type:{new():T}):T{
        let res=new type()
        if(json){
            res=Object.assign(res,json)
        }   
        return res     
    }
}