import { MathUtils, Flags } from '@uino/base-thing';
import { Utils } from '../common/Utils';
import { BaseCSSComponent } from './BaseCSSComponent';

let _position_1 = MathUtils.createVec3();
let _position_2 = MathUtils.createVec3();

const Flag = {
	AutoRemove: 1 << 0,
	AutoBind: 1 << 1
}

/**
 * @class CSS2DComponent
 * CSS 2D 组件。
 * @memberof THING
 * @extends THING..BaseCSSComponent
 * @public
 */
class CSS2DComponent extends BaseCSSComponent {

	constructor(options) {
		super(options);

		this._offset = null;
		this._pivot = [0.5, 0.5];

		this._flags = new Flags();
		this._flags.enable(Flag.AutoRemove, true);
		this._flags.enable(Flag.AutoBind, false);

		this._factor = 1;
	}

	// #region Private

	_isVisible(screenPosition) {
		// Check whether behind camera
		let z = screenPosition[2];
		if (z > 1) {
			return false;
		}

		return true;
	}

	// #endregion

	// #region Overrides

	onRemove() {
		if (this._domElement && this.autoRemove) {
			let parentNode = this._domElement.parentNode;
			if (parentNode) {
				parentNode.removeChild(this._domElement);
			}
		}

		this._domElement = null;

		super.onRemove();
	}

	onRender(renderLayout) {
		let domElement = this._domElement;
		if (!domElement) {
			return;
		}

		// Get the center position of screen
		let center;
		if (this._offset) {
			center = renderLayout.selfToWorld(this._offset, false, _position_1);
		}
		else {
			center = renderLayout.getCenter(_position_1);
		}

		// Get the screen position
		let screenPosition = renderLayout.worldToScreen(center, _position_2);
		let isVisible = this._isVisible(screenPosition);

		// Auto update visible state
		if (this.updateDomElementVisibility(isVisible)) {
			// Update Z-Index value
			if (Utils.isNull(this._zIndex)) {
				let zIndex = 1000 - Math.ceil(screenPosition[2] * 10000 - 9900);
				domElement._setZIndex(zIndex);
			}

			// Get width and height by threshold
			const threshold = 1.5;
			let width = domElement._getOffsetWidth(threshold);
			let height = domElement._getOffsetHeight(threshold);

			// Get left and top position by pivot and size
			let position = domElement._getPositionByPivot(this._delegate.domElement, width, height, screenPosition, this._pivot);
			domElement._setLeft(position[0]);
			domElement._setTop(position[1]);
		}
	}

	// #endregion

	/**
	 * 获取/设置是否在移除时自动移除 DOM 元素。
	 * @type {boolean}
	 * @public
	 * @example
	 * // 组件移除时自动移除 DOM 元素
	 * component.autoRemove = true;
	 */
	get autoRemove() {
		return this._flags.has(Flag.AutoRemove);
	}
	set autoRemove(value) {
		this._flags.enable(Flag.AutoRemove, value);
	}

	/**
	 * 获取/设置是否在添加到场景时自动绑定 DOM 元素。
	 * @type {boolean}
	 * @public
	 * @example
	 * // 添加到场景时自动绑定 DOM 元素
	 * component.autoBind = true;
	 */
	get autoBind() {
		return this._flags.has(Flag.AutoBind);
	}
	set autoBind(value) {
		if (this._flags.enable(Flag.AutoBind, value)) {
			let app = this.object.app;

			if (value) {
				this._domElement.style.position = "absolute"; // Add absolute positioning
				app.container.appendChild(this._domElement);
			}
			else {
				app.container.removeChild(this._domElement);
			}
		}
	}

	/**
	 * 获取/设置对象在自身空间中的偏移量,null表示使用对象的边界框中心。
	 * @type {Array<number>}
	 * @public
	 * @example
	 * // 设置偏移量为 [10, 20]
	 * component.offset = [10, 20];
	 */
	get offset() {
		return this._offset;
	}
	set offset(value) {
		if (value) {
			this._offset = value.slice(0);
		}
		else {
			this._offset = null;
		}
	}

	/**
	 * 获取/设置从左下角计算的轴心点。
	 * @type {Array<number>}
	 * @public
	 * @example
	 * // 设置轴心点为中心
	 * component.pivot = [0.5, 0.5];
	 */
	get pivot() {
		return this._pivot;
	}
	set pivot(value) {
		if (value) {
			this._pivot = value.slice(0);
		}
		else {
			this._pivot = [0.5, 0.5];
		}
	}

	/**
	 * 获取/设置缩放因子。
	 * @type {number}
	 * @public
	 * @example
	 * // 设置缩放因子为 2
	 * component.factor = 2;
	 */
	get factor() {
		return this._factor;
	}
	set factor(value) {
		if (Utils.isValid(value)) {
			this._factor = value;

			if (this._domElement) {
				this._domElement.style.transform = `scale(${value}, ${value})`
			}
		}
	}

}

export { CSS2DComponent }