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

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

const {dirtyFieldDetector, dirtyFieldTrigger} = decorators;

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

/**
 * 矩阵转换组件
 * 缩放、旋转、位移
 */
export default class Transform extends ScillaComponent {
	onVector2DModify = (value, key, oldValue) => {
		this.makeDirty(value, key, oldValue);
	};

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

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

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

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

	/**
	 * 尺寸
	 * 对于不同的子类渲染都有不同的效果
	 */
	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 _globalPivotMatrix: Matrix = Matrix.create();
	protected dirty: boolean;

	get width(): number {
		const renderer = this.entity.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.entity.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');
		}
	}

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

		switch (key) {
			case 'width':
			case 'height':
				const renderers = this.entity.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.ROTATE_SCALE) {
			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 = entity.parent.getComponent(Transform);
			if (parentTransform) {
				this._renderAlpha = parentTransform._renderAlpha * this.alpha;
				_globalMatrix.concat(parentTransform.getMatrix(true));
			}
		}else{
			this._renderAlpha = this.alpha;
		}
		_globalPivotMatrix.copyFrom(_globalMatrix);
		_globalPivotMatrix.translate(
			-(px - 0.5) * width,
			-(py - 0.5) * height,
		);
	}

	/**
	 * 获取矩阵
	 */
	getMatrix(withPivot = false): Matrix {
		return withPivot ? this._globalPivotMatrix : this._globalMatrix;
	}

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

		this.updateGlobalMatrix();

		super.onUpdate(t);
	}
}
