
const charLimit=1000
const MONEY_SUFFIX=["k","m","b","t","aa","bb","cc","dd","ee","ff","gg","hh","ii","jj","kk","ll","mm","nn","oo","pp","qq","rr","ss","tt","uu","vv","ww","xx","yy","zz"]

const NumStrs = ['0','1','2','3','4','5','6','7','8','9']

export enum SortType{
    Asc=0,
    Desc=1,
}

export default class MathUtil {

    //i=mv 冲量
    //使用冲量表示，无论质量多少（质量大就乘以大小就乘上小的），都一定要达到速度vel
    public static impulseSelf(vel:cc.Vec2,mass:number){
        return vel.mulSelf(mass)
    }

    /**
    * @param 0-0.999999
    */
    private static rnd(seed) {
        seed = (seed * 9301 + 49297) % 233280
        return seed / (233280.0)
    }

    /**
     * @param 随机数，线性同余，比Math.random靠谱，它概率都不一样
     * 半开半闭区间[)
    */
    public static randInt(n: number): number {
        let today = new Date()
        let seed = today.getTime()
        seed = Math.random() * seed
        let rnd = this.rnd(seed)
        let res = Math.floor(rnd * n)
        return res
    }

    /**生成bit位随机数*/
    public static numArrRnd(bit:number=16):string{
        let str=""
        for (let i=0; i<bit;i++) {
            const pos = Math.round(Math.random() * (NumStrs.length-1))
            str += NumStrs [pos]
        }
        return str
    }

    /**
     * @param 返回[0,1)之间的值
    */
    public static rand(): number {
        let today = new Date()
        let seed = today.getTime() //用时间同一帧调用的值一样
        seed = Math.random() * seed
        let res = this.rnd(seed)
        return res
    }

    public static randRange(left:number,right:number):number{
        let min=Math.min(left,right)
        let max=Math.max(left,right)
        return MathUtil.rand()*(max-min)+min
    }

    /**
     * @param [left,right)
    */
    public static randIntRange(left: number, right: number): number {
        if(left==right) return left
        if (left < 0) {
            let nl = this.randInt(left)
            let nr = this.randInt(right)
            if (this.randInt(2) == 1) {
                return nl
            } else {
                return nr
            }
        } else {
            let n = this.randInt(right) //[0,right)  25
            let res = Math.floor(left + (right - 1 - left) / (right - 1) * n)
            return res
        }
    }

    //洗牌算法
    public static shuffleSelf(input:Array<any>) {
        const length = input?.length??0
        if(length<=1) return input
        let index:number=0
        // 执行length-1次即可，i=0时替换的是自身，这么做没有意义
        for (let i = length - 1; i; i --){
            // 选取0到i-1中的一个位置
            index = Math.floor(this.rand() * i)
            // 与i位置的值互换
            input[i] = input.splice(index, 1, input[i])[0]
        }
        return input
    }

    //洗牌算法[耗时比较长]
    // public static shuffle1(arr:Array<any>){
    //     return arr&&arr.sort((a,b)=>this.rand()-0.5)
    // }

    /**
     * 
     * @param arr  待排序数组
     * @param type 升序还是降序
     * @param funsKey 用来排序的返回number的函数名字
     * @returns 
     */
    public static sort(arr:Array<any>,type:SortType,...funsKey:string[]){
        return arr.sort((a,b)=>{
            for(let i=0;i<funsKey.length;++i){
                let funKey=funsKey[i]
                let resA=a[funKey]()
                let resB=b[funKey]()
                if(resA==resB){
                    if(i<funsKey.length-1){
                        continue
                    }else{
                        return 0
                    }
                }else{
                    if(type==SortType.Asc){
                        return resA-resB
                    }else{
                        return resB-resA
                    }
                }
            }
        })
    }

    /**
     * 计算两个向量的夹角，返回0-360
     * 
	 * 	dot = x1*x2 + y1*y2      # dot product
		det = x1*y2 - y1*x2      # determinant 行列式
		angle = atan2(det, dot)  # atan2(y, x) or atan2(sin, cos)
     * @param v1 
     * @param v2 
     * 
     * 以0,-1向量为起点,顺时针0-360
     */
    public static countAngleV2(v1:cc.Vec2,v2:cc.Vec2):number{
		let dot=v2.dot(v1)
		let det=v2.x*v1.y-v2.y*v1.x
        let angle=180*Math.atan2(det,dot)/Math.PI
        if(angle<0){
			angle+=360
        }
        return angle
    }

    /**
     * 计算向量的夹角
     * 不管z坐标
     */
    public static countAngleV3(v1:cc.Vec3,v2:cc.Vec3):number{
        return this.countAngleV2(cc.v2(v1),cc.v2(v2))
    }


    /**
     * @param 格式化数值
    */
     public static numericalFormat(val: number): string {
        let res="0",index=-1
        if(val>=Number.MAX_VALUE) return "unlimit"
        if(val<=9999) return val.toFixed(0)
        if(val>charLimit){
            while(val>charLimit){
                val/=charLimit
                ++index
            }
            if(MONEY_SUFFIX[index]==undefined){
                res="unlimit"
            }else{
                res=val.toFixed(0)+MONEY_SUFFIX[index]
            }
        }else{
            res=val.toFixed(0)
        }
        return res
    }

    //三个数选中间数
    public static between(a, b, c):number {
        return [a, b, c].sort((a, b) => {
            return a - b;
        })[1];
    }
    
    //两点间距离
    public static distance(x1, y1, x2, y2) {
        let dx = x1 - x2;
        let dy = y1 - y2;
        return Math.sqrt(dx * dx + dy * dy);
    }
}