import { BaseComponent, Camera, MathUtils, Math, ProjectionType, ViewMode } from '@uino/thing';

/**
 * 小地图组件
 * @class MinimapComponent
 * @summary 小地图组件,在三维场景的角落叠加一个俯视摄像机视图作为小地图,并支持主摄像机方向标记。
 * 通过附加的 Orthographic 俯视摄像机渲染场景缩略视图,同时在 DOM 上叠加方向指示图标,
 * 帮助用户快速了解主摄像机在场景中的位置与朝向。支持位置/尺寸/布局自定义,
 * 并内置关闭按钮、视口指示器和摄像机标记等图标。
 * @public
 * @memberof THING
 * @example
 * // 在场景中添加小地图组件
	app.root.addComponent(THING.MinimapComponent, 'minimap', {
		size: [250, 250],
		layout: ['Right', 'Bottom'],
	});
	app.root.minimap.enable=true;  
 */
class MinimapComponent extends BaseComponent {

	/**
	 * @constructor
	 * @public
	 * @param {object} param 初始参数
	 * @param {Number[]} size 小地图尺寸
	 * @param {String[]} layout 小地图布局位置
	 * 
	 */
	constructor(param) {
		super(param);
		let def_param = JSON.parse(JSON.stringify(this.def_param)); // 拷贝默认参数
		this.options = { ...def_param, ...param }; // 与默认参数合并
	}

	onAdd(object) {
		super.onAdd(object);
		this._create();
		this.enable = true;
	}

	onRemove() {
		this._destroy()
		super.onRemove();
	}

	onUpdate() {
		this._update();
	}


	get size() {
		return this.options.size
	}
	/**
	 * 设置/获取小地图的尺寸
	 * @public
	 * @type {Array}
	 * @example
	 * minimap.size = [300, 300]
	 */
	set size(val) {
		this._destroy()
		this.options.size = val
		this._create()
	}

	get width() {
		return this.options.size[0]
	}

	set width(val) {
		this._destroy()
		this.options.size[0] = val
		this._create()
	}

	get height() {
		return this.options.size[1]
	}

	set height(val) {
		this._destroy()
		this.options.size[1] = val
		this._create()
	}

	get distance() {
		return this.options.distance
	}

	set distance(val) {
		this.options.distance = val
		if (this.minimapCamera) {
			let position = this.minimapCamera.position;
			this.minimapCamera.position = [position[0], val, position[2]]
		}
	}

	get layout() {
		return this.options.layout
	}

	/**
	 * 设置/获取小地图的布局
	 * @public
	 * @type {String[]}
	 * @example
	 *  minimap.layout = ["Left", "Bottom"]
	 */
	set layout(val) {
		this._destroy()
		this.options.layout = val
		this._create()
	}

	get position() {
		return this.options.position
	}

	/**
	 * 设置/获取小地图的位置 如果设置了 position 就忽略 layout
	 * @public
	 * @type {Number}
	 * @example
	 *  minimap.position = [1,1]
	 */
	set position(val) {
		this._destroy()
		this.options.position = val
		this._create()
	}

	/**
	 * 设置/获取小地图是否启用
	 * @public
	 * @type {Array}
	 * @example
	 *  minimap.enable = true
	 */
	get enable() {
		return this._enable;
	}

	set enable(value) {
		this._enable = value;
		this['minimap-border'].style.display = value ? 'block' : 'none';
		this.minimapCamera.visible = value;
	}

	_create() {
		this._createMinimapDom();
		this._createMinimapView();
	}

	_destroy() {
		if (this['minimap-border'] != null) {
			this.app.container.removeChild(this['minimap-border']);
			this['minimap-border'] = null;
		}
		this.minimapCamera.destroy();
	}

	// 创建小地图的dom
	_createMinimapDom() {
		let _style_ =
			`.minimap-border {
                    position : absolute;
                    border: 5px solid rgba(255, 255, 255, 0.8);
                    border-radius: 3px;
                    display: block;
                    box-sizing: border-box;
                    overflow:hidden;
                }
                .minimap-viewport {
                    position : absolute;
                }
                .minimap-target {
                    position : absolute;
                }
                .minimap-close {
                    position : absolute;
                    right : 1px;
                    top : 1px;
                }
            `;
		let style = document.createElement("style")
		style.type = "text/css";
		style.innerHTML = _style_;
		document.body.appendChild(style);

		let _classNames = [];
		function _getClassNames(options) {
			for (let key in options) {
				if (key === 'className') {
					_classNames.push({ key: options[key], show: options['show'], size: options['size'], src: options['src'] })
				}

				if (typeof options[key] === 'object') {
					_getClassNames(options[key])
				}
			}
		}
		_getClassNames(this.options);

		// 创建 div
		_classNames.forEach((cn) => {
			let div;
			if (cn.key === 'minimap-border') {
				div = document.createElement("div");
				let o = this._getDomOrigin();
				div.style.left = o.left === null ? null : o.left + 'px';
				div.style.right = o.right === null ? null : o.right + 'px';
				div.style.top = o.top === null ? null : o.top + 'px';
				div.style.bottom = o.bottom === null ? null : o.bottom + 'px';
				this.app.container.appendChild(div);
				this.miniDomDiv = div;
			}
			else {
				div = document.createElement("img");
				div.src = cn.src; // 设置背景图片
				this.miniDomDiv.appendChild(div)
			}

			div.className = cn.key;
			div.style.display = cn.show ? 'block' : 'none'; // 是否显示某个icon
			div.style.width = cn.size[0] + 'px'; // 设置宽度
			div.style.height = cn.size[1] + 'px'; // 设置高度

			this[cn.key] = div;  // 赋给全局

			// 如果是关闭按钮,则绑定关闭事件
			let that = this;
			if (cn.key === 'minimap-close') {
				if (cn.show) {
					div.style.right = '0px';
					div.style.top = '0px';
				}
				div.onclick = function () {
					if (that.enable) { that.enable = false; }
				}
			}
		})
	}

	// 创建小地图摄影机
	_createMinimapView() {
		var minimapCamera = new Camera();
		minimapCamera.enableViewport = true;
		minimapCamera.viewport = [this._getDomOrigin().left, this._getDomOrigin().top, this.options.size[0], this.options.size[1]];
		minimapCamera.projectionType = ProjectionType.Orthographic;
		minimapCamera.viewMode = ViewMode.Top;
		minimapCamera.postEffect.enable = false;
		minimapCamera.enable = false;
		minimapCamera.background = null;
		minimapCamera.control.enableAdjustTargetPosition = false;
		let position = minimapCamera.position
		if (this.options.distance) {
			minimapCamera.position = [position[0], this.options.distance, position[2]]
		}
		else {
			this.options.distance = position[2]
		}

		this.minimapCamera = minimapCamera;
	}

	// 刷新一次。主要刷新状态,例如图标的显隐
	_refresh() {

	}

	// 每帧刷新。更新小地图中图标的方向和位置
	_update() {
		// 如果是激活状态
		if (!this.enable) return;
		let iconConfig = this.options.iconConfig;
		let target = iconConfig.target;
		let viewport = iconConfig.viewport;

		let ori = this._getDomOrigin();
		let pos = this._getPos_world2screen();
		let ang = this._getAng_world2screen();

		if (this._getShow(target)) { // 如果显示主摄像机标记
			this['minimap-target'].style.left = pos.left - target.size[0] / 2 + 'px';
			this['minimap-target'].style.top = pos.top - target.size[1] / 2 + 'px';
		}
		if (this._getShow(viewport)) {  // 如果显示视口图片
			this['minimap-viewport'].style.left = pos.left - viewport.size[0] / 2 + 'px';
			this['minimap-viewport'].style.top = pos.top - viewport.size[1] + 'px';
			this['minimap-viewport'].style.transform = 'rotate(' + (ang) + 'deg)';
			this['minimap-viewport'].style.transformOrigin = "50% 100%";
		}
	}

	// 根据小地图的分布获取dom的原点
	_getDomOrigin() {
		let left = 0
		let top = 0
		let width = this.app.container.clientWidth - this.options.size[0]
		let height = this.app.container.clientHeight - this.options.size[1]
		if (this.options.position) {
			left = this.options.position[0] * width;
			top = this.options.position[1] * height
		}
		else if (this.options.layout) {
			let layout = this.options.layout;
			if (layout[0].toLowerCase() === 'left') {
				left = 0
			}
			else if (layout[0].toLowerCase() === 'right') {
				left = width
			}
			else if (layout[0].toLowerCase() === 'center') {
				left = 0.5 * width
			}

			if (top = layout[1].toLowerCase() === 'top') {
				top = 0
			}
			else if (top = layout[1].toLowerCase() === 'bottom') {
				top = height
			}
			else if (top = layout[1].toLowerCase() === 'center') {
				top = 0.5 * height
			}
		}

		return {
			left, top
		}
	}
	// 转换成小地图坐标
	_getPos_world2screen() {
		// 把小地图的摄影机坐标系按比例转成小地图视口的屏幕坐标
		let _cameraPos_ = this.minimapCamera.position;
		let _width_ = this.minimapCamera.orthoRect[1] - this.minimapCamera.orthoRect[0];
		let _height_ = this.minimapCamera.orthoRect[3] - this.minimapCamera.orthoRect[2];
		let _oriX_ = _cameraPos_[0] - _width_ / 2;
		let _oriZ_ = _cameraPos_[2] - _height_ / 2;

		// 计算比例
		let _mainCameraPos_ = this.app.camera.position;
		let _scale_x_ = (_mainCameraPos_[0] - _oriX_) / _width_;
		let _scale_z_ = (_mainCameraPos_[2] - _oriZ_) / _height_;

		// 2d坐标
		let left = _scale_x_ * this.options.size[0];
		let top = _scale_z_ * this.options.size[1];
		return { left, top };
	}

	// 转换角度
	_getAng_world2screen() {
		const camDir = this.app.camera.forward;
		const angleRad = MathUtils.vec3.angle([0, 0, -1], [camDir[0], 0, camDir[2]]);
		let v3 = [];
		MathUtils.vec3.cross(v3, [0, 0, -1], [camDir[0], 0, camDir[2]]);
		const angle = MathUtils.radToDeg(angleRad);
		return 360 - (v3[1] > 0 ? angle : 360 - angle);
	}

	// 获取是否显示
	_getShow(icon) {
		return icon.show;
	}

	// 获取默认参数
	get def_param() {
		return {
			/* --- 小地图配置项 --- */
			className: "minimap-border",
			show: true,
			borderWidth: 5, // 边框宽度

			layout: ["Left", "Top"], // 小地图的布局
			size: [200, 200], // 小地图窗口的大小
			opacity: 1, // 小地图窗口的透明度
			scaleFactor: 1, // 视口缩放
			followTarget: false, // 主摄影机跟随视口鼠标点击位置

			/* --- 图标配置项 --- */
			iconConfig: {
				// 关闭按钮
				close: {
					className: "minimap-close",
					show: true,
					src: "http://www.thingjs.com/static/images/minimap2.png",
					size: [20, 20]
				},
				// 视口
				viewport: {
					className: "minimap-viewport",
					show: true,
					src: "http://www.thingjs.com/static/images/minimap1.png",
					size: [40, 30]
				},
				// 主摄影机标记
				target: {
					className: "minimap-target",
					show: true,
					src: "http://www.thingjs.com/static/images/minimap0.png",
					size: [15, 15]
				}
			}
		}
	}

}

export { MinimapComponent }