/**
 * Created by rockyl on 2018/11/5.
 */

import {Vector2D, Matrix, decorators} from "scilla";
import Renderer from "../renderer/Renderer";
import ScillaComponent from "./ScillaComponent";

const {dirtyFieldDetector, dirtyFieldTrigger} = decorators;

/**
 * 矩阵处理顺序
 * SCALE_ROTATE: 先缩放后旋转
 * ROTATE_SCALE: 先旋转后缩放
 */
export enum MATRIX_ORDER {
	SCALE_ROTATE,
	ROTATE_SCALE,
}

/**
 * 矩阵转换组件
 * 缩放、旋转、位移
 */
export default class Transform extends ScillaComponent {
	protected localPos: any = {};

	onVector2DModify = (value, key, oldValue) => {
		this.makeDirty(value, key, oldValue);
	};

	/**
	 * 坐标
	 */
	@dirtyFieldTrigger
	position: Vector2D = new Vector2D(0, 0);

	/**
	 * 全局坐标
	 */
	private _globalPosition: Vector2D = new Vector2D(0, 0);

	/**
	 * 节点透明度
	 */
	@dirtyFieldTrigger
	alpha: number = 1;

	/**
	 * 节点渲染透明度
	 */
	private _renderAlpha: number;

	get renderAlpha(): number {
		return this._renderAlpha;
	}

	/**
	 * 影响子节点
	 */
	@dirtyFieldTrigger
	affectChildren: boolean = true;

	/**
	 * 尺寸
	 * 对于不同的子类渲染都有不同的效果
	 */
	private _width: number = NaN;
	private _height: number = NaN;
	/**
	 * 缩放
	 */
	@dirtyFieldTrigger
	scale: Vector2D = new Vector2D(1, 1);
	/**
	 * 轴距
	 */
	@dirtyFieldTrigger
	pivot: Vector2D = new Vector2D(0.5, 0.5);
	/**
	 * 旋转
	 */
	@dirtyFieldDetector
	rotation = 0;

	private order: MATRIX_ORDER = MATRIX_ORDER.SCALE_ROTATE;

	protected _localMatrix: Matrix = Matrix.create();
	protected _globalMatrix: Matrix = Matrix.create();
	protected _globalInvertMatrix: Matrix = Matrix.create();
	protected _globalPivotMatrix: Matrix = Matrix.create();
	protected dirty: boolean;

	get width(): number {
		const renderer = this.getComponent(Renderer);
		return renderer ? renderer.bounds.width : (isNaN(this._width) ? 0 : this._width);
	}

	get explicitWidth(): number {
		return this._width;
	}

	set width(value: number) {
		if (this._width != value) {
			this._width = value;

			this.makeDirty(value, 'width');
		}
	}

	get height(): number {
		const renderer = this.getComponent(Renderer);
		return renderer ? renderer.bounds.height : (isNaN(this._height) ? 0 : this._height);
	}

	get explicitHeight(): number {
		return this._height;
	}

	set height(value: number) {
		if (this._height != value) {
			this._height = value;

			this.makeDirty(value, 'height');
		}
	}

	/**
	 * 获取全局坐标
	 */
	get globalPosition() {
		this._globalPosition.setXY(this._globalMatrix.tx, this._globalMatrix.ty);
		return this._globalPosition;
	}

	/**
	 * 获取全局角度
	 */
	get globalRotation() {
		return this._globalMatrix.rotation * 180 / Math.PI;
	}

	/**
	 * 全局坐标转本地坐标
	 * @param position
	 */
	globalPositionToLocal(position) {
		const matrix = this.getMatrix(true, true, true);
		matrix.transformPoint(position.x, position.y, this.localPos);

		return this.localPos;
	}

	makeDirty(value, key, oldValue?) {
		this.dirty = true;

		switch (key) {
			case 'width':
			case 'height':
				const renderers = this.getComponents(Renderer);
				for (let renderer of renderers) {
					renderer.makeDirty();
				}
				break;
		}
	}

	/**
	 * @inheritDoc
	 */
	onModify(value, key, oldValue) {
		super.onModify(value, key, oldValue);

		this.makeDirty(value, key, oldValue);
		switch (key) {
			case 'position':
			case 'scale':
				//case 'size':
				value.onChange = this.onVector2DModify;
				break;
		}
	}

	/**
	 * 更新本地矩阵
	 */
	protected updateLocalMatrix() {
		const {
			position: {x, y},
			scale: {x: sx, y: sy}, rotation,
		} = this;

		const matrix = this._localMatrix;
		matrix.identity();

		if (this.order === MATRIX_ORDER.SCALE_ROTATE) {
			matrix.scale(sx, sy);
			matrix.rotate(rotation * Math.PI / 180);
		} else {
			matrix.rotate(rotation * Math.PI / 180);
			matrix.scale(sx, sy);
		}

		matrix.translate(
			x,
			y,
		);
	}

	/**
	 * 更新全局矩阵
	 */
	protected updateGlobalMatrix() {
		const {
			entity, _globalMatrix, _localMatrix, _globalPivotMatrix,
			pivot: {x: px, y: py},
			width, height,
		} = this;

		_globalMatrix.copyFrom(_localMatrix);

		if (entity.parent) {
			const parentTransform: Transform = <Transform>entity.parent.getComponent(Transform);
			if (parentTransform) {
				this._renderAlpha = parentTransform._renderAlpha * this.alpha;
				_globalMatrix.concat(parentTransform.getMatrix(true, false));
			} else {
				this._renderAlpha = this.alpha;
			}
		} else {
			this._renderAlpha = this.alpha;
		}

		if(this.entity.name === 'Miner'){
			console.log();
		}
		_globalPivotMatrix.copyFrom(_globalMatrix);
		const {a, d} = _globalMatrix;
		_globalPivotMatrix.translate(
			-(px - 0.5) * width * a,
			-(py - 0.5) * height * d,
		);
	}

	/**
	 * 获取矩阵
	 */
	getMatrix(withPivot: boolean = false, invert: boolean = false, affectChildren = false): Matrix {
		let matrix;
		if (this.affectChildren || affectChildren) {
			matrix = withPivot ? this._globalPivotMatrix : this._globalMatrix;
			if (invert) {
				const invertMatrix = this._globalInvertMatrix;
				invertMatrix.copyFrom(matrix);
				invertMatrix.invert();

				return invertMatrix;
			}
		} else {
			matrix = this.entity.parent.getComponent(Transform).getMatrix(withPivot, invert);
		}

		return matrix;
	}

	onUpdate(t) {
		if (this.dirty) {
			this.updateLocalMatrix();
			this.dirty = false;
		}

		this.updateGlobalMatrix();

		super.onUpdate(t);
	}

	onEditorUpdate(t) {
		this.onUpdate(t);
	}
}
