import { Container, Sprite } from "../2d/display";
import { Texture } from "../2d/texture";
import { RAD_TO_DEG, DEG_TO_RAD } from "../2d/const";
import { Graphics } from "../2d/graphics";
import { HashObject } from "../2d/HashObject";
import { Matrix } from "../2d/math";

/**
 * 仿照three，用节点模拟，然后取全局矩阵，再赋值给显示对象
 */
export class Bone extends Container/*Container*/ {//为了测试用sprite
    static yDown: boolean = true;//当前引擎y轴朝下
    //a开头都是用于约束的，再说
    public ax = 0;
    public ay = 0;
    public arotation = 0;
    public ascaleX = 0;
    public ascaleY = 0;
    public ashearX = 0;
    public ashearY = 0;
    public appliedValid = false;
    public sorted = false;

    get matrix() {
        return this.worldMatrix
    }
    //不能用skew，因为是反的
    public shearX = 0;
    public shearY = 0;

    private debugBone: Graphics
    constructor(public data: IBoneData, public root: Container) {
        super();
        this._instanceType = "Bone";
        this.name = data.name;
        //考虑要不要处理下data
        this.data.x = this.data.x || 0
        this.data.y = this.data.y || 0
        this.data.scaleX = this.data.scaleX || 1
        this.data.scaleY = this.data.scaleY || 1
        this.data.rotation = this.data.rotation || 0
        this.data.shearX = this.data.shearX || 0
        this.data.shearY = this.data.shearY || 0

        this.setToSetupPose();
        //到时去掉
        if (root) {
            this.debugBone = this.addChild(new Graphics())
                .beginFill(0xff0000)
                .drawRect(0, 0, data.length || 10, 10)
                .endFill();
        }

    }
    setToSetupPose() {
        var data = this.data;
        this.x = data.x;
        this.y = data.y;
        this.rotation = data.rotation;
        this.scaleX = data.scaleX;
        this.scaleY = data.scaleY;
        this.shearX = data.shearX;
        this.shearY = data.shearY;
        //skew是反的
        this.skewX = -data.shearY;
        this.skewY = data.shearX;
    };
    //方式要改
    updateTransform() {
        this.appliedSelf();

        var sy = Bone.yDown ? -1 : 1;
        if (this.parent) {
            var parent = this.parent
            if (this.parent.instanceType == "Bone") {
                // this.transform.updateLocalMatrix();//自己计算
                this.transform._worldID++;
                var pm = parent.transform.worldMatrix;
                var lm = this.localMatrix;
                var wm = this.worldMatrix;
                //pc和pb写错了，再说
                var pa = pm.a, pb = pm.c, pc = pm.b, pd = pm.d;
                wm.tx = pa * this.x + pb * this.y + pm.tx;
                wm.ty = pc * this.x + pd * this.y + pm.ty;
                //自身计算方式要根据data.transform
                switch (this.data.transform) {
                    case TransformType.onlyTranslation://其他统统用lm的
                        this.transform.updateLocalMatrix();
                        wm.a = lm.a;
                        wm.c = lm.c;
                        wm.b = lm.b;
                        wm.d = lm.d;
                        break;
                    case TransformType.noRotationOrReflection: {
                        var s = pa * pa + pc * pc;
                        var prx = 0;
                        if (s > 0.0001) {
                            s = Math.abs(pa * pd - pb * pc) / s;
                            pb = pc * s;
                            pd = pa * s;
                            prx = Math.atan2(pc, pa) * RAD_TO_DEG;
                        }
                        else {
                            pa = 0;
                            pc = 0;
                            prx = 90 - Math.atan2(pd, pb) * RAD_TO_DEG;
                        }
                        var rx = this.rotation + this.shearX - prx;
                        var ry = this.rotation + this.shearY - prx + 90;
                        var la = Math.cos(rx * DEG_TO_RAD) * this.scaleX;
                        var lb = Math.cos(ry * DEG_TO_RAD) * this.scaleY * sy;//*sy反向，其他几种情况，遇到了再说
                        var lc = Math.sin(rx * DEG_TO_RAD) * this.scaleX;
                        var ld = Math.sin(ry * DEG_TO_RAD) * this.scaleY * sy;
                        wm.a = pa * la - pb * lc;
                        wm.c = pa * lb - pb * ld;
                        wm.b = pc * la + pd * lc;
                        wm.d = pc * lb + pd * ld;
                        break;
                    }
                    case TransformType.noScale:
                    case TransformType.noScaleOrReflection: {
                        var cos = Math.cos(this.rotation * DEG_TO_RAD);
                        var sin = Math.sin(this.rotation * DEG_TO_RAD);
                        var za = (pa * cos + pb * sin) / 1//sx;
                        var zc = (pc * cos + pd * sin) / 1//sy;
                        var s = Math.sqrt(za * za + zc * zc);
                        if (s > 0.00001)
                            s = 1 / s;
                        za *= s;
                        zc *= s;
                        s = Math.sqrt(za * za + zc * zc);
                        if (this.data.transform == TransformType.noScale
                            && (pa * pd - pb * pc < 0) != (Bone.yDown ?
                                // (this.skeleton.scaleX < 0 != this.skeleton.scaleY > 0) :
                                // (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)))
                                (1 < 0 != -1 > 0) :
                                (1 < 0 != -1 < 0)))//先直接设置了
                            s = -s;
                        var r = Math.PI / 2 + Math.atan2(zc, za);
                        var zb = Math.cos(r) * s;
                        var zd = Math.sin(r) * s;
                        var la = Math.cos(this.shearX * DEG_TO_RAD) * this.scaleX;
                        var lb = Math.cos((90 + this.shearY) * DEG_TO_RAD) * this.scaleY;
                        var lc = Math.sin(this.shearX * DEG_TO_RAD) * this.scaleX;
                        var ld = Math.sin((90 + this.shearY) * DEG_TO_RAD) * this.scaleY;
                        wm.a = za * la + zb * lc;
                        wm.c = za * lb + zb * ld;
                        wm.b = zc * la + zd * lc;
                        wm.d = zc * lb + zd * ld;
                        break;
                    }
                    case TransformType.normal:
                    default:
                        // super.updateTransform();
                        // this.transform.updateWorldMatrix(this.parent.transform);
                        this.displayObjectUpdateTransform();
                        //下面这个官网的
                        // var rotation = this.rotation
                        // var rotationY = rotation + 90 + this.shearY;
                        // var la = Math.cos((rotation + this.shearX) * DEG_TO_RAD) * this.scaleX;
                        // var lb = Math.cos(rotationY * DEG_TO_RAD) * this.scaleY;
                        // var lc = Math.sin((rotation + this.shearX) * DEG_TO_RAD) * this.scaleX;
                        // var ld = Math.sin(rotationY * DEG_TO_RAD) * this.scaleY;
                        // wm.a = pa * la + pb * lc;
                        // wm.c = pa * lb + pb * ld;
                        // wm.b = pc * la + pd * lc;
                        // wm.d = pc * lb + pd * ld;
                        break;
                }
            } else {
                // super.updateTransform();
                //不能根据父级的来玩，把自己当作root
                let temp = this.parent;
                //@ts-ignore
                this.parent = this._tempDisplayObjectParent;
                this.transform.updateWorldMatrix(this.parent.transform);
                this.parent = temp;
            }
        }

        //子级
        for (let i = 0, j = this.children.length; i < j; ++i) {
            const child = this.children[i];
            child.updateTransform();
            if (child == this.debugBone) {
                //还需要root转一次
                child.worldMatrix.prepend(this.root.worldMatrix)
            }
        }
    }
    /**
     * 是parent的需要进行子级的递归，因为子级的在后执行
     * 这些都是最后执行的，直接修改自己的世界矩阵数据
     * @param x 
     * @param y 
     * @param rotation 
     * @param scaleX 
     * @param scaleY 
     * @param shearX 
     * @param shearY 
     */
    updateWorldTransformWith(x: number, y: number, rotation: number, scaleX: number, scaleY: number, shearX: number, shearY: number) {
        this.ax = this.x = x;
        this.ay = this.y = y;
        this.arotation = this.rotation = rotation;
        this.ascaleX = this.scaleX = scaleX;
        this.ascaleY = this.scaleY = scaleY;
        this.ashearX = shearX;
        this.ashearY = shearY;
        this.appliedValid = true;
        //反的
        this.skewX = -shearY;
        this.skewY = shearX;
        //继续执行一边
        this.updateTransform();
    }

    private appliedSelf() {
        this.ax = this.x;
        this.ay = this.y;
        this.arotation = this.rotation;
        this.ascaleX = this.scaleX;
        this.ascaleY = this.scaleY;
        this.ashearX = this.shearX//this.skewX;
        this.ashearY = this.shearY//this.skewY;
        this.appliedValid = true;
    }
}

//用官网的吧，后续好扩展，比如ik啥的，用引擎的不好弄了
// export class Bone extends HashObject {
//     destroy() { }
//     static yDown: boolean = true;//当前引擎y轴朝下
//     public name: string;
//     public matrix = new Matrix();
//     public children:Bone[] = new Array();
//     //常规属性
//     public x = 0;
//     public y = 0;
//     public rotation = 0;
//     public scaleX = 0;
//     public scaleY = 0;
//     public shearX = 0;
//     public shearY = 0;
//     //a开头都是用于约束的，再说
//     public ax = 0;
//     public ay = 0;
//     public arotation = 0;
//     public ascaleX = 0;
//     public ascaleY = 0;
//     public ashearX = 0;
//     public ashearY = 0;
//     public appliedValid = false;
//     //标记未排序
//     public sorted = false;

//     //兼容下skew
//     public get skewX() {
//         return this.shearX
//     }
//     public set skewX(v) {
//         this.shearX = v;
//     }
//     public get skewY() {
//         return this.shearY
//     }
//     public set skewY(v) {
//         this.shearY = v;
//     }


//     constructor(public data: IBoneData, public parent?: Bone) {
//         super();
//         this._instanceType = "Bone";
//         this.name = data.name;
//         //考虑要不要处理下data
//         this.data.x = this.data.x || 0
//         this.data.y = this.data.y || 0
//         this.data.scaleX = this.data.scaleX || 1
//         this.data.scaleY = this.data.scaleY || 1
//         this.data.rotation = this.data.rotation || 0
//         this.data.shearX = this.data.shearX || 0
//         this.data.shearY = this.data.shearY || 0

//         //重置一次
//         this.setToSetupPose();
//     }
//     setToSetupPose() {
//         var data = this.data;
//         this.x = data.x;
//         this.y = data.y;
//         this.rotation = data.rotation;
//         this.scaleX = data.scaleX;
//         this.scaleY = data.scaleY;
//         this.shearX = data.shearX;
//         this.shearY = data.shearY;
//     };

//     get worldX() {
//         return this.matrix.tx;
//     }
//     get worldY() {
//         return this.matrix.ty;
//     }
//     update() {
//         this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY);
//     };
//     updateWorldTransform() {
//         this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY);
//     };
//     updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY) {
//         this.ax = x;
//         this.ay = y;
//         this.arotation = rotation;
//         this.ascaleX = scaleX;
//         this.ascaleY = scaleY;
//         this.ashearX = shearX;
//         this.ashearY = shearY;
//         this.appliedValid = true;
//         var parent = this.parent;
//         var m = this.matrix;
//         var sx = 1//this.skeleton.scaleX;
//         var sy = -1//Bone.yDown ? -this.skeleton.scaleY : this.skeleton.scaleY;
//         if (!parent) {
//             if (Bone.yDown) {
//                 rotation = -rotation;
//                 this.arotation = rotation;
//             }
//             //var skeleton = this.skeleton;
//             var rotationY = rotation + 90 + shearY;
//             m.a = Math.cos((rotation + shearX) * DEG_TO_RAD) * scaleX * sx;
//             m.c = Math.cos((rotationY) * DEG_TO_RAD) * scaleY * sy;
//             m.b = Math.sin((rotation + shearX) * DEG_TO_RAD) * scaleX * sx;
//             m.d = Math.sin((rotationY) * DEG_TO_RAD) * scaleY * sy;
//             m.tx = x * sx //+ skeleton.x;
//             m.ty = y * sy //+ skeleton.y;
//             return;
//         }
//         var pa = parent.matrix.a, pb = parent.matrix.c, pc = parent.matrix.b, pd = parent.matrix.d;
//         m.tx = pa * x + pb * y + parent.matrix.tx;
//         m.ty = pc * x + pd * y + parent.matrix.ty;
//         switch (this.data.transform) {
//             case TransformType.normal: {
//                 var rotationY = rotation + 90 + shearY;
//                 var la = Math.cos((rotation + shearX) * DEG_TO_RAD) * scaleX;
//                 var lb = Math.cos((rotationY) * DEG_TO_RAD) * scaleY;
//                 var lc = Math.sin((rotation + shearX) * DEG_TO_RAD) * scaleX;
//                 var ld = Math.sin((rotationY) * DEG_TO_RAD) * scaleY;
//                 m.a = pa * la + pb * lc;
//                 m.c = pa * lb + pb * ld;
//                 m.b = pc * la + pd * lc;
//                 m.d = pc * lb + pd * ld;
//                 return;
//             }
//             case TransformType.onlyTranslation: {
//                 var rotationY = rotation + 90 + shearY;
//                 m.a = Math.cos((rotation + shearX) * DEG_TO_RAD) * scaleX;
//                 m.c = Math.cos((rotationY) * DEG_TO_RAD) * scaleY;
//                 m.b = Math.sin((rotation + shearX) * DEG_TO_RAD) * scaleX;
//                 m.d = Math.sin((rotationY) * DEG_TO_RAD) * scaleY;
//                 break;
//             }
//             case TransformType.noRotationOrReflection: {
//                 var s = pa * pa + pc * pc;
//                 var prx = 0;
//                 if (s > 0.0001) {
//                     s = Math.abs(pa * pd - pb * pc) / s;
//                     pb = pc * s;
//                     pd = pa * s;
//                     prx = Math.atan2(pc, pa) * RAD_TO_DEG;
//                 }
//                 else {
//                     pa = 0;
//                     pc = 0;
//                     prx = 90 - Math.atan2(pd, pb) * RAD_TO_DEG;
//                 }
//                 var rx = rotation + shearX - prx;
//                 var ry = rotation + shearY - prx + 90;
//                 var la = Math.cos(rx * DEG_TO_RAD) * scaleX;
//                 var lb = Math.cos(ry * DEG_TO_RAD) * scaleY;
//                 var lc = Math.sin(rx * DEG_TO_RAD) * scaleX;
//                 var ld = Math.sin(ry * DEG_TO_RAD) * scaleY;
//                 m.a = pa * la - pb * lc;
//                 m.c = pa * lb - pb * ld;
//                 m.b = pc * la + pd * lc;
//                 m.d = pc * lb + pd * ld;
//                 break;
//             }
//             case TransformType.noScale:
//             case TransformType.noScaleOrReflection: {
//                 var cos = Math.cos(rotation * DEG_TO_RAD);
//                 var sin = Math.sin(rotation * DEG_TO_RAD);
//                 var za = (pa * cos + pb * sin) / sx;
//                 var zc = (pc * cos + pd * sin) / sy;
//                 var s = Math.sqrt(za * za + zc * zc);
//                 if (s > 0.00001)
//                     s = 1 / s;
//                 za *= s;
//                 zc *= s;
//                 s = Math.sqrt(za * za + zc * zc);
//                 if (this.data.transform == TransformType.noScale
//                     && (pa * pd - pb * pc < 0) != (Bone.yDown ?
//                         // (this.skeleton.scaleX < 0 != this.skeleton.scaleY > 0) :
//                         // (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)))
//                         (1 < 0 != 1 > 0) :
//                         (1 < 0 != 1 < 0)))
//                     s = -s;
//                 var r = Math.PI / 2 + Math.atan2(zc, za);
//                 var zb = Math.cos(r) * s;
//                 var zd = Math.sin(r) * s;
//                 var la = Math.cos((shearX) * DEG_TO_RAD) * scaleX;
//                 var lb = Math.cos((90 + shearY) * DEG_TO_RAD) * scaleY;
//                 var lc = Math.sin((shearX) * DEG_TO_RAD) * scaleX;
//                 var ld = Math.sin((90 + shearY) * DEG_TO_RAD) * scaleY;
//                 m.a = za * la + zb * lc;
//                 m.c = za * lb + zb * ld;
//                 m.b = zc * la + zd * lc;
//                 m.d = zc * lb + zd * ld;
//                 break;
//             }
//         }
//         m.a *= sx;
//         m.c *= sx;
//         m.b *= sy;
//         m.d *= sy;
//     };
// }

export interface IBoneData {
    length: number
    name: string
    parent: string
    rotation: number
    x: number
    y: number
    scaleX: number//默认1
    scaleY: number//默认1
    shearX: number//默认0
    shearY: number//默认0
    transform: TransformType //跟随父级的变换类型
    skin: boolean,//基本是false。不然有skin时才有效
}

export enum TransformType {
    // normal = 0,//默认
    // onlyTranslation,
    // noRotationOrReflection,
    // noScale,
    // noScaleOrReflection,
    normal = "normal",//默认
    onlyTranslation = "onlyTranslation",
    noRotationOrReflection = "noRotationOrReflection",
    noScale = "noScale",
    noScaleOrReflection = "noScaleOrReflection",
}