import { StringEncoder, Callbacks, ObjectProxy } from '@uino/base-thing';
import { Utils } from '../common/Utils';
import { Object3D } from '../objects/Object3D';
import { RootObject } from '../objects/RootObject';
import { AmbientLight } from '../objects/AmbientLight';
import { DirectionalLight } from '../objects/DirectionalLight';
import { ImageTexture } from '../resources/ImageTexture';
import { ImageMappingType } from '../const';
import { CubeTexture } from '../resources/CubeTexture';

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


const _renderOverlayFuncName = StringEncoder.toText("<@secret renderOverlay>");
const _ClearColorBuffer = StringEncoder.toText("<@secret ClearColorBuffer>");

/**
 * @public
 * @class Scene
 * 场景对象,负责维护底层渲染场景、根节点、相机、灯光、环境贴图和渲染生命周期。
 * @memberof THING
 */
class Scene {

	/**
	 * 创建场景管理对象。
	 * @param {object} param 初始化参数
	 * @param {THING.App} param.app App 实例。
	 * @param {object} param.scene 底层渲染场景对象。
	 * @param {boolean} [param.initLights=true] 是否创建默认环境光和主方向光。
	 * @param {string|Array<string>|THING.CubeTexture|THING.ImageTexture} [param.envMap] 环境贴图。字符串可为全景图地址或立方体贴图目录,数组表示立方体贴图地址列表。
	 * @param {object} param.defaultSettings 默认设置。
	 */
	constructor(param = {}) {
		this[__.private] = {};
		let _private = this[__.private];

		_private.app = param['app'];
		_private.visible = true;
		_private.isDisposed = false;

		// Root objects
		_private.rootObjects = {};
		_private.scene = null;

		// Lights
		_private.ambientLight = null;
		_private.mainLight = null;

		// Environment
		_private.envMap = null;

		// Render options
		_private.instancedOffset = null;
		_private.renderOptions = null;

		// Camera
		_private.curCameraIndex = -1; // The current logic camera index
		_private.cameras = []; // [0]: main render camera

		// Callbacks
		_private.beforeRenderCallbacks = new Callbacks();
		_private.afterRenderCallbacks = new Callbacks();

		this._initScene(param);
		this._initLight(param);
		this._initRenderOptions();
		this._initEnvMap(param);

		// Enable static mode as default
		this.staticMode = true;
	}

	// #region Private

	/**
	 * 触发渲染前生命周期回调,并同步通知 App delegate 与底层场景。
	 * @param {number} deltaTime 距离上一帧的时间,单位为秒。
	 * @param {object} camera 当前用于主渲染的底层相机节点。
	 * @private
	 */
	_onBeforeRender(deltaTime, camera) {
		let _private = this[__.private];

		_private.beforeRenderCallbacks.invoke(deltaTime, camera);

		_private.app.delegate.onBeforeRender(camera);

		_private.scene.beforeRender(deltaTime);
	}

	/**
	 * 触发渲染后生命周期回调,并同步通知底层场景与 App delegate。
	 * @param {number} deltaTime 距离上一帧的时间,单位为秒。
	 * @param {object} camera 当前用于主渲染的底层相机节点。
	 * @private
	 */
	_onAfterRender(deltaTime, camera) {
		let _private = this[__.private];

		_private.scene.afterRender(deltaTime);

		_private.app.delegate.onAfterRender(camera);

		_private.afterRenderCallbacks.invoke(deltaTime, camera);
	}

	/**
	 * 初始化底层渲染场景、逻辑根对象以及 Overlay 专用根节点。
	 * @param {object} param 初始化参数。
	 * @param {object} param.scene 底层渲染场景对象。
	 * @private
	 */
	_initScene(param) {
		let _private = this[__.private];

		// Create scene
		_private.scene = param['scene'];

		// The scene root object
		_private.rootObjects['scene'] = new RootObject({
			name: 'scene-root',
			loaded: true,
			queryable: false
		});

		// Create logical root nodes
		let rootNodes = {
			'attachedPoint': Utils.createObject('Node', { app: _private.app }),
			'debug': Utils.createObject('Node', { app: _private.app }),
			'bodyBridge': Utils.createObject('Node', { app: _private.app })
		};

		// Create other logical root objects
		for (let key in rootNodes) {
			let rootName = key + '-root';

			let rootObject = new Object3D({
				rootNode: rootNodes[key],
				name: rootName,
				queryable: false,
				loaded: true,
				castShadow: false,
				receiveShadow: false
			});

			_private.rootObjects[key] = rootObject;
		}

		// Bind root objects
		let root = _private.scene.getRoot();
		for (let key in _private.rootObjects) {
			root.add(_private.rootObjects[key].node);
		}

		// Get overlay root node
		let getOverlayRootFunc = StringEncoder.toText("<@secret getOverlayRoot>");
		let overlayRoot = _private.scene[getOverlayRootFunc]();
		overlayRoot.setVisible(true);

		// Create overlay root node
		_private.overlayRootNode = Utils.createObject('Node', { app: _private.app });
		_private.overlayRootNode.setName(StringEncoder.toText("<@secret OverlayRoot>"));
		overlayRoot.add(_private.overlayRootNode);

		// Create overlay logo root node
		_private.overlayMarkerRootNode = Utils.createObject('Node', { app: _private.app });
		_private.overlayMarkerRootNode.setName(StringEncoder.toText("<@secret OverlayMarkerRoot>"));
		overlayRoot.add(_private.overlayMarkerRootNode);

		// Update accessors for internal usage
		_private.accessors = {};
		_private.accessors[StringEncoder.toText("<@secret overlayRootNode>")] = _private.overlayRootNode;
		_private.accessors[StringEncoder.toText("<@secret overlayMarkerRootNode>")] = _private.overlayMarkerRootNode;
	}

	/**
	 * 初始化场景默认灯光。
	 * @param {object} param 初始化参数。
	 * @param {boolean} [param.initLights=true] 是否创建默认灯光。
	 * @private
	 */
	_initLight(param) {
		let initLights = Utils.parseValue(param['initLights'], true);
		if (!initLights) {
			return;
		}

		let _private = this[__.private];

		let root = _private.rootObjects['scene'];

		// Create ambient light
		let ambientLight = new AmbientLight({
			parent: root,
			name: 'mainAmbientLight',
			tags: ['MainAmbientLight']
		});

		// Create main light
		let mainLight = new DirectionalLight({
			parent: root,
			name: 'mainDirectionalLight',
			target: [0, 0, 0],
			tags: ['MainDirectionalLight']
		});

		// Initialize adapater for main light as default
		let adapter = mainLight.adapter;
		if (_private.app.view._compatibleRender) {
			adapter.horzAngle = 30;
		}
		else {
			adapter.horzAngle = 40;
		}
		adapter.vertAngle = 30;
		adapter.bind(root);

		// Create lights finished
		this.ambientLight = ambientLight;
		this.mainLight = mainLight;
	}

	/**
	 * 初始化渲染配置代理,配置变更后会自动同步到底层场景。
	 * @private
	 */
	_initRenderOptions() {
		let _private = this[__.private];

		_private.renderOptions = new ObjectProxy({
			data: {
				environment: {
					quaternion: null
				},
			},
			onChange: function (ev) {
				if (_private.scene) {
					_private.scene.setRenderOptions(ev.data);
				}
			}
		});
	}

	/**
	 * 初始化环境贴图。未传入贴图且默认设置启用时,会加载视图提供的默认环境贴图。
	 * @param {object} param 初始化参数。
	 * @param {string|Array<string>|THING.CubeTexture|THING.ImageTexture} [param.envMap] 环境贴图配置。
	 * @private
	 */
	_initEnvMap(param) {
		const envMap = Utils.parseValue(param['envMap'], null);

		let _private = this[__.private];
		const app = _private.app;

		if (Utils.isArray(envMap)) {
			const imageTexture = new CubeTexture(envMap);
			this.envMap = imageTexture;
		}
		else if (Utils.isString(envMap)) {
			if ((envMap.indexOf('.png') > -1 || envMap.indexOf('.jpg') > -1)) {
				const imageTexture = new ImageTexture({
					url: envMap,
					mappingType: ImageMappingType.EquirectangularReflection
				});
				this.envMap = imageTexture;
			}
			else {
				const urls = Utils.parseCubeTextureUrlsByPath(envMap);
				const imageTexture = new ImageTexture(urls);
				this.envMap = imageTexture;
			}
		}
		else if (param.defaultSettings.envMap) {
			app.view.getDefaultEnvImage().then((envMap) => {
				if (envMap) {
					this.envMap = new CubeTexture({ data: envMap });
				}
			});
		}
	}

	// #endregion

	/**
	 * 销毁场景管理对象并释放根对象、Overlay 节点、渲染配置、底层场景和回调。
	 * @private
	 */
	dispose() {
		let _private = this[__.private];

		if (_private.overlayRootObject) {
			_private.overlayRootObject.destroy();
			_private.overlayRootObject = null;
		}

		_private.overlayRootNode.dispose();
		_private.overlayMarkerRootNode.dispose();
		_private.overlayRootNode = null;
		_private.overlayMarkerRootNode = null;
		_private.accessors = null;

		_private.app.objectManager.clearKeepAliveObjects();

		for (let key in _private.rootObjects) {
			_private.rootObjects[key].destroy(true);
		}

		_private.rootObjects = {};

		_private.renderOptions.dispose();
		_private.renderOptions = null;

		_private.scene.dispose();
		_private.scene = null;

		_private.ambientLight = null;
		_private.mainLight = null;

		_private.envMap = null;

		_private.curCameraIndex = -1;
		_private.cameras = [];

		_private.beforeRenderCallbacks.clear();
		_private.afterRenderCallbacks.clear();

		_private.isDisposed = true;
	}

	/**
	 * 调整场景内所有渲染相机和 Overlay 根对象尺寸。
	 * @param {number} width 视口宽度,单位为像素。
	 * @param {number} height 视口高度,单位为像素。
	 * @private
	 */
	resize(width, height) {
		let _private = this[__.private];

		_private.cameras.forEach(camera => {
			camera.resize(width, height);
		});

		if (_private.overlayRootObject) {
			_private.overlayRootObject.width = width;
			_private.overlayRootObject.height = height;
		}
	}

	/**
	 * 执行一帧渲染。
	 *
	 * 渲染顺序为:主相机、附加渲染相机、Overlay;无主相机时直接跳过。
	 * @param {number} deltaTime 距离上一帧的时间,单位为秒。
	 * @private
	 */
	render(deltaTime) {
		let _private = this[__.private];

		let cameras = _private.cameras;

		let mainCamera = cameras[0];
		if (!mainCamera) {
			return;
		}

		let mainCameraNode = mainCamera.node;

		// Prepare for rendering
		this._onBeforeRender(deltaTime, mainCameraNode);

		if (_private.visible) {
			// Render main camera
			if (mainCameraNode.getVisible()) {
				mainCameraNode.render();
			}

			// Render scene with other cameras
			for (let i = 1, l = cameras.length; i < l; i++) {
				let camera = cameras[i];

				if (!camera.visible) {
					continue;
				}

				// Render to texture
				if (camera.renderTexture) {
					camera.node.render(camera.renderTexture.getTextureResource());
				}
				// Render to viewport
				else if (camera.enableViewport && camera.viewport) {
					camera.node.render();
				}
			}

			// Render overlay
			if (_private.overlayRootNode && _private.overlayRootNode.getVisible()) {
				// We can not clear color buffer due to context use the same color buffer ...
				let clearColorBuffer = mainCameraNode.getAttribute(_ClearColorBuffer);
				mainCameraNode.setAttribute(_ClearColorBuffer, false);
				mainCameraNode[_renderOverlayFuncName]();
				mainCameraNode.setAttribute(_ClearColorBuffer, clearColorBuffer);
			}
		}

		// Finished for rendering
		this._onAfterRender(deltaTime, mainCameraNode);
	}

	/**
	 * 添加一个附加渲染相机。附加相机默认不清除颜色缓冲,便于渲染到纹理或指定视口。
	 * @param {THING.Camera} camera 相机对象。
	 * @private
	 */
	addRenderCamera(camera) {
		let _private = this[__.private];
		let cameras = _private.cameras;

		// For other render camera, we are not going to clear color buffer as default
		let cameraNode = camera.node;
		cameraNode.setAttribute(_ClearColorBuffer, false);

		let mainCamera = cameras[_private.curCameraIndex];

		Utils.pushToArray(cameras, camera);

		_private.curCameraIndex = cameras.indexOf(mainCamera);
	}

	/**
	 * 移除一个附加渲染相机,并保持当前逻辑相机索引不变。
	 * @param {THING.Camera} camera 相机对象。
	 * @private
	 */
	removeRenderCamera(camera) {
		let _private = this[__.private];
		let cameras = _private.cameras;

		let mainCamera = cameras[_private.curCameraIndex];

		Utils.removeFromArray(cameras, camera);

		_private.curCameraIndex = cameras.indexOf(mainCamera);
	}

	/**
	 * 渲染生命周期回调。
	 * @callback OnRenderCallback
	 * @param {number} deltaTime 距离上一帧的时间,单位为秒。
	 * @param {object} camera 当前用于主渲染的底层相机节点。
	 * @private
	 */

	/**
	 * 添加渲染前回调。
	 * @param {OnRenderCallback} callback 回调函数。
	 * @private
	 */
	addBeforeRenderCallback(callback) {
		this[__.private].beforeRenderCallbacks.add(callback);
	}

	/**
	 * 移除渲染前回调。
	 * @param {OnRenderCallback} callback 回调函数。
	 * @private
	 */
	removeBeforeRenderCallback(callback) {
		this[__.private].beforeRenderCallbacks.remove(callback);
	}

	/**
	 * 添加渲染后回调。
	 * @param {OnRenderCallback} callback 回调函数。
	 * @private
	 */
	addAfterRenderCallback(callback) {
		this[__.private].afterRenderCallbacks.add(callback);
	}

	/**
	 * 移除渲染后回调。
	 * @param {OnRenderCallback} callback 回调函数。
	 * @private
	 */
	removeAfterRenderCallback(callback) {
		this[__.private].afterRenderCallbacks.remove(callback);
	}

	/**
	 * 根据内部类型标识获取场景属性。
	 * @param {string} type 内部类型标识。
	 * @returns {*} 对应的内部对象;无法匹配时返回 null。
	 * @private
	 */
	getAttribute(type) {
		const overlayRootObject = StringEncoder.toText("<@secret OverlayRootObject>");
		const accessors = StringEncoder.toText("<@secret Accessors>");

		let _private = this[__.private];

		switch (type) {
			case overlayRootObject:
				if (!_private.overlayRootObject) {
					let app = _private.app;

					_private.overlayRootObject = new Object3D({
						name: StringEncoder.toText("<@secret overlayRoot>"),
						rootNode: _private.overlayRootNode,
						parent: null,
						queryable: false,
					});

					_private.overlayRootObject.x = 0;
					_private.overlayRootObject.y = 0;
					_private.overlayRootObject.width = app.size[0];
					_private.overlayRootObject.height = app.size[1];
				}

				return _private.overlayRootObject;

			case accessors:
				return _private.accessors;

			default:
				return null;
		}
	}

	// #region Accessor

	/**
	 * 获取底层场景根节点。
	 * @type {object}
	 * @private
	 */
	get root() {
		return this[__.private].scene.getRoot();
	}

	/**
	 * 获取场景逻辑根对象集合。
	 * @type {object}
	 * @private
	 */
	get rootObjects() {
		return this[__.private].rootObjects;
	}

	/**
	 * 获取场景渲染相机列表。数组第 0 项为主渲染相机。
	 * @type {Array<THING.Camera>}
	 * @public
	 */
	get cameras() {
		return this[__.private].cameras;
	}

	/**
	 * 获取/设置当前逻辑相机。
	 * 设置后会同时将该相机设为主渲染相机。
	 * @type {THING.Camera}
	 * @public
	 */
	get camera() {
		let _private = this[__.private];

		return _private.cameras[_private.curCameraIndex];
	}
	set camera(value) {
		let _private = this[__.private];

		let index = _private.cameras.indexOf(value);
		if (index === -1) {
			_private.cameras.push(value);

			index = _private.cameras.length - 1;
		}

		_private.curCameraIndex = index;

		// Use camera as render camera
		this.renderCamera = value;

		// Keep it alive
		_private.app.objectManager.addKeepAliveObject(value);
	}

	/**
	 * 获取/设置主渲染相机。
	 *
	 * 主渲染相机固定在相机列表第 0 项,并负责渲染到主视口。
	 * @type {THING.Camera}
	 * @private
	 */
	get renderCamera() {
		let _private = this[__.private];

		return _private.cameras[0];
	}
	set renderCamera(value) {
		let _private = this[__.private];
		let cameras = _private.cameras;

		let mainCamera = cameras[_private.curCameraIndex];

		// Disable previous main camera render to viewport
		let mainRenderCamera = cameras[0];
		if (mainRenderCamera && mainRenderCamera != value) {
			mainRenderCamera.enableViewport = false;
		}

		let index = cameras.indexOf(value);
		if (index === -1) {
			cameras._insert(0, value);
		}
		else if (index !== 0) {
			cameras._swap(0, index);
		}

		_private.curCameraIndex = cameras.indexOf(mainCamera);

		// Enable render to viewport
		value.enableViewport = true;
	}

	/**
	 * 获取/设置实例化绘制偏移量,会影响所有实例化绘制对象的相对位置。
	 * @type {Array<number>}
	 * @example
	 * 	app.scene.instancedOffset = [10000, 10000, 10000];
	 * @public
	 */
	get instancedOffset() {
		let _private = this[__.private];

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

		if (value) {
			_private.instancedOffset = value.slice(0);

			this.root.setInstancedOffset(_private.instancedOffset);
		}
		else {
			_private.instancedOffset = null;

			this.root.setInstancedOffset([0, 0, 0]);
		}
	}

	/**
	 * 获取/设置静态模式,用于开启或关闭变换矩阵缓存以优化矩阵计算。
	 *
	 * 加载资源时通常关闭,预览渲染时再开启。
	 * @type {boolean}
	 * @public
	 */
	get staticMode() {
		let _private = this[__.private];

		return _private.scene.isEnabled('TransformCache');
	}
	set staticMode(value) {
		let _private = this[__.private];

		_private.scene.enable('TransformCache', value);
	}

	/**
	 * 获取/设置 环境贴图资源。
	 * @type {THING.CubeTexture|THING.ImageTexture}
	 * @public
	 */
	get envMap() {
		let _private = this[__.private];

		return _private.envMap;
	}

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

		if (_private.envMap) {
			_private.envMap.release();
		}

		if (value) {
			if (value.isImageTexture || value.isCubeTexture) {
				_private.envMap = value;
				_private.envMap.addRef();

				_private.envMap.waitForComplete().then((image) => {
					if (_private.isDisposed) {
						return;
					}
					scene.setEnvironment(image.getTextureResource());
				});
			}
			// Image url of String type
			else if (Utils.isString(value)) {
				_private.envMap = new ImageTexture(value);
				_private.envMap.mappingType = ImageMappingType.EquirectangularReflection;

				_private.envMap.waitForComplete().then((image) => {
					if (_private.isDisposed) {
						return;
					}
					scene.setEnvironment(image.getTextureResource());
				});
			}
			else {
				_private.envMap = null;
				scene.setEnvironment(null);
			}
		}
		else {
			_private.envMap = null;
			scene.setEnvironment(null);
		}
	}

	/**
	 * 获取/设置环境光照强度,取值范围为0到1。
	 * @type {number}
	 * @public
	 * @example
	 * 	app.scene.envMapLightIntensity = 0.5;
	 * 	// @expect(app.scene.envMapLightIntensity == 0.5);
	 */
	get envMapLightIntensity() {
		Utils.warn('Please use envDiffuseIntensity instead');
		let _private = this[__.private];
		return _private.scene.getEnvDiffuseIntensity();
	}
	set envMapLightIntensity(value) {
		Utils.warn('Please use envDiffuseIntensity instead');
		let _private = this[__.private];
		_private.scene.setEnvDiffuseIntensity(value);
	}

	/**
	 * 获取/设置环境漫反射强度,取值范围为0到1。
	 * @type {number}
	 * @public
	 * @example
	 * 	app.scene.envDiffuseIntensity = 0.5;
	 * 	// @expect(app.scene.envDiffuseIntensity == 0.5);
	 */
	get envDiffuseIntensity() {
		let _private = this[__.private];
		return _private.scene.getEnvDiffuseIntensity();
	}
	set envDiffuseIntensity(value) {
		let _private = this[__.private];
		_private.scene.setEnvDiffuseIntensity(value);
	}

	/**
	 * 获取/设置环境镜面反射强度,取值范围为0到1。
	 * @type {number}
	 * @public
	 * @example
	 * 	app.scene.envSpecularIntensity = 0.5;
	 * 	// @expect(app.scene.envSpecularIntensity == 0.5);
	 */
	get envSpecularIntensity() {
		let _private = this[__.private];
		return _private.scene.getEnvSpecularIntensity();
	}
	set envSpecularIntensity(value) {
		let _private = this[__.private];
		_private.scene.setEnvSpecularIntensity(value);
	}

	/**
	 * 获取/设置场景默认环境光。
	 * @type {THING.AmbientLight}
	 * @public
	 * @example
	 * 	let app = THING.App.current;
	 * 	app.scene.ambientLight.color = 'blue';
	 * 	app.scene.ambientLight.intensity = 0.1;
	 *  let ret1 = app.scene.ambientLight.color == 'blue';
	 *  let ret2 = app.scene.ambientLight.intensity == 0.1;
	 * // @expect(ret1 == true && ret2 == true);
	 */
	get ambientLight() {
		return this[__.private].ambientLight;
	}
	set ambientLight(value) {
		let _private = this[__.private];

		_private.ambientLight = value;

		// Keep it alive to prevent destroy action
		_private.app.objectManager.addKeepAliveObject(value);
	}

	/**
	 * 获取/设置场景主平行光。
	 * @type {THING.DirectionalLight}
	 * @public
	 */
	get mainLight() {
		return this[__.private].mainLight;
	}
	set mainLight(value) {
		let _private = this[__.private];

		_private.mainLight = value;

		// Keep it alive to prevent destroy action
		_private.app.objectManager.addKeepAliveObject(value);
	}

	/**
	 * @typedef {object} SceneRenderEnvironmentOptions
	 * @property {Array<number>} quaternion 环境贴图旋转四元数。
	 * @public
	 */

	/**
	 * @typedef {object} SceneRenderOptions
	 * @property {SceneRenderEnvironmentOptions} environment 环境渲染配置。
	 * @public
	 */

	/**
	 * 获取/设置渲染配置。
	 * @type {SceneRenderOptions}
	 * @public
	 */
	get renderOptions() {
		let _private = this[__.private];

		return _private.renderOptions.dataProxy;
	}
	set renderOptions(value) {
		let _private = this[__.private];
		let scene = _private.scene;
		let dataProxy = _private.renderOptions.dataProxy;

		if (value) {
			Utils.mergeObject(dataProxy, value, true);

			scene.setRenderOptions(dataProxy);
		}
		else {
			dataProxy.environment.quaternion = null;

			scene.setRenderOptions(dataProxy);
		}
	}

	/**
	 * 获取当前渲染状态。
	 * @type {RenderStateResult}
	 * @private
	 */
	get renderState() {
		let _private = this[__.private];

		return _private.scene.getRenderState();
	}

	/**
	 * @public
	 * 获取/设置输出颜色编码类型。
	 * @type {TexelEncodingType}
	 */
	get outputEncodingType() {
		let _private = this[__.private];

		return _private.scene.getOutputEncodingType();
	}
	set outputEncodingType(value) {
		let _private = this[__.private];

		_private.scene.setOutputEncodingType(value);
	}


	/**
	 * @public
	 * 获取/设置最大灯光分组数量。
	 * @type {number}
	 */
	get maxLightingGroupCount() {
		let _private = this[__.private];

		return _private.scene.getMaxLightingGroupCount();
	}
	set maxLightingGroupCount(value) {
		let _private = this[__.private];

		_private.scene.setMaxLightingGroupCount(value);
	}

	/**
	 * 获取/设置场景是否参与主渲染。
	 * @type {boolean}
	 * @public
	 */
	get visible() {
		let _private = this[__.private];

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

		_private.visible = value;
	}

	/**
	 * 获取底层渲染场景对象。
	 * @type {object}
	 * @private
	 */
	get context() {
		let _private = this[__.private];

		return _private.scene;
	}

	// #endregion

	/**
	 * 标识当前对象为 Scene 实例。
	 * @type {boolean}
	 * @readonly
	 */
	get isScene() {
		return true;
	}

}

export { Scene }