import { Utils } from '../common/Utils'
import { MathUtils } from '../math/MathUtils';
import { BaseDynamicPoints } from './BaseDynamicPoints';

let _originalQuat = [0, 0, 0, 1];

/**
 * ExtrudeShape - 拉伸几何体
 *
 * 用于通过平面轮廓和高度的方式创建拉伸几何体。
 * @class ExtrudeShape
 * @memberof THING
 * @extends THING.BaseDynamicPoints
 * @public
 * @example
 * const shape = new THING.ExtrudeShape({
 *   selfPlanePoints: [[0, 0], [2, 0], [2, 2], [0, 2]],
 *   height: 3,
 * });
 */
class ExtrudeShape extends BaseDynamicPoints {

	static defaultTagArray = ['Geometry'];

	/**
	 * 创建一个ExtrudeShape对象,用于在场景中通过高度创建多边形形状。
	 * @param {object} param 初始化参数
	 * @param {Array<Array<number>>} [param.selfPlanePoints] 自身空间中的平面点
	 * @param {Array<Array<Array<number>>>} [param.selfPlaneHoles] 自身空间中的平面孔洞
	 * @param {Array<Array<Array<number>>>} [param.selfHoles] 自身空间中的孔洞
	 * @param {Array<Array<Array<number>>>} [param.holes] 世界空间中的孔洞
	 * @param {number} [param.height] 拉伸高度
	 * @param {string} [param.visibleDirection] 可见方向,可选值:'Both'、'Top'、'Bottom'
	 * @constructor
	 * @public
	 */
	constructor(param = {}) {
		super(param);
	}

	// #region Private Functions

	/**
	 * Refresh holes.
	 * @private
	 */
	_refreshHoles() {
		let selfPlaneHoles = this.selfPlaneHoles;

		this.bodyNode.setHoles(selfPlaneHoles);
	}
	// #endregion

	// #region Overrides

	onSetupResource(param) {
		// 读取点数据,写到参数里传给父类处理
		const selfPlanePoints = param['selfPlanePoints'];
		if (selfPlanePoints) {
			param['selfPoints'] = convertPlanePoints(selfPlanePoints);
		}

		// 读取洞数据
		const selfPlaneHoles = param['selfPlaneHoles'];
		if (selfPlaneHoles) {
			this._selfHoles = convertPlaneHolesPoints(selfPlaneHoles);
		}
		else if (param['selfHoles']) {
			this._selfHoles = param['selfHoles'];
		}
		else if (param['holes']) {
			this._selfHoles = param['holes'].map(hole => {
				return hole.map(_hole => {
					return this.worldToSelf(_hole);
				});
			});
		}
		else {
			this._selfHoles = [];
		}

		this._height = Utils.parseNumber(param['height'], 0);
		this._visibleDirection = param['visibleDirection'] || 'Both';

		super.onSetupResource(param);
	}

	onCreateBodyNode(param) {
		const node = Utils.createObject('ExtrudeShape', { app: this.app });
		node.setQuaternion(_originalQuat);
		return node;
	}

	onSetupBodyNode(node) {
		super.onSetupBodyNode(node);

		const holes = this.selfPlaneHoles;
		if (holes) {
			node.setHoles(holes);
		}

		if (this._height) {
			node.setHeight(this._height);
		}

		if (this._visibleDirection) {
			node.setVisibleDirection(this._visibleDirection);
		}
	}

	onGetSelfPoints(selfPoints) {
		return selfPoints.map(point => {
			return [point[0], point[2]];
		});
	}

	onExportExternalData() {
		let external = Object.assign({}, super.onExportExternalData());
		Utils.setAttributeIfExist(external, 'selfPlanePoints', this);
		Utils.setAttributeIfExist(external, 'selfPlaneHoles', this);
		Utils.setAttributeIfExist(external, 'selfHoles', this);
		Utils.setAttributeIfExist(external, 'height', this);
		Utils.setAttributeIfExist(external, 'visibleDirection', this);
		return external;
	}

	// #endregion

	// #region Accessor

	/**
	 * Get/Set the plane points in self space.
	 * @type {Array<Array<number>>}
	 * @private
	 */
	get selfPlanePoints() {
		return this.points.map(point => {
			let selfPoint = this.worldToSelf(point);

			return [selfPoint[0], selfPoint[2]];
		});
	}
	set selfPlanePoints(value = []) {
		if (!MathUtils.isClockWise(value)) {
			const reversedArr = value.slice().reverse();
			this.points = (reversedArr).map(point => {
				return this.selfToWorld([point[0], 0, point[1]]);
			});
		}
		else {
			this.points = (value).map(point => {
				return this.selfToWorld([point[0], 0, point[1]]);
			});
		}
	}

	/**
	 * Get/Set the plane holes in self space.
	 * @type {Array<Array<Array<number>>>}
	 * @private
	 */
	get selfPlaneHoles() {
		return this._selfHoles.map(hole => {
			return hole.map(_hole => {
				return [_hole[0], _hole[2]];
			});
		});
	}
	set selfPlaneHoles(value) {
		this._selfHoles = value.map(hole => {
			return hole.map(_hole => {
				return [_hole[0], 0, _hole[1]];
			});
		});

		this._refreshHoles();
	}

	/**
	 * 获取/设置自身空间中的孔洞。
	 * @type {Array<Array<Array<number>>>}
	 * @public
	 */
	get selfHoles() {
		return this._selfHoles;
	}
	set selfHoles(value = []) {
		this._selfHoles = value.slice(0);

		this._refreshHoles();
	}

	/**
	 * 获取/设置世界空间中的孔洞。
	 * @type {Array<Array<Array<number>>>}
	 * @public
	 */
	get holes() {
		return this._selfHoles.map(hole => {
			return hole.map(_hole => {
				return this.selfToWorld(_hole);
			});
		});
	}
	set holes(value = []) {
		this._selfHoles = value.map(hole => {
			return hole.map(_hole => {
				return this.worldToSelf(_hole);
			});
		});

		this._refreshHoles();
	}

	/**
	 * 获取/设置高度。
	 * @type {number}
	 * @public
	 */
	get height() {
		return this._height;
	}
	set height(value) {
		this._height = value;

		this.bodyNode.setHeight(value);
	}

	/**
	 * 获取/设置生成底部或顶部面的可见性。
	 * @public
	 * @type {THING.ExtrudeShapeDirection}
	 */
	set visibleDirection(value) {
		this._visibleDirection = value;
		this.bodyNode.setVisibleDirection(value);
	}

	get visibleDirection() {
		return this._visibleDirection;
	}

	// #endregion

	get isExtrudeShape() {
		return true;
	}

}

export { ExtrudeShape }

function convertPlanePoints(value) {
	if (!MathUtils.isClockWise(value)) {
		const reversedArr = value.slice().reverse();
		return (reversedArr).map(point => {
			return [point[0], 0, point[1]];
		});
	}
	else {
		return (value).map(point => {
			return [point[0], 0, point[1]];
		});
	}
}

function convertPlaneHolesPoints(value) {
	return value.map(hole => {
		return hole.map(_hole => {
			return [_hole[0], 0, _hole[1]];
		});
	});
}