/**
 * Created by rockyl on 2018/7/12.
 */

import Bounds from "../support/Bounds";
import HashObject from "../core/HashObject";
import {createCanvas} from "./context/RenderContext";
import {Frame} from "../ReType";
import {dirtyFieldDetector} from "../tools/decorators";

/**
 * 纹理类
 */
export default class Texture extends HashObject {
	@dirtyFieldDetector
	img: any;

	private _bounds: Bounds;
	private _cacheCanvas;
	private _cacheContext;

	constructor() {
		super();

		this['isDirty'] = true;
		this._bounds = new Bounds(0, 0, 0, 0, () => {
			this['isDirty'] = true;
		});
	}

	/**
	 * 设置图集中的坐标和尺寸
	 * @param frame
	 */
	setFrame(frame: Frame) {
		let {x, y, w, h} = frame;
		this._bounds.setTo(x, y, w, h);
	}

	/**
	 * 设置图片
	 * @param img
	 */
	setImg(img) {
		this.img = img;
	}

	/**
	 * 获取纹理宽度
	 */
	get width() {
		return this._bounds.width;
	}

	/**
	 * 获取纹理高度
	 */
	get height() {
		return this._bounds.height;
	}

	/**
	 * 获取边界
	 */
	get bounds(): Bounds {
		return this._bounds;
	}

	/**
	 * 产生一个缓存画布
	 */
	getCacheCanvas() {
		let canvas = this._cacheCanvas;

		if (this['isDirty']) {
			this['isDirty'] = false;

			const {_bounds: {width, height}} = this;

			if (!canvas) {
				canvas = this._cacheCanvas = createCanvas();
			}

			let context = this._cacheContext;
			if (!context) {
				context = canvas.getContext('2d');
			}

			canvas.width = width;
			canvas.height = height;
			this.drawToCanvas(context);

			this.drawToCanvas(context);
		}

		return canvas;
	}

	/**
	 * 绘制到一个画布上
	 * @param context
	 * @param dx
	 * @param dy
	 * @param sx
	 * @param sy
	 * @param dw
	 * @param dh
	 */
	drawToCanvas(context, dx = 0, dy = 0, sx?, sy?, dw?, dh?) {
		const {_bounds: {x, y, width, height}} = this;

		context.drawImage(this.img, sx || x, sy || y, width, height, dx, dy, dw || width, dh || height);
	}

	/**
	 * 销毁自身
	 */
	destroy() {
		this.img = null;
		this._bounds = null;

		this.destroyCacheCanvas();
	}

	/**
	 * 销毁缓存画布
	 */
	destroyCacheCanvas() {
		this._cacheCanvas = null;
	}
}

/**
 * 快捷创建纹理
 * @param img
 * @param frame
 */
export function createTexture(img, frame?: Frame): Texture {
	const texture = new Texture();
	texture.setImg(img);
	texture.setFrame(frame || {x: 0, y: 0, w: img.width, h: img.height});

	return texture;
}
