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

import {createCanvas, getContext, ScillaComponent, Bounds, Vector2D, math, decorators, EngineConfig} from "scilla";

const {dirtyFieldTrigger} = decorators;

/**
 * 渲染组件基类
 */
export default class Renderer extends ScillaComponent {
	protected onVector2DModify = () => {
		this.makeDirty();
	};

	private _debugDrawColor: string;

	protected dirty: boolean = true;

	/**
	 * 是否使用缓存模式
	 */
	protected _useCacheMode: boolean = false;

	/**
	 * 透明度
	 */
	alpha: number = 1;

	//锚点：在各子render里面加，从绘制上改，将同时更改位置原点，旋转原点，缩放原点,以0到1比例形式（现用此方案）
	//在该render上改transform；更改旋转和缩放原点，不改变位置原点，默认中心为位置原点，以真实数值形式
	@dirtyFieldTrigger
	anchor: Vector2D = new Vector2D(0.5, 0.5);

	/**
	 * 边界
	 */
	protected bounds = new Bounds();

	protected cacheCanvas = null;

	/**
	 * 缓存用的渲染上下文
	 */
	protected cacheCanvasContext;

	/**
	 * 锚点实际偏移
	 */
	protected _anchorOffset: Vector2D = new Vector2D();

	//渲染上下文
	protected _context = getContext();

	/**
	 * 扩展尺寸
	 */
	protected _margin: number = 0;

	get useCacheMode() {
		return this.getUseCacheMode();
	}

	set useCacheMode(value) {
		this._useCacheMode = value;
	}

	constructor(){
		super();

		this._debugDrawColor = `hsl(${math.makeRandomInt(360)}, ${math.makeRandomInt(100)}%, 60%)`;
	}

	protected getUseCacheMode() {
		return this._useCacheMode;
	}

	/**
	 * 获取渲染上下文
	 * 如果缓存上下文存在，则返回缓存上下文
	 */
	get context() {
		return this.cacheCanvasContext || this._context;
	}

	makeDirty() {
		this.dirty = true;
	}

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

		this.makeDirty();
		switch (key) {
			case 'anchor':
				value.onChange = this.onVector2DModify;
				break;
		}
	}

	onAwake() {
		super.onAwake();

		if (!this.transform) {
			console.warn('renderer need a transform component');
		}
	}

	/**
	 * @inheritDoc
	 */
	onUpdate(t) {
		if (this.dirty) {
			if(this.entity.name == 'label_status'){
				console.log();
			}
			if (this.useCacheMode) {
				this.readyCacheCanvas();
			}
			this.measureBounds();
			if (this.useCacheMode) {
				this.updateCacheCanvas();
			}
		}
		this.transformToLocal();
		this.render();

		if (EngineConfig.drawRenderRect) {
			const {_context, _debugDrawColor, bounds: {width, height}, _anchorOffset: {x, y}, transform: {pivot: {x: px, y: py}}} = this;
			_context.globalAlpha = 0.9;
			_context.strokeStyle = _debugDrawColor;
			_context.fillStyle = _debugDrawColor;
			_context.beginPath();
			_context.rect(0, 0, width, height);
			_context.stroke();
			_context.beginPath();
			_context.arc(width * px, height * py, 3, 0, 2 * Math.PI);
			_context.fill();
		}
	}

	/**
	 * 准备缓存渲染上下文
	 */
	protected readyCacheCanvas() {
		let canvas = this.cacheCanvas;
		if (!canvas) {
			canvas = this.cacheCanvas = createCanvas();
			this.cacheCanvasContext = canvas.getContext('2d');
		}
	}

	/**
	 * 更新缓存属性
	 */
	protected updateCacheCanvas() {
		let canvas = this.cacheCanvas;

		const {width, height} = this.bounds;
		canvas.width = width + this._margin * 2;
		canvas.height = height + this._margin * 2;
	}

	/**
	 * 渲染过程
	 */
	protected render() {
		this.beforeDraw();
		this.drawClip();

		if (this.dirty) {
			if(this.useCacheMode){
				this.draw();
			}
			this.dirty = false;
		}

		if (this.useCacheMode) {
			this.drawCache();
		} else {
			this.draw();
		}
	}

	/**
	 * 画之前
	 */
	protected beforeDraw() {
		this.applyAlpha();
	}

	/**
	 * 执行矩阵转换
	 */
	protected transformToLocal() {
		const {transform, _anchorOffset: {x: ax, y: ay}} = this;

		if (transform && transform.enabled) {
			const {a, b, c, d, tx, ty} = transform.getMatrix(true);
			const offX = ax * a + ay * c;
			const offY = ax * b + ay * d;
			this._context.setTransform(a, b, c, d, tx - offX, ty - offY);
		} else {
			this._context.setTransform(1, 0, 0, 1, -ax, -ay);
		}
	}

	/**
	 * 应用透明度
	 */
	protected applyAlpha() {
		this._context.globalAlpha = this.alpha * this.transform.renderAlpha;
	}

	/**
	 * 绘制缓存
	 */
	protected drawCache() {
		if (this.cacheCanvas.width > 0 && this.cacheCanvas.height > 0) {
			this._context.drawImage(this.cacheCanvas, -this._margin, -this._margin);
		}
	}

	/**
	 * 画遮罩
	 */
	protected drawClip() {

	}

	/**
	 * 画
	 */
	protected draw() {

	}

	/**
	 * 测量边界
	 */
	protected measureBounds() {
		const {anchor: {x, y}, bounds, bounds: {width, height}} = this;

		const anchorOffsetX = this._anchorOffset.x = width * x;
		const anchorOffsetY = this._anchorOffset.y = height * y;

		bounds.x = -anchorOffsetX;
		bounds.y = -anchorOffsetY;
	}

	/**
	 * 碰撞检测
	 * @param x
	 * @param y
	 */
	hitTest(x, y) {
		return this.bounds.contains(x, y);
	}
}
