import { Box3 } from '@uino/base-thing';
import { Object3D, Utils } from '@uino/thing';


function _calFloorUV2(box, verticesUV2, verticespos, obj) {
	for (let i = 0; i < verticespos.length; i += 3) {
		let x = (verticespos[i] - (box.center[0] - obj.position[0] - box.halfSize[0])) / (2 * box.halfSize[0]);
		let y = (verticespos[i + 2] - (box.center[2] - obj.position[2] - box.halfSize[2])) / (2 * box.halfSize[2]);
		verticesUV2.push(x, 1 - y);
	}
	return verticesUV2;
}

const __ = {
	private: Symbol('private'),
}


/**
 * @class Floor
 * 楼层
 * @extends THING.Object3D
 * @public
 */
class Floor extends Object3D {

	static defaultTagArray = ['Floor'];

	constructor(param = {}) {
		super(param);
		const _private = this[__.private] = {};

		// 楼层高度
		_private.height = Utils.parseNumber(param['height'], 3);

		this._constantShowThings = Utils.parseBoolean(param['constantShowThings'], false);
	}

	/**
	 * 显示/隐藏所有屋顶(包括楼层和楼层下方房间的屋顶)
	 * @param {Boolean} visible true 显示(默认)/ false 隐藏
	   * @public
	 */
	showAllRoofs(visible = true) {
		const roofs = this.roofs;
		if (roofs) {
			roofs.forEach(element => {
				element.visible = visible;
			});
		}
	}

	/**
	 * 显示/隐藏所有天花板(包括楼层和楼层下方房间的天花板)
	 * @param {Boolean} visible true 显示(默认)/ false 隐藏
	   * @public
	 */
	showAllCeilings(visible = true) {
		const ceilings = this.ceilings;
		if (ceilings) {
			ceilings.forEach(element => {
				element.visible = visible;
			});
		}
	}

	bake(params) {
		var walls = this.walls;
		if (!walls.length) {
			return;
		}

		if (params === null) {
			if (!this._baked) {
				return;
			}

			this.slabs.forEach(element => {
				const ustyle = element.body.style.resource;
				ustyle.setImage('AOMap', null)
			});

			this._baked = false;
		}
		else {
			params = params || {};

			const intensity = Utils.parseValue(params['intensity'], 3);

			let aoMap = Utils.createObject('RenderTextureResource');

			let wallNodes = [];
			walls.forEach(wall => {
				wallNodes.push(wall.node);
			});
			const floorBondingBox = this.boundingBox;

			let center = [0, 0, 0]
			THING.MathUtils.subVector(floorBondingBox.center, this.parent.position, center)

			const floorBox = new Box3(floorBondingBox.center, floorBondingBox.halfSize);
			const floorBox2 = new Box3(center, floorBondingBox.halfSize);
			this.app.view.bakeAOMap(wallNodes, floorBox2, aoMap);

			this.slabs.forEach(slab => {
				let verticesUV2 = [];
				const slabNode = slab.node;
				if (slabNode.setUv2) {
					slabNode.setUv2(floorBox, slab.position)
				} else if (slabNode._geometryResource) {
					const verticespos = slabNode._geometryResource.getAttribute('a_Position');
					_calFloorUV2(floorBox, verticesUV2, verticespos, slab);
					slabNode._geometryResource.setAttribute('a_Uv2', new Float32Array(verticesUV2));
				} else {
					return;
				}
				const ustyle = slab.body.style.resource;
				ustyle.setAttribute('AOMapIntensity', intensity);
				ustyle.setImage('AOMap', aoMap)
			});

			this._baked = true;
		}
	}

	/**
	 * Gets the building where the floor is located
	 * @type {THING.Building}
	 */
	get building() {
		return this.parents.find('tags:or(Building)');
	}

	get corners() {
		return this._corners;
	}

	/**
	 * 获取楼层下的墙体对象集合
	 * @type {THING.Selector<THING.Object3D>}
	 * @example
	 * let roofs = floor.roofs;
	 * console.log(roofs);
	   * @public
	 */
	get roofs() {
		return this.queryByTags('RoomRoof');
	}

	/**
	 * 获取楼层下的房间对象集合
	 * @type {THING.Selector<THING.Room>}
	 * @example
	 * let rooms = floor.rooms;
	 * console.log(rooms);
	   * @public
	 */
	get rooms() {
		return this.queryByTags('Room');
	}

	/**
	 * 获取楼层下的天花板对象集合
	 * @type {THING.Selector<THING.Object3D>}
	 * @example
	 * let ceilings = floor.ceilings;
	 * console.log(ceilings);
	   * @public
	 */
	get ceilings() {
		return this.queryByTags('RoomCeiling');
	}

	/**
	 * 获取楼层下的墙体对象集合
	 * @type {THING.Selector<THING.Object3D>}
	 * @example
	 * let walls = floor.walls;
	 * console.log(walls);
	   * @public
	 */
	get walls() {
		return this.queryByTags('Wall');
	}

	/**
	 * 获取楼层下的门对象集合
	 * @type {THING.Selector<THING.Door>}
	 * @example
	 * let doors = floor.doors;
	 * console.log(doors);
	   * @public
	 */
	get doors() {
		return this.queryByTags('Door');
	}

	/**
	 * 获取楼层下的板块对象集合
	 * @type {THING.Selector<THING.Object3D>}
	 * @example
	 * let slabs = floor.slabs;
	 * console.log(slabs);
	   * @public
	 */
	get slabs() {
		return this.query('tags:or(Slab,RoomFloor)');
	}

	/**
	 * 获取其他对象
	 * @type {THING.Object3D}
	 * @example
	 * let misc = floor.misc;
	 * console.log(misc);
	 * @public
	 */
	get misc() {
		return this.children.find('tags:or(Misc)');
	}

	/**
	 * 获取楼层下的放置对象集合
	 * @type {THING.Selector<THING.Entity>}
	 * @example
	 * let placements = floor.placements;
	 * console.log(placements);
	 * @public
	 */
	get placements() {
		let plcs = this.queryByTags('Placement');
		return plcs;
	}

	/**
	 * 获取楼层编号(从1开始)
	 * @type {Number}
	 * @example
	 * let levelNumber = floor.levelNumber;
	 * console.log(levelNumber);
	 * @public
	 */
	get levelNumber() {
		let children = this.parent.children;

		let levelNumber = 1;

		for (let i = 0; i < children.length; i++) {
			const child = children[i];
			if (!child.isFloor) {
				continue;
			}

			if (child == this) {
				break;
			}

			++levelNumber;
		}

		return levelNumber;
	}

	/**
	 * Get floor height
	 * @private
	 * @type {Number}
	 */
	get height() {
		const _private = this[__.private];
		return _private.height;
	}

}

export { Floor };