import { ObjectProxy } from '@uino/base-thing';

import { Utils } from '../common/Utils';

import { BaseComponent } from './BaseComponent';



const __ = {

	private: Symbol('private'),

}



const cKeys = [

	'glow',

	'innerGlow',

	'tailing',

	'radial',

	'ghosting',

	'lineBloom',

];



/**
 * CameraEffectComponent - 相机效果组件
 *
 * 控制相机渲染效果,可以启用或关闭后处理效果如辉光、模糊等。
 * @class CameraEffectComponent
 * @memberof THING
 * @extends THING.BaseComponent
 * @public
 * @example
	app.camera.effect.enable = true;
	app.camera.effect.glow.enable = true;
 */
class CameraEffectComponent extends BaseComponent {



	/**

	 * 相机的渲染效果,可以在这里更改一些对象的后处理效果。

	 * </br>这里面所有的属性代表整体的一个控制,如需看到效果,需要先把物体身上的对应的effect开启

	 */

	constructor() {
		super();



		this[__.private] = {};

		let _private = this[__.private];



		_private.needsRefresh = false;



		/**

		 发光效果
		 * @typedef {object} CameraGlowEffect
		 * @property {boolean} enable 是否开启
		 * @property {number} strength 强度
		 * @property {number} threshold 阈值
		 * @property {number} radius 半径
		 * @public
		 */



		_private.glow = {

			enable: true,

			strength: 1.5,

			threshold: 0.001,

			radius: 0.4

		};



		/**

		 内发光效果
		 * @typedef {object} CameraInnerGlowEffect
		 * @property {boolean} enable 是否开启
		 * @property {Array<number>} color 颜色
		 * @property {number} strength 强度
		 * @property {number} stride 跨度
		 * @public
		 */



		_private.innerGlow = {

			color: [1, 0, 0, 1],

			enable: true,

			strength: 2,

			stride: 10,

		};



		/**
		 
		 拖尾效果
		 * @typedef {object} CameraTailingEffect
		 * @property {boolean} enable 是否开启
		 * @property {Array<number>} direction 方向
		 * @property {Array<number>} center 中心点
		 * @public
		 */



		_private.tailing = {

			enable: true,

			direction: [0, 1],

			center: [0.5, 0.5]

		};



		/**

		 扩散效果
		 * @typedef {object} CameraRadialEffect
		 * @property {boolean} enable 是否开启
		 * @property {Array<number>} center 中心
		 * @public
		 */



		_private.radial = {

			enable: true,

			center: [0.5, 0.5]

		};



		/**

		 残影效果
		 * @typedef {object} CameraGhostingEffect
		 * @property {boolean} enable 是否开启
		 * @property {Array<number>} center 中心位置
		 * @public
		 */



		_private.ghosting = {

			enable: true,

			center: [0.5, 0.5]

		};



		/**

		 线辉光效果
		 * @typedef {object} CameraLineBloomEffect
		 * @property {boolean} enable 是否开启
		 * @property {number} blendRate 混合比例
		 * @property {number} blurSize 模糊半径
		 * @property {number} strength 强度
		 * @public
		 */



		_private.lineBloom = {

			enable: true,

			blendRate: 0.7,

			blurSize: 1,

			strength: 1,

		};



		/**

		 选中效果
		 * @typedef {object} CameraLineBloomEffect
		 * @property {number} thickness 厚度
		 * @property {number} strength 强度
		 * @public
		 */



		_private.outLine = {

			strength: 1.5,

			thickness: 1.0,

		};



		_private.onChange = null;



		_private.enable = false;



		// Initialize config

		_private.objectProxy = new ObjectProxy({

			data: {

				glow: _private.glow,

				innerGlow: _private.innerGlow,

				tailing: _private.tailing,

				radial: _private.radial,

				ghosting: _private.ghosting,

				lineBloom: _private.lineBloom,

				outLine: _private.outLine,

			},

			onChange: function (ev) {
				_private.needsRefresh = true;



				if (_private.onChange) {
					_private.onChange(ev);
				}
			}

		});



		// Show config always

		Object.defineProperty(this, 'customFormatters', {

			enumerable: false,

			configurable: false,

			get: function () {
				return ['object', { object: _private.objectProxy.dataProxy }];
			}

		});
	}



	// #region Private



	_refreshEffect() {
		let _private = this[__.private];



		let cameraNode = this.object.node;

		cameraNode.setEffectConfig('glow', _private.glow);

		cameraNode.setEffectConfig('innerGlow', _private.innerGlow);

		cameraNode.setEffectConfig('tailing', _private.tailing);

		cameraNode.setEffectConfig('radial', _private.radial);

		cameraNode.setEffectConfig('ghosting', _private.ghosting);

		cameraNode.setEffectConfig('lineBloom', _private.lineBloom);

		cameraNode.setEffectConfig('outLine', _private.outLine);



		// Check whether disable it

		if (!_private.enable) {
			cKeys.forEach(key => {
				cameraNode.setEffectConfig(key, { enable: false });
			});
		}
	}



	_refresh() {
		let _private = this[__.private];



		if (!_private.needsRefresh) {
			return;
		}



		_private.needsRefresh = false;



		this._refreshEffect();
	}



	// #endregion



	// #region BaseComponent Overrides



	onAdd(object) {
		super.onAdd(object);



		// Refresh config before render if needed

		this.app.addBeforeRenderCallback(this._onBeforeRenderCallback = () => {
			this._refresh();
		});



		// Refresh effect by current config

		this._refreshEffect();
	}



	onRemove() {
		let _private = this[__.private];



		_private.objectProxy.dispose();



		this.app.removeBeforeRenderCallback(this._onBeforeRenderCallback);



		super.onRemove();
	}



	// #endregion



	/**

	 是否开启
	 * @type {boolean}
	 * @public
	 */

	get enable() {
		let _private = this[__.private];



		return _private.enable;
	}

	set enable(value) {
		let _private = this[__.private];



		if (_private.enable == value) {
			return;
		}



		_private.enable = value;



		this._refreshEffect();
	}



	/**

	 发光效果
	 * @type {CameraGlowEffect}
	 * @public
	 */

	get glow() {
		return this[__.private].objectProxy.dataProxy.glow;
	}



	/**

	 内发光效果
	 * @type {CameraInnerGlowEffect}
	 * @public
	 */

	get innerGlow() {
		return this[__.private].objectProxy.dataProxy.innerGlow;
	}



	/**

	 拖尾效果(1.0中的postRadialBlur)
	 * @type {CameraTailingEffect}
	 * @public
	 */

	get tailing() {
		return this[__.private].objectProxy.dataProxy.tailing;
	}



	/**

	 扩散效果(1.0中的postRadialBlur2)
	 * @type {CameraRadialEffect}
	 * @public
	 */

	get radial() {
		return this[__.private].objectProxy.dataProxy.radial;
	}



	/**

	 残影效果
	 * @type {CameraGhostingEffect}
	 * @public
	 */

	get ghosting() {
		return this[__.private].objectProxy.dataProxy.ghosting;
	}



	/**

	 线辉光效果
	 * @type {CameraLineBloomEffect}
	 * @public
	 */

	get lineBloom() {
		return this[__.private].objectProxy.dataProxy.lineBloom;
	}



	/**

	 选中效果
	 * @type {CameraLineBloomEffect}
	 * @public
	 */

	get outLine() {
		return this[__.private].objectProxy.dataProxy.outLine;
	}

	/**

	 配置项
	 * @type {object}
	 * @public
	 */

	get config() {
		return this[__.private].objectProxy.dataProxy;
	}

	set config(value = {}) {
		let _private = this[__.private];



		let to = _private.objectProxy.dataProxy;



		Utils.mergeObject(to.glow, value.glow, true);

		Utils.mergeObject(to.innerGlow, value.innerGlow, true);

		Utils.mergeObject(to.tailing, value.tailing, true);

		Utils.mergeObject(to.radial, value.radial, true);

		Utils.mergeObject(to.ghosting, value.ghosting, true);

		Utils.mergeObject(to.lineBloom, value.lineBloom, true);

		Utils.mergeObject(to.outLine, value.outLine, true);
	}



	/**

	 Get/Set when change callback function.
	 * @type {Function}
	 * @private
	 */

	get onChange() {
		let _private = this[__.private];



		return _private.onChange;
	}

	set onChange(value) {
		let _private = this[__.private];



		_private.onChange = value;
	}



}



export { CameraEffectComponent }