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

import { BaseTickableObject3D } from './BaseTickableObject3D';

import { ParticleGroup } from './ParticleGroup';

import { Object3D } from './Object3D';

import { StyleModifier } from '../resources/StyleModifier';

import { Style } from '../resources/Style';



let dummyStyle;



/**
 * ParticleSystem - 粒子系统
 *
 * 用于创建和管理粒子系统对象,实现烟雾、火焰、雨雪等粒子特效。
 * @class ParticleSystem
 * @memberof THING
 * @extends THING.BaseTickableObject3D
 * @public
 * @example
	const data = await THING.Utils.loadJSONFileAsync('https://model.3dmomoda.com/models/19061018snbajhvuzrheq9sbgwdoefuk/0/particles/index.json');
	const fire = new THING.ParticleSystem({
		id: 'fire01',
		data
	});
 */
class ParticleSystem extends BaseTickableObject3D {



	/**
	 粒子系统对象构造函数。
	 * @param {object} param 初始参数。
	 * @param {string} [param.url] 粒子系统资源的URL路径。
	 * @param {object} [param.data] 粒子系统数据对象,包含粒子系统的配置和属性。
	 * 其他参数与 {@link THING.BaseTickableObject3D} 的构造函数相同。
	 * 请在 {@link THING.BaseTickableObject3D} 的文档中查看构造函数部分以获取详细参数列表。
	 * @constructor
	 * @public
	 */

	constructor(param = {}) {
		super(param);

		const gl = this.app.camera.bodyNode.$uAppView._renderer.context;

		const sizeMax = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE)[1];

		if (sizeMax < 1024) {
			console.warn("The maximum settable gl_pointSize supported by the current browser is " + sizeMax + ", when the calculated value exceeds this value, the display may be incorrect.");
		}
	}



	// #region BaseObject Interface



	onUpdate(deltaTime) {
		super.onUpdate(deltaTime);

		if (this.loaded) {
			this.bodyNode.update(deltaTime, this.app.camera.node);
		}
	}



	getStyle() {
		dummyStyle = dummyStyle || new Style(new StyleModifier(new Object3D({ parent: null })));



		console.warn("This interface cannot be used for particle!");

		return dummyStyle;
	}



	/**

	 添加粒子组。
	 * @param {ParticleGroup} group 粒子组。
	 * @returns {ParticleGroup|undefined} 返回添加的粒子组。
	 * @public
	 * @example

	 * 	const group = new THING.ParticleGroup();

	 * 	particleSystem.addGroup(group);
	 */

	addGroup(group) {
		let node = group.node;



		if (!this.node) {
			return;
		}



		this.node.addGroup(node);



		this._updateGroups();



		return this.groups[this.groups.length - 1];
	}



	/**

	 移除粒子组。
	 * @param {ParticleGroup} group 粒子组。
	 * @public
	 * @example

	 * 	const groups = particleSystem.getGroups();

	 * 	particleSystem.removeGroup(groups[0]);
	 */

	removeGroup(group) {
		if (!this.node) {
			return;
		}



		if (this.groups.length == 0) {
			return;
		}



		this.node.removeGroup(group.node);

		this._updateGroups();
	}



	_updateGroups() {
		this._groups = [];



		const that = this;

		this.getGroups().forEach(node => {
			const group = new ParticleGroup({ node });

			that._groups.push(group);
		})
	}



	/**

	 Get group.
	 * @returns {Array<ParticleGroup>} 返回粒子组。
	 * @private
	 * @example

	 * 	const groups = particleSystem.getGroups();
	 */

	getGroups() {
		return this.node.getGroups();
	}



	/**

	 获取当前粒子系统的数据。
	 * @param {object} param { dataVersion2:false } 当dataVersion2为true时,获取ThingJS 2.0的数据。
	 * @returns {object} 粒子系统的数据
	 * @public
	 * @example

	 * 	const data = particleSystem.getParticleData({ dataVersion2:false });
	 */

	getParticleData(param) {
		return this.node.getParticleData(param);
	}



	/**

	 Set root path.
	 * @param {string} value 根路径。
	 * @private
	 */

	setRootPath(value) {
		this.node.setRootPath(value);
	}



	/**

	 Get root path.
	 * @returns {string} 返回根路径。
	 * @private
	 */

	getRootPath() {
		return this.node.getRootPath();
	}



	// #endregion



	// #region Resources



	/**

	 When load reosurce.
	 * @param {object} options The options to load.
	 * @param {Function} resolve The promise resolve callback function.
	 * @param {Function} reject The promise reject callback function.
	 * @private
	 */

	onLoadResource(options, resolve, reject) {
		if (!this.isDynamicLoad) {
			let app = this.app;

			options['screenSize'] = options['screenSize'] || app.size;

			options['maxVaryings'] = options['maxVaryings'] || app.renderCapabilities.maxVaryings;



			// Start to load particle resource

			let url = this.resource.url;

			if (url) {
				app.resourceManager.loadParticle(

					this.resource.url,

					(ev) => {
						if (this.destroyed) {
							return false;
						}

						else {
							this.body && this.body.setNode(ev.node);



							resolve();
						}
					},

					(ev) => {

					},

					(ev) => {
						reject(ev);
					},

					options

				);
			}

			// Load from data

			else if (options['data']) {
				let node = app.resourceManager.parseParticle(options['data'], options);

				if (node) {
					this.body && this.body.setNode(node);



					resolve();
				}

				else {
					reject(`Parse particle data failed`);
				}
			}

			else {
				// Create default particle

				const node = Utils.createObject('ParticleSystem', { app: this.app });

				const particleGroup = Utils.createObject('ParticleGroup', { app: this.app });

				const particleEmitter = Utils.createObject('ParticleEmitter', { app: this.app });

				node.addGroup(particleGroup);

				particleGroup.addEmitter(particleEmitter);

				this.body.setNode(node);



				resolve();
			}
		}

		else {
			resolve();
		}
	}



	// #endregion



	// #region Accessor



	/**

	 获取粒子组
	 * @type {Array<ParticleGroup>}
	 * @public
	 */

	get groups() {
		if (!this._groups) {
			this._updateGroups();
		}



		return this._groups;
	}



	// #endregion



	/**

	 检查是否为粒子系统类型或继承自粒子系统类型
	 * @type {boolean}
	 * @public
	 */

	get isParticleSystem() {
		return true;
	}



}



export { ParticleSystem }