import { ObservablePoint } from './ObservablePoint';
import { Matrix } from "./Matrix";
import { HashObject } from '../HashObject';
import { cos, sin } from '../const';

/**
 * @class
 */
export default class Transform extends HashObject {
    /**
     * 世界矩阵
     */
    worldMatrix: Matrix;
    /**
     * 本地矩阵
     */
    localMatrix: Matrix;

    //约定，要更新时。父级的_worldID 和子级的_parentID不能同时设为-1；或者，只要都是-1就要更新
    /**
     * 记录子级是否更新worldMatrix，需要保证子级修改设置_worldID++
     */
    _worldID: number;
    /**
     * 记录是否和父级更新的_worldID一致，需要保证跟随父级修改设置_parentID=-1
     */
    _parentID: number;
    /**
    * 位置
    */
    position: ObservablePoint;
    /**
     * 缩放
     */
    scale: ObservablePoint;
    /**
     * 锚点
     * 不改变坐标原点
     */
    anchor: ObservablePoint;
    /**
     * 斜切值
     */
    skew: ObservablePoint;
    /**
     * 弧度制
     */
    _rotation: number;
    _cx: number;
    _sx: number;
    _cy: number;
    _sy: number;

    /**
     * 记录的本地坐标id；需要保证本地矩阵修改设置_localID++
     */
    _localID: number;
    /**
     * 当前本地坐标id
     */
    _currentLocalID: number;

    constructor() {
        super();
        let s = this;
        s._instanceType = "Transform";

        this.worldMatrix = new Matrix();

        this.localMatrix = new Matrix();

        //初始为0
        this._worldID = 0;
        this._parentID = 0;

        this.position = new ObservablePoint(this.onChange, this, 0, 0);

        this.scale = new ObservablePoint(this.onChange, this, 1, 1);

        this.anchor = new ObservablePoint(this.onChange, this, 0, 0);

        this.skew = new ObservablePoint(this.updateSkew, this, 0, 0);

        this._rotation = 0;

        this._cx = 1; // cos rotation + skewY;
        this._sx = 0; // sin rotation + skewY;
        this._cy = 0; // cos rotation + Math.PI/2 - skewX;
        this._sy = 1; // sin rotation + Math.PI/2 - skewX;

        //初始为0
        this._localID = 0;
        this._currentLocalID = 0;
    }

    /**
     * 任何属性更改
     * @private
     */
    onChange() {
        this._localID++;
    }

    /**
     * 当斜切改变时，先记录，优化计算
     * @private
     */
    updateSkew() {
        this._cx = cos(this._rotation + this.skew._y);
        this._sx = sin(this._rotation + this.skew._y);
        this._cy = -sin(this._rotation - this.skew._x); // cos, added PI/2
        this._sy = cos(this._rotation - this.skew._x); // sin, added PI/2

        this._localID++;
    }

    /**
     * 更新本地矩阵
     */
    updateLocalMatrix() {
        const lt = this.localMatrix;

        if (this._localID !== this._currentLocalID) {
            //根据基础属性计算本地矩阵
            lt.a = this._cx * this.scale._x;
            lt.b = this._sx * this.scale._x;
            lt.c = this._cy * this.scale._y;
            lt.d = this._sy * this.scale._y;

            //不改变位置原点，只改缩放和旋转中心点，+this.anchor._x
            lt.tx = this.position._x + this.anchor._x - ((this.anchor._x * lt.a) + (this.anchor._y * lt.c));
            lt.ty = this.position._y + this.anchor._y - ((this.anchor._x * lt.b) + (this.anchor._y * lt.d));
            this._currentLocalID = this._localID;

            //保证会更新世界坐标
            this._parentID = -1;
        }
    }

    /**
     * 更新世界矩阵,跟随父级修改
     * @param {Transform} parentTransform - 父级矩阵
     */
    updateWorldMatrix(parentTransform: Transform) {
        const lt = this.localMatrix;

        //先确定local是否需要更新
        if (this._localID !== this._currentLocalID) {
            //根据基础属性计算本地矩阵
            lt.a = this._cx * this.scale._x;
            lt.b = this._sx * this.scale._x;
            lt.c = this._cy * this.scale._y;
            lt.d = this._sy * this.scale._y;

            //不改变位置原点，只改缩放和旋转中心点，+this.anchor._x
            lt.tx = this.position._x + this.anchor._x - ((this.anchor._x * lt.a) + (this.anchor._y * lt.c));
            lt.ty = this.position._y + this.anchor._y - ((this.anchor._x * lt.b) + (this.anchor._y * lt.d));
            this._currentLocalID = this._localID;

            //保证会更新世界坐标
            this._parentID = -1;
        }

        //判断是否和父级更新的_worldID一致，或者都为-1(防止都设为-1的情况)去掉-1判断后TODO待测试
        if (this._parentID !== parentTransform._worldID /*|| parentTransform._worldID == -1*/) {
            // concat the parent matrix with the objects transform.
            const pt = parentTransform.worldMatrix;
            const wt = this.worldMatrix;

            wt.a = (lt.a * pt.a) + (lt.b * pt.c);
            wt.b = (lt.a * pt.b) + (lt.b * pt.d);
            wt.c = (lt.c * pt.a) + (lt.d * pt.c);
            wt.d = (lt.c * pt.b) + (lt.d * pt.d);
            wt.tx = (lt.tx * pt.a) + (lt.ty * pt.c) + pt.tx;
            wt.ty = (lt.tx * pt.b) + (lt.ty * pt.d) + pt.ty;

            // if (parentTransform._worldID == -1) {
            //     this._parentID = parentTransform._worldID = 0;
            // } else {
            //     this._parentID = parentTransform._worldID
            // }

            //修改自身worldId,保证子级会更新
            this._worldID++;
        }
    }

    /**
     * 弧度制
     *
     * @member {number}
     */
    get rotation() {
        return this._rotation;
    }

    set rotation(value) {
        if (value === this._rotation) return
        this._rotation = value;
        this.updateSkew();
    }

    destroy() {
        this.worldMatrix = null;
        this.localMatrix = null;
        this.position = null;
        this.skew = null;
        this.scale = null;
        this.anchor = null;
    }
}
