import { Flags, ObjectProxy } from '@uino/base-thing';
import { MathUtils } from '../math/MathUtils';
import { Utils } from '../common/Utils'
import { Selector } from '../selector/Selector';
import { DynamicSelector } from '../selector/DynamicSelector';
import { BaseComponentGroup } from '../components/BaseComponentGroup';
import { EventType, InheritType } from '../const';
import { Tags } from '../common/Tags';

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

const Flag = {
	Destroyed: 1 << 0,
	Dirty: 1 << 1,
	Queryable: 1 << 2,
	Destroyable: 1 << 3,
}

let _orderId = 1;
let _dummySelector = new Selector();
let _eventListeners = [];
let _defaultParams = {};

// #region Private Functions



// #endregion

/**
 * @class BaseObject
 * ThingJS中最基础的对象
 * @memberof THING
 * @extends THING.BaseComponentGroup
 * @public
 */
class BaseObject extends BaseComponentGroup {

	static defaultTagArray = ['BaseObject'];


	/**
	 * 基础对象类,负责 ThingJS 中最基础的对象功能实现。
	 * ⚠️ 不建议直接 new 该类,推荐通过 THING.Object3D 或其子类来创建实例。
	 * @param {object} param 初始化 BaseObject 的属性
	 * @param {string} [param.name=''] 物体名称
	 * @param {string} [param.id=''] 物体 id
	 * @param {string} [param.uuid] 物体唯一标识,如果不传会自动生成唯一字符串
	 * @param {object} [param.userData] 设置/获取物体的自定义属性
	 * @param {boolean} [param.queryable=true] 物体是否可被查询,默认 true
	 * @param {boolean} [param.destroyable=true] 物体是否可被销毁,默认 true
	 */
	constructor(param = {}) {
		super();

		this[__.private] = {};
		let _private = this[__.private];

		this.onSetupApp(param);

		// Common
		_private.tags = null;
		_private.userData = null;
		_private.internalData = null;
		_private.type = '';
		_private.dtType = ''; // Add dtType for digital twin type

		// Temporary Data
		_private.tempData = null;

		// Update internal order ID for fast searching
		_private.orderId = _orderId++;

		// Relation
		_private.parent = null;
		_private.children = null;

		// The proxy object
		_private.proxyObject = null;

		// Show important info what we can not wrap into private space, so bind to object
		this._name = Utils.parseValue(param['name'], '');
		this._id = Utils.parseValue(param['id'], '');
		this._uuid = param['uuid'] || MathUtils.generateUUID();

		// Setup flags
		this._flags = new Flags();
		this._flags.enable(Flag.Queryable, Utils.parseValue(param['queryable'], true));
		this._flags.enable(Flag.Destroyable, Utils.parseValue(param['destroyable'], true));

		// Setup type first, because we need type attribute
		this.onSetupType(param);

		// Setup
		this.onBeforeSetup(param);
		this.onSetupFlags(param);
		this.onSetupTags(param);
		this.onSetupParent(param); // Set parent first to make sure parent order ID is valid
		this.onSetupAsyncSelector(param); // Add object first to make sure object order ID is valid
		this.onSetupUserData(param);
		this.onSetupInternalData(param)
		this.onAfterSetup(param);

		// Add object into manager
		_private.app.objectManager.addObject(this);
	}

	// #region Private

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

		// Remove it from previous parent
		if (_private.parent) {
			let children = _private.parent.children;
			let index = children.indexOf(this);
			if (index !== -1) {
				children.removeAt(index);
			}

			_private.parent = null;
		}
	}

	_addEventListener(type, condition, callback, tag, priority, options, once = false) {
		let info = Utils.parseEvent(type, condition, callback, tag, priority, options, this.onInitEventArgs);
		if (this.onParseEvent(info)) {
			let app = this.app || Utils.getCurrentApp();
			return app.eventManager.addEventListener(info.type.toLowerCase(), this, info.condition, info.callback, info.tag, {
				once,
				priority: info.priority,
				propagate: info.propagate,
				useCapture: info.useCapture,
				enumerable: info.enumerable,
				pausable: info.pausable,
				includeSelf: info.includeSelf
			});
		}

		return null;
	}

	_getEventListener(type, condition, tag) {
		return this.app.eventManager.getEventListener(type.toLowerCase(), this, condition, tag);
	}

	_removeEventListener(type, condition, tag) {
		this.app.eventManager.removeEventListener(type.toLowerCase(), this, condition, tag);
	}

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

		let userData = _private.userData;
		if (userData) {
			return userData;
		}

		if (Selector.asyncSelector) {
			_private.userData = new ObjectProxy({
				onChange: (ev) => {
					Selector.updateObjectAttribute(this, 'userData', ev.data);
				}
			});
		}
		else {
			_private.userData = {};
		}

		return _private.userData;
	}

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

		if (!_private.internalData) {
			_private.internalData = {};
		}

		return _private.internalData;
	}

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

		if (!_private.tempData) {
			_private.tempData = {
				tickableCounter: 0,
				resizableCounter: 0,
			};

			if (callback) {
				callback(_private.tempData);
			}
		}

		return _private.tempData;
	}

	_getParentObject(param) {
		let parent = param['parent'];
		if (parent === null) {
			return null;
		}

		return parent || this.app.root;
	}

	_isExpression(condition) {
		// It's string format
		if (condition._startsWith('"') || condition._startsWith('\'')) {
			return true;
		}

		// It's id format
		if (condition._startsWith('#')) {
			return true;
		}

		// It's type format
		if (condition._startsWith('.')) {
			return true;
		}

		// It's attribute name
		if (condition._startsWith('[') && condition._endsWith(']')) {
			return true;
		}

		// Has OR operator
		if (condition.indexOf('||') !== -1 || condition.indexOf('|') !== -1) {
			return true;
		}

		// Has AND operator
		if (condition.indexOf('&&') !== -1 || condition.indexOf('&') !== -1) {
			return true;
		}

		// It's tags format
		if (condition._startsWith('tags')) {
			if (condition[4] === ':' || condition[4] === '(') {
				return true;
			}
		}

		return false;
	}

	// #endregion

	// #region Overrides

	onSetupApp(param) {
		const _private = this[__.private];

		// Setup app
		const parent = param['parent']
		if (parent && parent.app) {
			_private.app = parent.app;
		}
		else {
			_private.app = param['app'] || Utils.getCurrentApp();
		}
	}

	onAddTickableObject() {
		let tempData = this._getTempData();
		if (tempData['tickableCounter'] === 0) {
			this.app.objectManager.addTickableObject(this);
		}

		tempData['tickableCounter']++;
	}

	onAddResizableObject() {
		let tempData = this._getTempData();
		if (tempData['resizableCounter'] === 0) {
			this.app.objectManager.addResizableObject(this);
		}

		tempData['resizableCounter']++;
	}

	onRemoveTickableObject() {
		let tempData = this._getTempData();

		tempData['tickableCounter']--;
		if (tempData['tickableCounter'] === 0) {
			this.app.objectManager.removeTickableObject(this);
		}
	}

	onRemoveResizableObject() {
		let tempData = this._getTempData();

		tempData['resizableCounter']--;
		if (tempData['resizableCounter'] === 0) {
			this.app.objectManager.removeResizableObject(this);
		}
	}

	// #endregion

	// #region Setup
	onSetupFlags(param) {

	}

	onBeforeSetup(param) {
	}

	onAfterSetup(param) {
	}

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

		let prototype = this.__proto__;

		let className = Utils.getClassNameFromProto(prototype);
		_private.type = className;
		_private.dtType = param['dtType'] || ''; // Initialize dtType from param

		let selfClassKey = 'is' + className;
		if (this.selfClassKey == undefined) {
			Object.defineProperty(this, selfClassKey, {
				enumerable: false,
				configurable: false,
				get() {
					return true;
				},
			});
		}

		// Check whether we had processed yet
		prototype.__inherits = prototype.__inherits || {};
		if (prototype.__inherits[className]) {
			return;
		}

		// The types of each class to get inherition
		prototype.__inherits[className] = {
			types: {}
		};

		// Get the class names
		let classNames;
		let app = this.app;
		if (app) {
			classNames = app.global.getClassNamesFromObject(this);
		}
		else {
			let proto = this.__proto__;
			classNames = [Utils.getClassNameFromProto(proto)];
		}

		classNames.forEach(name => {
			prototype.__inherits[className].types[name] = true;

			let key = 'is' + name;

			if (!this[key]) {
				Object.defineProperty(prototype, key, {
					enumerable: false,
					configurable: false,
					get() {
						return prototype.__inherits[className].types[name];
					},
				});
			}
		});
	}

	onSetupParent(param) {
		let parent = this._getParentObject(param);
		if (!parent) {
			return;
		}
		const indexOfParent = param['indexOfParent'];
		parent.add(this, { attachMode: false, indexOfParent });
	}

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

		// Setup tags
		if (param['tags'] === undefined) {
			const defaultTags = this.onGetDefaultTags();
			_private.tags = new Tags(Utils.mergeSet(param['tags'], defaultTags));
		}
		else {
			_private.tags = new Tags(param['tags']);
		}
	}

	onGetDefaultTags() {
		return this.constructor.defaultTagArray;
	}

	onSetupAsyncSelector(param) {
		// Add into async selector
		Selector.addObject(this);
	}

	onSetupUserData(param) {
		let fromUserData = param['userData'];
		if (!fromUserData) {
			return;
		}

		let toUserData = this._getUserData();
		if (toUserData.isObjectProxy) {
			toUserData.copy(fromUserData);
		}
		else {
			Object.assign(toUserData, fromUserData);
		}
	}
	onSetupInternalData(param) {
		let fromInternalData = param['internalData'];
		if (!fromInternalData) {
			return;
		}

		let toInternalData = this._getInternalData();
		Object.assign(toInternalData, fromInternalData);
	}
	// #endregion

	// #region Overrides

	/**
	 * When update.
	 * @param {number} deltaTime The delta time in seconds.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.onUpdate = function(deltaTime) {
	 *   console.log(deltaTime);
	 * };
	 */
	onUpdate(deltaTime) {
		let tickableComponents = this.tickableComponents;
		if (tickableComponents) {
			for (let i = 0, l = tickableComponents.length; i < l; i++) {
				let component = tickableComponents[i];
				if (component.active === false) {
					continue;
				}

				component.onUpdate(deltaTime);
			}
		}
	}

	/**
	 * When resize.
	 * @param {number} width The width in pixel.
	 * @param {number} height The height in pixel.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.onResize = function(width, height) {
	 *   console.log(width, height);
	 * };
	 */
	onResize(width, height) {
		let resizableComponents = this.resizableComponents;
		if (resizableComponents) {
			for (let i = 0, l = resizableComponents.length; i < l; i++) {
				let component = resizableComponents[i];

				component.onResize(width, height);
			}
		}
	}

	/**
	 * When refresh.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.onRefresh = function() {
	 *   console.log('refresh');
	 * };
	 */
	onRefresh() {
		let refreshableComponents = this.refreshableComponents;
		if (refreshableComponents) {
			for (let i = 0, l = refreshableComponents.length; i < l; i++) {
				let component = refreshableComponents[i];

				component.onRefresh();
			}
		}

		this._flags.enable(Flag.Dirty, false);
	}

	/**
	 * When before destroy.
	 * @returns {boolean} false indicates break the destroy operation.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.onBeforeDestroy = function() {
	 *   console.log('before destroy');
	 *   return false;
	 * };
	 */
	onBeforeDestroy() {
		let flags = this._flags;

		// Check whether can be destroyed
		if (!flags.has(Flag.Destroyable)) {
			return false;
		}

		// Check whether had destroyed
		if (flags.has(Flag.Destroyed)) {
			return false;
		}

		return true;
	}

	/**
	 * When destroy.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.onDestroy = function() {
	 *   console.log('destroy');
	 * };
	 */
	onDestroy() {
		let _private = this[__.private];

		// Notify it's going to destroy it
		this.trigger(EventType.Destroy);

		// Remove all children
		if (_private.children) {
			let children = _private.children.slice(0);
			children.forEach(child => {
				child.destroy();
			});

			_private.children.clear();
		}

		// Notify parent to remove child object
		let parent = _private.parent;
		if (parent) {
			parent.onBeforeRemoveChild(this);

			this.onSetParent(null);

			parent.onAfterRemoveChild(this);
		}

		// Remove it from object manager
		_private.app.objectManager.removeObject(this);
		_private.app.objectManager.removeTickableObject(this);
		_private.app.objectManager.removeResizableObject(this);

		// Remove it from async selector
		Selector.removeObject(this);

		// Remove all components
		this.removeAllComponents(true);

		// Clear all accessor info
		this.clearAccessorInfo();

		// Clear user data
		let userData = _private.userData;
		if (userData) {
			if (userData.isObjectProxy) {
				userData.dispose();
			}

			_private.userData = null;
		}

		// We must clear parent here, due to 'AfterDestroy' event need to check parent object
		_private.parent = null;

		// Remove all events of it
		_private.app.eventManager.removeAllEventListeners(this);

		// Make it destroyed, be careful:
		// We must set the destroy flag after object manager remove it to prevent 'Destroy' event trigger failed
		this._flags.enable(Flag.Destroyed, true);
	}

	/**
	 * When after destroy.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.onAfterDestroy = function() {
	 *   console.log('after destroy');
	 * };
	 */
	onAfterDestroy() {
		let _private = this[__.private];

		// Remove it from previous parent
		this._removeFromParent();

		// Resume all paused events
		// _private.app.eventManager.resumeAllEvents(this);

		_private.app = null;
	}

	onParseEvent(info) {
		return true;
	}

	onBeforeAddChild(object) {
		// Notify all components
		let components = this.components;
		components.forEach((component) => {
			if (component.onBeforeAddChild) {
				component.onBeforeAddChild(object);
			}
		})

		this.trigger(EventType.BeforeAddChild, { child: object });
	}

	onAddChild(object, options) {
		object.onSetParent(this, options);
	}

	onAfterAddChild(object) {
		// Notify all components
		let components = this.components;
		components.forEach((component) => {
			if (component.onAfterAddChild) {
				component.onAfterAddChild(object);
			}
		})

		this.trigger(EventType.AfterAddChild, { child: object });
	}

	onBeforeRemoveChild(object) {
		// Notify all components
		let components = this.components;
		components.forEach((component) => {
			if (component.onBeforeRemoveChild) {
				component.onBeforeRemoveChild(object);
			}
		})

		this.trigger(EventType.BeforeRemoveChild, { child: object });
	}

	onAfterRemoveChild(object) {
		// Notify all components
		let components = this.components;
		components.forEach((component) => {
			if (component.onAfterRemoveChild) {
				component.onAfterRemoveChild(object);
			}
		})

		this.trigger(EventType.AfterRemoveChild, { child: object });
	}

	// #endregion

	// #region BaseComponentGroup Interfaces

	onAddComponent(component, args) {
		super.onAddComponent(component, args);

		if (component.onUpdate || component.onRender) {
			this.onAddTickableObject();
		}

		if (component.onResize) {
			this.onAddResizableObject();
		}
	}

	onRemoveComponent(component) {
		super.onRemoveComponent(component);

		if (component.onUpdate || component.onRender) {
			this.onRemoveTickableObject();
		}

		if (component.onResize) {
			this.onRemoveResizableObject();
		}
	}

	onBeforeSetParent() {

	}

	// #endregion

	// #region Common

	/**
	 * 检查是否含有属性名为name的属性
	 * @param {string} name 属性名称,支持嵌套,例如查询object.a.b.c 可以使用object.hasAttribute('a/b/c')
	 * @param {string} separator 分隔符,默认是'/'
	 * @returns {boolean} 返回一个布尔值,表示是否存在指定的属性
	 * @example
	 * let object = new THING.BaseObject();
	 * object.userData['power'] = 100;
	 * let ret = object.hasAttribute('userData/power');
	 * // @expect(ret == true)
	 * @public
	 */
	hasAttribute(name, separator = '/') {
		return Utils.hasAttribute(this, name, separator);
	}

	/**
	 * 根据name获取属性值
	 * @param {string} key 属性名称,支持嵌套,例如获取object.a.b.c 可以使用object.getAttribute('a/b/c')
	 * @param {string} separator 分隔符,默认是'/'
	 * @returns {*} 返回指定属性的值
	 * @example
	 * let object = new THING.BaseObject();
	 * object.userData['power'] = 100;
	 * let power = object.getAttribute('userData/power');
	 * // @expect(power == 100)
	 * @public
	 */
	getAttribute(key, separator = '/') {
		return Utils.getAttribute(this, key, separator);
	}

	/**
	 * 设置属性名称为key的属性值
	 * @param {string} key 属性名称,支持嵌套,例如设置object.a.b.c=1 可以使用object.setAttribute('a/b/c',1)
	 * @param {*} value 属性值
	 * @param {string} separator 分隔符,默认是'/'
	 * @example
	 * let object = new THING.BaseObject();
	 * object.setAttribute('userData/power', 200);
	 * let power = object.getAttribute('userData/power');
	 * // @expect(power == 200)
	 * @public
	 */
	setAttribute(key, value, separator = '/') {
		Utils.setAttribute(this, key, value, separator);
	}

	/**
	 * 设置属性
	 * @param {object} attributes 属性对象
	 * @param {boolean} [overwrite=true] 是否覆盖
	 * @param {string} separator 分隔符,默认是'/'
	 * @example
	 * let object = new THING.BaseObject();
	 * object.setAttributes({
	 *   "userData/name": 'Mr.Door',
	 *   "userData/age": 18
	 * })
	 * let name = object.getAttribute('userData/name');
	 * // @expect(name == 'Mr.Door')
	 * let age = object.getAttribute('userData/age');
	 * // @expect(age == 18)
	 * @public
	 */
	setAttributes(attributes = {}, overwrite = true, separator = '/') {
		for (let key in attributes) {
			if (!overwrite && !Utils.isUndefined(this.getAttribute(key))) {
				continue;
			}

			this.setAttribute(key, attributes[key], separator);
		}

		this.trigger(EventType.ChangeAttributes, { attributes });
	}

	/**
	 * 获取app对象
	 * @type {THING.App}
	 * @example
	 * let object = new THING.BaseObject();
	 * let app = object.app;
	 * let ret = app == THING.App.current;
	 * // @expect(ret == true)
	 * @public
	 */
	get app() {
		return this[__.private].app;
	}

	/**
	 * 获取类型
	 * @type {string}
	 * @example
	 * let object = new THING.BaseObject();
	 * let type = object.type;
	 * // @expect(type == 'BaseObject')
	 * @public
	 */
	get type() {
		return this[__.private].type;
	}

	/**
	 * 设置/获取 孪生体类型
	 * @type {string}
	 * @example
	 * let object = new THING.BaseObject();
	 * object.dtType = 'Equipment';
	 * // @expect(object.dtType == 'Equipment')
	 * @public
	 */
	get dtType() {
		return this[__.private].dtType;
	}
	set dtType(value) {
		this[__.private].dtType = value;
		Selector.updateObjectAttribute(this, 'dtType', value);
	}

	/**
	 * Get order ID.
	 * @type {number}
	 * @private
	 */
	get orderId() {
		return this[__.private].orderId;
	}

	/**
	 * 设置/获取 物体名称
	 * @type {string}
	 * @example
	 * let object = new THING.BaseObject();
	 * // @expect(object.name == '');
	 * object.name = 'car';
	 * // @expect(object.name == 'car');
	 * @public
	 */
	get name() {
		return this._name;
	}
	set name(value) {
		this._name = value;

		Selector.updateObjectAttribute(this, 'name', value);
	}

	/**
	 * 设置/获取 物体id
	 * @type {string}
	 * @example
	 * let object = new THING.BaseObject();
	 * object.id = 'DEVICE_007';
	 * // @expect(object.id == 'DEVICE_007')
	 * @public
	 */
	get id() {
		return this._id;
	}
	set id(value) {
		this._id = value;

		Selector.updateObjectAttribute(this, 'id', value);
	}

	/**
	 * 设置/获取 物体的唯一标识
	 * @type {string}
	 * @example
	 * let object = new THING.BaseObject({uuid: 10000});
	 * // @expect(object.uuid == 10000)
	 * object.uuid = THING.Math.generateUUID();
	 * // @expect(object.id != 10000)
	 * @public
	 */
	get uuid() {
		return this._uuid;
	}
	set uuid(value) {
		if (this._uuid != value) {
			this.app.objectManager.removeObject(this);
			this._uuid = value;
			this.app.objectManager.addObject(this);
			Selector.updateObjectAttribute(this, 'uuid', value);
		}
	}

	/**
	 * 设置/获取 物体标签
	 * @type {Set<string>}
	 * @example
	 *  // Get tags
	 * 	let tags = object.tags;
	 *  console.log(tags);
	 *
	 *  // Set tags by array
	 *  object.tags = ['one','two','three'];
	 *
	 *  // Set tags by set
	 *  object.tags = new Set(['one','two','three']);
	 * @public
	 */
	get tags() {
		let _private = this[__.private];
		_private.tags = _private.tags || new Tags();
		return _private.tags;
	}
	set tags(value) {
		if (Utils.isArray(value) || Utils.isSet(value)) {
			const tags = this.tags;
			tags.clear();

			value.forEach(element => {
				tags.add(element);
			});
		}
	}

	/**
	 * 设置/获取 物体的自定义属性
	 * @type {object}
	 * @example
	 * let object = new THING.BaseObject();
	 * object.userData['Notebook'] = {
	 * 	name: 'FlyingCar',
	 * 	price: 100
	 * };
	 * let name = object.userData['Notebook'].name;
	 * // @expect(name == 'FlyingCar')
	 * let price = object.userData['Notebook'].price
	 * // @expect(price == 100)
	 * @public
	 */
	get userData() {
		let userData = this._getUserData();

		if (userData.isObjectProxy) {
			return userData.dataProxy;
		}
		else {
			return userData;
		}
	}
	set userData(value) {
		let userData = this._getUserData();
		if (userData.isObjectProxy) {
			userData.copy(value);
		}
		else {
			Utils.copyObject(userData, value);
		}
	}

	get internalData() {
		return this._getInternalData();
	}
	set internalData(value) {
		let internalData = this.internalData;
		Utils.copyObject(internalData, value);
	}

	// #endregion

	// #region Inherit

	hasInherit() {
		return false;
	}

	// #region Traverse

	traverseInheritance(callback, onGetInheritance, jumpSelf) {
		if (!jumpSelf) {
			callback(this);
		}

		if (this.hasChildren()) {
			let children = this.children;
			for (let i = 0, l = children.length; i < l; i++) {
				let child = children[i];

				let inheritance = onGetInheritance(child);
				switch (inheritance) {
					case InheritType.Normal:
						child.traverseInheritance(callback, onGetInheritance);
						break;

					case InheritType.Break:
						callback(child);
						break;

					case InheritType.Jump:
						child.traverseInheritance(callback, onGetInheritance, true);
						break;

					case InheritType.Stop:
						break;

					default:
						break;
				}
			}
		}
	}

	// #endregion

	// #endregion

	// #region State

	/**
	 * Get queryable state.
	 * @returns {boolean} 返回一个布尔值,表示是否可以查询
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let ret = object.getQueryable();
	 * // @expect(ret == false);
	 */
	getQueryable() {
		return this._flags.has(Flag.Queryable);
	}

	/**
	 * Set queryable state.
	 * @param {boolean} value The state value.
	 * @param {boolean} recursive True indicates process it with all children.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.setQueryable(true);
	 * // @expect(object.getQueryable() == true);
	 */
	setQueryable(value, recursive) {
		// Update queryable flag
		this._flags.enable(Flag.Queryable, value);

		// Sync background selector's flag
		Selector.updateObjectAttribute(this, 'queryable', value);

		// Change all children if needed
		if (recursive) {
			let _private = this[__.private];
			if (_private.children) {
				let children = _private.children;
				for (let i = 0, l = children.length; i < l; i++) {
					children[i].setQueryable(value, true);
				}
			}
		}
	}

	/**
	 * Get destroyable state.
	 * @returns {boolean} 返回一个布尔值,表示是否可以销毁
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let ret = object.getDestroyable();
	 * // @expect(ret == true);
	 */
	getDestroyable() {
		return this._flags.has(Flag.Destroyable);
	}

	/**
	 * Set destroyable state.
	 * @param {boolean} value The state value.
	 * @param {boolean} recursive True indicates process it with all children.
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * object.setDestroyable(false);
	 * // @expect(object.getDestroyable() == false);
	 */
	setDestroyable(value, recursive) {
		// Update destroyable flag
		this._flags.enable(Flag.Destroyable, value);

		// Change all children if needed
		if (recursive) {
			let _private = this[__.private];
			if (_private.children) {
				let children = _private.children;
				for (let i = 0, l = children.length; i < l; i++) {
					children[i].setDestroyable(value, true);
				}
			}
		}
	}

	/**
	 * Make object to call onRefresh() interface later.
	 * @param {boolean} force 是否强制刷新
	 * @example
	 * let object = new THING.BaseObject();
	 * object.setDirty(true);
	 * // @expect(object.onRefresh() == true);
	 * @private
	 */
	setDirty(force) {
		let flags = this._flags;
		if (flags.has(Flag.Dirty)) {
			return;
		}

		flags.enable(Flag.Dirty, true);

		if (force) {
			this.onRefresh();
		}
		else {
			this.app.objectManager.addDirtyObject(this);
		}
	}


	/**
	 *  销毁物体
	 * @returns {boolean} 返回一个布尔值,表示是否销毁成功
	 * @example
	 * let object = new THING.BaseObject();
	 * // @expect(object.destroyed == false);
	 * object.destroy();
	 * // @expect(object.destroyed == true)
	 * @public
	 */
	destroy() {
		if (this.onBeforeDestroy() === false) {
			return false;
		}

		this.onDestroy();

		this.onAfterDestroy();

		return true;
	}

	/**
	 * Get flags.
	 * @type {object}
	 * @private
	 */
	get flags() {
		return this._flags;
	}

	/**
	 * Get destroyed state.
	 * @type {boolean}
	 * @private
	 */
	get destroyed() {
		return this._flags.has(Flag.Destroyed);
	}

	/**
	 * 设置/获取 对象是否可以被销毁
	 * @type {boolean}
	 * @example
	 * let object = new THING.BaseObject();
	 * object.destroyable = true;
	 * // @expect(object.destroyable == true)
	 * @public
	 */
	get destroyable() {
		return this._flags.has(Flag.Destroyable);
	}
	set destroyable(value) {
		this.setDestroyable(value, true);
	}

	/**
	 * 设置/获取 对象是否可以被查询
	 * @type {boolean}
	 * @example
	 * let object = new THING.BaseObject();
	 * object.name = 'Hidden';
	 * let ret = app.query('Hidden');
	 * // @expect(ret[0].name = 'Hidden')
	 * object.queryable = false;
	 * ret = app.query('Hidden');
	 * // @expect(ret.length = 0)
	 * @public
	 */
	get queryable() {
		return this._flags.has(Flag.Queryable);
	}
	set queryable(value) {
		this.setQueryable(value, true);
	}

	// #endregion

	// #region Event

	/**
	 * Check whether has specified event listener.
	 * @param {string} type The event type.
	 * @param {string} tag The event tag.
	 * @returns {boolean} 返回一个布尔值,表示是否存在指定的事件
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let ret = object.hasEvent('click', 'MyTag');
	 * // @expect(ret == false);
	 */
	hasEvent(type, tag) {
		_eventListeners.length = 0;

		let events = this.app.eventManager.getEventListeners(type.toLowerCase(), this, _eventListeners);
		for (let i = 0; i < events.length; i++) {
			let event = events[i];

			if (event.removed) {
				continue;
			}

			if (tag !== event.tag) {
				continue;
			}

			return true;
		}

		return false;
	}

	/**
	 * @typedef {object} ObjectListenerInfo
	 * @property {string} type 事件类型。
	 * @property {string} condition 选择对象的条件。
	 * @property {Function} callback 事件回调函数。
	 * @property {string} tag 事件标签。
	 * @property {number} priority 事件优先级。
	 * @property {boolean} once 表示只触发一次的事件。
	 * @property {boolean} paused 表示事件是否已暂停。
	 * @public
	 */

	/**
	 * 获取指定类型的事件。
	 * @param {string} type 事件类型,为null表示获取所有事件。
	 * @returns {Array<ObjectListenerInfo>} 返回一个数组,包含所有指定类型的事件
	 * @public
	 * @example
	 * let object = new THING.BaseObject();
	 * let events = object.getEvents();
	 * // @expect(events.length > 0);
	 */
	getEvents(type) {
		let eventManager = this.app.eventManager;

		let events;
		if (type) {
			events = eventManager.getEventListeners(type.toLowerCase(), this);
		}
		else {
			events = eventManager.getAllEventListeners(this);
		}

		let aliveEvents = [];
		events.forEach(event => {
			if (event.removed) {
				return;
			}

			if (!event.enumerable) {
				return;
			}

			aliveEvents.push(event);
		});

		return aliveEvents;
	}

	/**
	 * 获取事件。
	 * @param {string} type 事件类型。
	 * @param {string} condition 选择对象的条件。
	 * @param {string} tag 事件标签。
	 * @returns {ObjectListenerInfo} 返回一个对象,包含指定类型的事件
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let event = object.getEvent('click', '.Box', 'MyTag');
	 * // @expect(event != null);
	 */
	getEvent(type, condition, tag) {
		type = type.toLowerCase();

		let events = this.getEvents();
		for (let i = 0; i < events.length; i++) {
			let event = events[i];

			if (event.type != type) {
				continue;
			}

			if (event.condition != condition) {
				continue;
			}

			if (event.tag != tag) {
				continue;
			}

			return event;
		}

		return null;
	}

	/**
	 * @public
	 * @typedef {object} ObjectEventOptions
	 * @property {boolean} once 是否只触发一次
	 * @property {boolean} useCapture 如果是true,会阻断孩子身上原有的事件,并给所有孩子注册这个事件
	 * @property {boolean} propagate 是否传播事件
	 */

	/**
	 * 注册事件
	 * @param {string} type 事件类型
	 * @param {string} condition 注册事件前先进行查询,对符合条件的对象进行注册
	 * @param {EventCallback} callback 事件回调函数
	 * @param {string} tag 事件的tag
	 * @param {number} priority 优先级 默认0
	 * @param {ObjectEventOptions} options 事件参数
	 * @example
	 * let object = new THING.BaseObject();
	 * let mark = 0;
	 * object.on('click', function(ev){
	 * 	mark = 1;
	 * }, 'MyClick');
	 * object.trigger('click');
	 * // @expect(mark == 1)
	 * let mark2 = 0;
	 * object.on('click', '.Box', function(ev){
	 * 	mark2 = 1;
	 * }, 'MyClick');
	 * // @expect(mark2 == 0)
	 * @public
	 */
	on(type, condition, callback, tag, priority, options) {
		this._addEventListener(type, condition, callback, tag, priority, options, false);
	}

	/**
	 * 注册一次性的事件,此事件响应只会触发一次,触发后会被自动注销
	 * @param {string} type 事件类型
	 * @param {string} condition 注册事件前先进行查询,对符合条件的对象进行注册
	 * @param {EventCallback} callback 事件回调函数
	 * @param {string} tag 事件的tag
	 * @param {number} priority 优先级 默认0
	 * @param {ObjectEventOptions} options 事件参数
	 * @example
	 * let object = new THING.BaseObject();
	 * let markOnce = 0;
	 * object.once('testOnce', function(ev) {
	 * 		markOnce = 1;
	 * });
	 * object.trigger('testOnce');
	 * // @expect(markOnce == 1);
	 * markOnce = 0;
	 * object.trigger('testOnce');
	 * // @expect(markOnce == 0);
	 * @public
	 */
	once(type, condition, callback, tag, priority, options) {
		this._addEventListener(type, condition, callback, tag, priority, options, true);
	}

	/**
	 * 注销事件
	 * @param {string} type 事件类型
	 * @param {string} condition 注册事件的条件
	 * @param {string} tag 事件的tag
	 * @example
	 * let object = new THING.BaseObject();
	 * let markOff = 0;
	 * object.on('testOff', function(ev) {
	 * 		markOff = 1;
	 * });
	 * object.trigger('testOff');
	 * // @expect(markOff == 1);
	 * markOff = 0;
	 * object.off('testOff');
	 * object.trigger('testOff');
	 * // @expect(markOff == 0);
	 * @public
	 */
	off(type, condition, tag) {
		// Use condition as tag
		if (Utils.isString(condition) && Utils.isNull(tag)) {
			this._removeEventListener(type, null, condition);
		}
		// Use both condition and tag
		else {
			this._removeEventListener(type, condition, tag);
		}
	}

	/**
	 * 暂停事件
	 * @param {string} type 事件类型
	 * @param {string} condition 注册事件的条件
	 * @param {string} tag 事件的tag
	 * @example
	 * let object = new THING.BaseObject();
	 * let markPause = 0;
	 * object.on('testPause', function(ev) {
	 * 		markPause = 1;
	 * });
	 * object.trigger('testPause');
	 * // @expect(markPause == 1);
	 * markPause = 0;
	 * object.pauseEvent('testPause');
	 * object.trigger('testPause');
	 * // @expect(markPause == 0);
	 * app.on('test', ".Box", (e) => {
	 * 	console.log(e.object)
	 * }, 'MyTag');
	 * app.pauseEvent('test', '.Box', 'MyTag');
	 * @public
	 */
	pauseEvent(type, condition, tag) {
		this.app.eventManager.pauseEvent(this, type, condition, tag);
	}

	/**
	 * 恢复事件
	 * @param {string} type 事件类型
	 * @param {string} condition 注册事件的条件
	 * @param {string} tag 事件的tag
	 * @example
	 * let object = new THING.BaseObject();
	 * let markResume = 0;
	 * object.on('testResume', function(ev) {
	 * 		markResume = 1;
	 * });
	 * object.trigger('testResume');
	 * // @expect(markResume == 1);
	 * markResume = 0;
	 * object.pauseEvent('testResume');
	 * object.trigger('testResume');
	 * // @expect(markResume == 0);
	 * object.resumeEvent('testResume');
	 * object.trigger('testResume');
	 * // @expect(markResume == 1);
	 * app.on('test', ".Box", (e) => {
	 * 	console.log(e.object)
	 * }, 'MyTag');
	 * app.pauseEvent('test', '.Box', 'MyTag');
	 * app.resumeEvent('test', '.Box', 'MyTag');
	 * @public
	 */
	resumeEvent(type, condition, tag) {
		this.app.eventManager.resumeEvent(this, type, condition, tag);
	}

	/**
	 * 抛出事件
	 * @param {string} type 事件类型。
	 * @param {string|object} condition 事件条件 或 事件数据。
	 * @param {object|string} data 事件数据 或 事件标签。
	 * @param {string} tagName 事件标签名称。
	 * @returns {*} 返回一个对象,包含指定类型的事件
	 * @example
	 * let object = new THING.BaseObject();
	 *  let markTrigger = {};
	 * 	object.on('myEvent', function(ev) {
	 * 		markTrigger = ev;
	 * 	});
	 * 	object.trigger('myEvent', { result: true });
	 *  let ret = markTrigger.result;
	 *  // @expect(ret == true);
	 *
	 * new THING.Box();
	 *
	 *  app.on('test', (e) => {
	 *      console.log('无条件+tag1', e)
	 *  }, 'MyTag1');
	 *  app.on('test', (e) => {
	 *      console.log('无条件+tag2', e)
	 *  }, 'MyTag2');
	 *
	 * app.on('test', ".Box", (e) => {
	 * 	    console.log('条件+tag1', e)
	 * }, 'MyTag1');
	 * app.on('test', ".Box", (e) => {
	 * 	    console.log('条件+tag2', e)
	 * }, 'MyTag2');
	 *
	 * // 事件类型 + 事件条件,触发事件。
	 * app.trigger('test', '.Box');
	 * // 事件类型 + 事件数据,触发事件
	 * app.trigger('test', { result: true });
	 * // 事件类型 + 事件条件 + 事件标签,触发事件
	 * app.trigger('test', '.Box', 'MyTag2');
	 * // 事件类型 + 事件条件 + 事件参数,触发事件
	 * app.trigger('test', '.Box', { result: true });
	 * // 事件类型 + 事件条件 + 事件数据 + 事件标签,触发事件
	 * app.trigger('test', '.Box', { result: true },'MyTag2');
	 *
	 * // 注意事项:
	 * // 1. 事件标签不能单独使用,否则事件标签和事件条件无法区分。
	 * app.trigger('test', null, 'MyTag2');
	 * // 2. 事件数据兼容了数组的情况,如果传了数组将无法从参数中获取object。
	 * app.trigger('test', '.Box', [{ result: 'r1' },{ result: 'r2' }], 'MyTag2')
	 * @public
	 */
	trigger(type, condition, data, tagName) {
		if (this.destroyed) return null;

		// condition 为null时,设置为空字符串
		if (condition == null) {
			condition = '';
		}

		// 参数解析逻辑
		let eventCondition = null;
		let eventData = {};
		let eventOptions = {};

		if (typeof condition === 'object') {
			// condition 为对象时,表示事件数据。data可能是tag (用typeof判断,兼容数组的情况)
			eventData = condition;
			if (Utils.isString(data)) {
				eventOptions.tag = data;
			}
		}
		else if (typeof data === 'object') {
			// data 为对象时,表示事件数据。condition为条件 tagName为tag  (用typeof判断,兼容数组的情况)
			eventCondition = condition;
			eventData = data;
			if (Utils.isString(tagName)) {
				eventOptions.tag = tagName;
			}
		}
		else {
			// condition 和 data 都不是对象,那么 condition 为条件,如果data也是字符串data为tag
			eventCondition = condition;
			if (Utils.isString(data)) {
				eventOptions.tag = data;
			}
		}

		if (eventCondition) {
			const result = this.query(eventCondition);
			return result.trigger(type, eventData, eventOptions);
		}
		else {
			return this.app.eventManager.dispatchEvent(
				type.toLowerCase(),
				this,
				eventData,
				eventOptions
			);
		}
	}

	/**
	 * 触发并等待事件完成
	 * @param {string} type 事件类型。
	 * @param {string|object} condition 事件条件 或 事件数据。
	 * @param {object|string} data 事件数据 或 事件标签。
	 * @param {string} tagName 事件标签名称。
	 * @returns {*} 返回一个Promise对象,包含指定类型的事件
	 * @public
	 */
	async invoke(type, condition, data, tagName) {
		if (this.destroyed) return null;

		// 参数解析逻辑
		let eventCondition = null;
		let eventData = {};
		let eventOptions = {};

		if (typeof condition === 'object') {
			// condition 为对象时,表示事件数据。data可能是tag (用typeof判断,兼容数组的情况)
			eventData = condition;
			if (Utils.isString(data)) {
				eventOptions.tag = data;
			}
		}
		else if (typeof data === 'object') {
			// data 为对象时,表示事件数据。condition为条件 tagName为tag  (用typeof判断,兼容数组的情况)
			eventCondition = condition;
			eventData = data;
			if (Utils.isString(tagName)) {
				eventOptions.tag = tagName;
			}
		}
		else {
			// condition 和 data 都不是对象,那么 condition 为条件,如果data也是字符串data为tag
			eventCondition = condition;
			if (Utils.isString(data)) {
				eventOptions.tag = data;
			}
		}

		if (eventCondition) {
			const result = this.query(eventCondition);
			return result.invoke(type, eventData, eventOptions);
		}
		else {
			return this.app.eventManager.invokeEvent(
				type.toLowerCase(),
				this,
				eventData,
				eventOptions
			);
		}
	}

	/**
	 * 设置事件过滤器
	 * @param {string} type 事件类型。
	 * @param {string} condition 事件条件。
	 * @param {object} tag 事件标签。
	 * @param {Function} callback 事件回调函数。
	 */
	addEventFilter(type, condition, callback, tag) {
		if (this.destroyed) return null;
		let info = Utils.parseEvent(type, condition, callback, tag);
		this.app.eventManager.addEventFilter(
			this,
			info.type,
			info.condition,
			info.tag,
			info.callback
		);
	}

	/**
	 * 移除事件过滤器
	 * @param {string} type 事件类型。
	 * @param {string} condition 事件条件
	 * @param {ostring} tag 事件标签
	 */
	removeEventFilter(type, condition, tag) {
		if (this.destroyed) return null;

		let callback = () => { }
		let info = Utils.parseEvent(type, condition, callback, tag);
		this.app.eventManager.removeEventFilter(
			this,
			info.type,
			info.condition,
			info.tag
		);
	}

	/**
	 * 移除所有事件过滤器
	 */
	removeAllEventFilters() {
		if (this.destroyed) return null;

		this.app.eventManager.removeAllEventFilters(this);
	}

	/**
	 * Get proxy object. 获取代理对象
	 * @returns {THING.BaseObject} 返回一个代理对象
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let proxyObject = object.getProxyObject();
	 * // @expect(proxyObject != null);
	 */
	getProxyObject() {
		let _private = this[__.private];

		return _private.proxyObject;
	}

	/**
	 * 设置代理对象
	 * </br>设置代理对象(它将捕获该对象的所有事件)。
	 * @param {THING.BaseObject} object The object.
	 * @example
	 * 	let car = app.query('#car01')[0];
	 * 	object.setProxyObject(car); // The car will catch all events of object
	 * @private
	 */
	setProxyObject(object) {
		let _private = this[__.private];

		_private.proxyObject = object;
	}

	triggerError(error, callback) {
		if (typeof error != 'object') {
			error = { error }
		}

		this.trigger(EventType.Error, error);
		Utils.error(error);
		callback && callback(error);
	}

	/**
	 * 获取当前对象注册的所有事件监听器的详细列表。
	 * 该属性返回一个 ObjectListenerInfo 类型的数组,每一项包含一个事件监听器的全部信息。
	 *
	 * ObjectListenerInfo 格式参考(常用字段如下):
	 * - name: 事件名称(一般为小写,如 "click", "update", "mouseenter" 等)
	 * - callback: 回调函数,事件触发时调用
	 * - context: 回调函数的上下文对象
	 * - once: 是否为一次性监听(只会触发一次,之后移除)
	 * - filter: 事件过滤函数(可选)
	 * - id: 事件监听唯一标识(可选)
	 * - other: 可能包含的其他参数或元数据
	 * @type {Array<ObjectListenerInfo>}
	 * @public
	 * @example
	 * let object = new THING.BaseObject();
	 * object.on('click', function() { console.log('clicked'); });
	 * // 获取所有事件监听器
	 * let allEvents = object.events;
	 * // @expect(Array.isArray(allEvents));
	 * // @expect(allEvents.length >= 0);
	 * // allEvents 结果类似:
	 * // [{
	 * //   name: 'click',
	 * //   callback: ƒ,
	 * //   context: object,
	 * //   once: false,
	 * //   filter: undefined,
	 * //   id: 1
	 * // }, ...]
	 */
	get events() {
		return this.getEvents();
	}

	// #endregion

	// #region Relative

	/**
	 * When set the parent.
	 * @param {THING.BaseObject} parent The parent.
	 * @param {object} options 选项
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parent = new THING.BaseObject();
	 * object.onSetParent(parent);
	 * // @expect(object.parent == parent);
	 */
	onSetParent(parent, options) {
		let _private = this[__.private];

		// Prevent for the same parent
		if (parent == _private.parent) {
			return;
		}

		// Attach to new parent
		if (parent) {
			parent.addChild(this, options);
		}

		// Remove it from previous parent
		this._removeFromParent();

		// Update current parent
		_private.parent = parent;
	}

	/**
	 * Get the parent.
	 * @returns {THING.BaseObject} 返回一个父对象
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parent = new THING.BaseObject();
	 * object.onSetParent(parent);
	 * // @expect(object.parent == parent);
	 */
	getParent() {
		return this[__.private].parent;
	}

	/**
	 * Get the parnet by type.
	 * @param {string} type The type string.
	 * @returns {THING.BaseObject} 返回一个父对象
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parent = new THING.BaseObject();
	 * object.onSetParent(parent);
	 * // @expect(object.parent == parent);
	 */
	getParentByType(type) {
		let typeString = 'is' + type;

		for (let parent = this.parent; parent; parent = parent.parent) {
			if (parent[typeString]) {
				return parent;
			}
		}

		return null;
	}

	/**
	 * Get the parents.
	 * @param {object} param The parameters.
	 * @param {THING.BaseObject} param.root The root to stop.
	 * @param {boolean} param.includeSelf True indicates including self object.
	 * @returns {THING.Selector} 返回一个选择器
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parents = object.getParents();
	 * // @expect(parents.length > 0);
	 */
	getParents(param = _defaultParams) {
		let _private = this[__.private];

		let root = param['root'];
		let includeSelf = param['includeSelf'];

		let selector = new Selector();

		if (includeSelf) {
			selector.push(this);
		}

		let parent = _private.parent;
		while (parent) {
			if (parent == root) {
				break;
			}

			selector.push(parent);

			parent = parent.parent;
		}

		return selector;
	}

	/**
	 * Get the brothers except self.
	 * @returns {THING.Selector} 返回一个选择器
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let brothers = object.getBrothers();
	 * // @expect(brothers.length > 0);
	 */
	getBrothers() {
		let _private = this[__.private];

		let parent = _private.parent;
		if (parent) {
			return parent.children.filter(object => {
				if (object === this) {
					return false;
				}

				return true;
			});
		}

		return new Selector();
	}

	/**
	 * Get the path to specific object.
	 * @param {THING.BaseObject} object The object to check.
	 * @returns {THING.Selector} 返回一个选择器
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let path = object.getPathTo(object);
	 * // @expect(path.length > 0);
	 */
	getPathTo(object) {
		if (!object) {
			return null;
		}

		if (this.isChildOf(object)) {
			let path = this.getParents({ root: object });
			path.push(object);

			return path;
		}
		else if (object.isChildOf(this)) {
			let path = object.getParents({ root: this }).reverse();
			path.push(object);

			return path;
		}
		else {
			// Get all parents
			let targetParents = object.parents.reverse();
			let selfParents = this.parents.reverse();

			// Check whether it has parents
			if (targetParents.length && selfParents.length) {
				// Check whether it come from the same root
				if (targetParents[0] == selfParents[0]) {
					// Find the link parent
					let linkParent;
					while (targetParents.length && selfParents.length) {
						if (targetParents[0] != selfParents[0]) {
							break;
						}

						linkParent = selfParents[0];
						targetParents.splice(0, 1);
						selfParents.splice(0, 1);
					}

					if (linkParent) {
						return selfParents.reverse().concat([linkParent]).concat(targetParents).concat(object);
					}
				}
			}
		}

		return null;
	}

	/**
	 * Check whether it's child.
	 * @param {THING.BaseObject} object The object to check.
	 * @returns {boolean} 返回一个布尔值,表示是否是子对象
	 * @example
	 * let parent = new THING.BaseObject();
	 * let child = new THING.BaseObject({parent: parent});
	 * let ret = child.isChildOf(parent);
	 *  // @expect(ret == true);
	 */
	isChildOf(object) {
		if (!object) {
			return false;
		}

		let parent = this.parent;
		while (parent) {
			if (parent == object) {
				return true;
			}

			parent = parent.parent;
		}

		return false;
	}

	/**
	 * Check whether it's brother.
	 * @param {THING.BaseObject} object The object to check.
	 * @returns {boolean} 返回一个布尔值,表示是否是兄弟对象
	 * @example
	 * let parent = new THING.BaseObject();
	 * let child1 = new THING.BaseObject({parent: parent});
	 * let child2 = new THING.BaseObject({parent: parent});
	 * let ret = child1.isBrotherOf(child2);
	 *  // @expect(ret == true);
	 */
	isBrotherOf(object) {
		if (!object) {
			return false;
		}

		if (this == object) {
			return false;
		}

		if (this.parent != object.parent) {
			return false;
		}

		return true;
	}

	addChild(object, options) {
		let _private = this[__.private];

		_private.children = _private.children || new Selector();
		if (options && Utils.isNumber(options.indexOfParent)) {
			_private.children.splice(options.indexOfParent, 0, object);
		}
		else {
			_private.children.push(object);
		}
	}

	/**
	 * 添加一个BaseObject作为自己的孩子
	 * @param {THING.BaseObject} object 待添加的BaseObject
	 * @param {object} options 参数 主要是子类定义
	 * @returns {boolean} 返回一个布尔值,表示是否添加成功
	 * @example
	 * let parent = new THING.BaseObject();
	 * let child = new THING.BaseObject();
	 * parent.add(child);
	 * let ret = child.isChildOf(parent);
	 *  // @expect(ret == true);
	 * @public
	 */
	add(object, options) {
		if (!object) {
			return false;
		}

		if (!object.isBaseObject) {
			options = object;
			object = options.object;
			delete options.object;
		}

		let parent = object.parent;
		if (parent) {
			// The final parent is passed in as an argument.
			object.onBeforeSetParent(this);
			parent.remove(object, options);
		}

		this.onBeforeAddChild(object);

		this.onAddChild(object, options);

		this.onAfterAddChild(object);

		return true;
	}

	/**
	 * 从自己的孩子中移除BaseObject
	 * @param {THING.BaseObject} object 待移除物体
	 * @param {object} options 选项
	 * @returns {boolean} 返回一个布尔值,表示是否移除成功
	 * @example
	 * let parent = new THING.BaseObject();
	 * let child = new THING.BaseObject();
	 * parent.add(child);
	 * let ret = child.isChildOf(parent);
	 *  // @expect(ret == true);
	 * 	parent.remove(child);
	 * ret = child.isChildOf(parent);
	 * 	// @expect(ret == false);
	 * @public
	 */
	remove(object, options) {
		if (!object) {
			return false;
		}

		this.onBeforeRemoveChild(object);

		object.onSetParent(null, null, options);

		this.onAfterRemoveChild(object);

		return true;
	}

	/**
	 * 递归遍历自己和自己的孩子 这个方法会遍历到所有的后代节点(孩子,孩子的孩子等)
	 * @param {Function} callback The callback function. 执行遍历时执行的方法
	 * @example
	 * let parent = new THING.BaseObject();
	 * let child1 = new THING.BaseObject({parent: parent});
	 * let child2 = new THING.BaseObject({parent: parent});
	 * let mark = 0;
	 * parent.traverse((child) => {
	 * 		mark++;
	 * });
	 * // @expect(mark == 3)
	 * @public
	 */
	traverse(callback) {
		callback(this);
		if (this.children) {
			let objects = this.children.objects;
			for (let i = 0, l = objects.length; i < l; i++) {
				objects[i].traverse(callback);
			}
		}
	}

	/**
	 * Traverse self and all children. (Support for exit at traverse runtime)
	 * @param {Function} callback The callback function. (Return false to exit)
	 * @returns {boolean} 返回一个布尔值,表示是否继续遍历
	 * @example
	 * let parent = new THING.BaseObject();
	 * let child1 = new THING.BaseObject({parent: parent});
	 * let child2 = new THING.BaseObject({parent: parent});
	 * let mark = 0;
	 * parent.traverseBranch((child)=>{
	 * 	   mark++;
	 * });
	 * // @expect(mark == 3)
	 * mark = 0;
	 * parent.traverseBranch((child)=>{
	 * 	   mark++;
	 *     if(child.children.length > 0){
	 * 		   return false;
	 * 	   }
	 *	   return true;
	 * });
	 * // @expect(mark == 1)
	 */
	traverseBranch(callback) {
		let isBranch = Utils.parseBoolean(callback(this), true);
		if (!isBranch) {
			return false;
		}

		let _private = this[__.private];

		let children = _private.children;
		if (children) {
			for (let i = 0, l = children.length; i < l; i++) {
				isBranch = children[i].traverseBranch(callback);
				if (!isBranch) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Traverse all parents except self.
	 * @param {Function} callback The callback function.
	 * @deprecated Deprecated, call with the selector returned by the object's parent interface
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parent = new THING.BaseObject();
	 * object.onSetParent(parent);
	 * // @expect(object.parent == parent);
	 */
	traverseParents(callback) {
		console.warn('Plase use Selector.tarverse instead of tarverseParents');
		for (let parent = this.parent; parent; parent = parent.parent) {
			callback(parent);
		}
	}

	/**
	 * Traverse all children except self.
	 * @param {Function} callback The callback function.
	 * @deprecated Deprecated, call with the selector returned by the object's children interface
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parent = new THING.BaseObject();
	 * object.onSetParent(parent);
	 * // @expect(object.parent == parent);
	 */
	traverseChildren(callback) {
		console.warn('Plase use Selector.tarverse instead of traverseChildren');
		let _private = this[__.private];

		if (_private.children) {
			let children = _private.children;
			for (let i = 0, l = children.length; i < l; i++) {
				children[i].traverse(callback);
			}
		}
	}

	/**
	 * Find all children except self.
	 * @param {Function} callback The callback function.
	 * @returns {THING.BaseObject} 返回一个物体
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let parent = new THING.BaseObject();
	 * object.onSetParent(parent);
	 * // @expect(object.parent == parent);
	 */
	findChildren(callback) {
		let _private = this[__.private];

		let children = _private.children;
		if (children) {
			for (let i = 0, l = children.length; i < l; i++) {
				let child = children[i];

				if (callback(child) === true) {
					return child;
				}

				let result = child.findChildren(callback);
				if (result) {
					return result;
				}
			}
		}

		return null;
	}

	/**
	 * Check whether has any children.
	 * @returns {boolean} 返回一个布尔值,表示是否存在孩子
	 * @example
	 * 	let parent = new THING.BaseObject();
	 *  let child = new THING.BaseObject({parent: parent});
	 * 	let ret = parent.hasChildren();
	 * 	// @expect(ret == true);
	 */
	hasChildren() {
		let _private = this[__.private];

		if (!_private.children) {
			return false;
		}

		if (!_private.children.length) {
			return false;
		}

		return true;
	}

	addRelationship(value) {
		this.relationship.addRelationship(value);
	}

	removeRelationship(value) {
		this.relationship.removeRelationship(value);
	}

	/**
	 * 设置/获取 父物体
	 * @type {THING.BaseObject}
	 * @example
	 * 	let parent = new THING.BaseObject();
	 *  let child = new THING.BaseObject({parent: parent});
	 * 	let ret = child.parent == parent;
	 * 	// @expect(ret == true);
	 * @public
	 */
	get parent() {
		return this[__.private].parent;
	}
	set parent(value) {
		if (value) {
			value.add(this);
		}
		else if (this.parent) {
			this.parent.remove(this);
		}
	}

	/**
	 * 设置/获取 关系
	 * @type {Array<THING.Relationship>}
	 * @example
	 * let object = new THING.Object3D();
	 * let source = new THING.Object3D();
	 * let target = new THING.Object3D();
	 * let relationship = new THING.Relationship({
	 *      type: 'control',
	 *      source: source,
	 *      target: target
	 * });
	 * object.addRelationship(relationship);
	 * let ret = object.relationships[0].type == 'control';
	 * // @expect(ret == true)
	 * @public
	 */
	get relationships() {
		return this.relationship.relationships || [];
	}

	/**
	 * 获取所有的祖先(父物体,父物体的父物体等,直到查询到根节点--app.root)
	 * @type {THING.Selector}
	 * @example
	 * 	let box1 = new THING.Box();
	 * 	let box2 = new THING.Box({parent: box1});
	 * 	let parents = box2.parents;
	 *  // @expect(parents.length == 2);
	 * @public
	 */
	get parents() {
		return this.getParents();
	}

	/**
	 * 获取兄弟节点(同级节点)
	 * @type {THING.Selector}
	 * @example
	 * 	let box1 = new THING.Box();
	 * 	let box2 = new THING.Box({parent: box1});
	 * 	let box3 = new THING.Box({parent: box1});
	 * 	let brothers = box3.brothers;
	 *  // @expect(brothers.length == 1);
	 * @public
	 */
	get brothers() {
		return this.getBrothers();
	}

	/**
	 * 获取孩子
	 * @type {THING.Selector}
	 * @example
	 * let object = new THING.BaseObject();
	 * let child= new THING.BaseObject({parent: object});
	 * let children = object.children;
	 * let ret = children.length == 1;
	 * // @expect(ret == true)
	 * @public
	 */
	get children() {
		let _private = this[__.private];

		return _private.children || _dummySelector;
	}

	// #endregion

	// #region Selector

	/**
	 * Test whether fit condition or not.
	 * @param {string} condition The condition to check.
	 * @returns {boolean} 返回一个布尔值,表示是否满足条件
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let ret = object.test('name == "liming"');
	 * // @expect(ret == true);
	 */
	test(condition) {
		return Selector.test(condition, this);
	}

	/**
	 * @public
	 * @typedef {object} ObjectQueryOptions
	 * @property {boolean} recursive 是否递归查询 默认true
	 * @property {boolean} includeSelf 是否包括自身 默认不包含
	 */

	/**
	 * 根据条件查询孩子 返回所有满足条件的对象集合
	 * @param {ObjectQueryOptions|string} condition 查询条件
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child= new THING.BaseObject({parent: object});
	 * child.userData = {power: 1000};
	 * let children = object.children.query('[userData/power>100]');
	 * let ret = children.length == 1;
	 * // @expect(ret == true)
	 * @public
	 */
	query(condition) {
		let options = {};

		if (Utils.isObject(arguments[1])) {
			options = arguments[1];
		}
		else if (Utils.isBoolean(arguments[1])) {
			// 兼容1.0的写法
			options = { recursive: arguments[1] };
		}

		if (Utils.isBoolean(arguments[2])) {
			// 兼容1.0的写法
			options['includeSelf'] = arguments[2];
		}

		options['app'] = this.app;

		let recursive = Utils.parseValue(options['recursive'], true);
		let includeSelf = options['includeSelf'];
		let selector = options['dynamic'] ? new DynamicSelector(this, condition, options) : new Selector();

		if (this.isRootObject && recursive) {
			selector.query(condition, this.app.objectManager.objects, selector);
		}
		else {
			if (includeSelf) {
				if (this.test(condition)) {
					selector.push(this);
				}
			}
			if (recursive) {
				if (Utils.isString(condition)) {
					// All
					var objs = [];
					if (condition == '*') {
						this.children.traverse(child => {
							if (child.queryable) {
								objs.push(child)
							}
						});
					}
					// Expression
					else if (this._isExpression(condition)) {
						let expression = Selector.buildExpression(condition);
						if (expression) {
							this.children.traverse(child => {
								if (Selector.testByExpression(expression, child) && child.queryable) {
									objs.push(child);
								}
							});
						}
					}
					// Compare name
					else {
						this.children.traverse(child => {
							if (child.name == condition && child.queryable) {
								objs.push(child);
							}
						});
					}
					selector.push(objs);
				}
				// Reg Expression
				else if (Utils.isRegExp(condition)) {
					if (this.children) {
						var objs = [];
						this.children.traverse(child => {
							if (Selector.testByRegExpName(condition, child) && child.queryable) {
								objs.push(child);
							}
						});
						selector.push(objs);
					}
				}
				// Function
				else if (Utils.isFunction(condition)) {
					if (this.children) {
						var objs = [];
						this.children.traverse(child => {
							if (Selector.testByFunction(condition, child) && child.queryable) {
								objs.push(child);
							}
						});
						selector.push(objs);
					}
				}
			}
			else {
				if (this.children) {
					selector.push(this.children.query(condition));
				}
			}
		}
		return selector;
	}

	/**
	 * 根据条件查询孩子 返回所有满足条件的对象集合(忽略 queryable 属性)
	 * @param {ObjectQueryOptions|string} condition 查询条件
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child= new THING.BaseObject({parent: object});
	 * child.userData = {power: 1000};
	 * let children = object.children.queryAll('[userData/power>100]');
	 * let ret = children.length == 1;
	 * // @expect(ret == true)
	 * @public
	 */
	queryAll(condition) {
		let options = {};

		if (Utils.isObject(arguments[1])) {
			options = arguments[1];
		}
		else if (Utils.isBoolean(arguments[1])) {
			// 兼容1.0的写法
			options = { recursive: arguments[1] };
		}

		if (Utils.isBoolean(arguments[2])) {
			// 兼容1.0的写法
			options['includeSelf'] = arguments[2];
		}

		options['app'] = this.app;

		let recursive = Utils.parseValue(options['recursive'], true);
		let includeSelf = options['includeSelf'];
		let selector = options['dynamic'] ? new DynamicSelector(this, condition, options) : new Selector();

		if (this.isRootObject && recursive) {
			selector.queryAll(condition, this.app.objectManager.objects, selector);
		}
		else {
			if (includeSelf) {
				if (this.test(condition)) {
					selector.push(this);
				}
			}
			if (recursive) {
				if (Utils.isString(condition)) {
					// All
					var objs = [];
					if (condition == '*') {
						this.children.traverse(child => {
							objs.push(child)
						});
					}
					// Expression
					else if (this._isExpression(condition)) {
						let expression = Selector.buildExpression(condition);
						if (expression) {
							this.children.traverse(child => {
								if (Selector.testByExpression(expression, child)) {
									objs.push(child);
								}
							});
						}
					}
					// Compare name
					else {
						this.children.traverse(child => {
							if (child.name == condition) {
								objs.push(child);
							}
						});
					}
					selector.push(objs);
				}
				// Reg Expression
				else if (Utils.isRegExp(condition)) {
					if (this.children) {
						var objs = [];
						this.children.traverse(child => {
							if (Selector.testByRegExpName(condition, child)) {
								objs.push(child);
							}
						});
						selector.push(objs);
					}
				}
				// Function
				else if (Utils.isFunction(condition)) {
					if (this.children) {
						var objs = [];
						this.children.traverse(child => {
							if (Selector.testByFunction(condition, child)) {
								objs.push(child);
							}
						});
						selector.push(objs);
					}
				}
			}
			else {
				if (this.children) {
					selector.push(this.children.queryAll(condition));
				}
			}
		}
		return selector;
	}

	/**
	 * 根据名称查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数 主要包括是否递归查询和是否包含自身
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child= new THING.BaseObject({parent: object, name: 'liming'});
	 * let result = object.queryByName('liming');
	 * let ret = result[0].name == 'liming';
	 * // @expect(ret == true)
	 * @public
	 */
	queryByName(condition, options = {}) {
		return this._queryByAttribute(this, options, (c) => { return c.name == condition });
	}
	/**
	 * 根据id查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.BaseObject({parent: object});
	 * child1.id = '10000';
	 * let child2= new THING.BaseObject({parent: object});
	 * let result = object.queryById('10000');
	 * let ret = result[0].id == '10000';
	 *  //@expect(ret == true)
	 * @public
	 */
	queryById(condition, options = {}) {
		return this._queryByAttribute(this, options, (c) => { return c.id == condition });
	}
	/**
	 * 根据tag查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.Object3D({parent: object, name: 'car1'});
	 * child1.tags.add('testCar');
	 * let child2= new THING.BaseObject({parent: object, name: 'car2'});
	 * let result = object.queryByTags('testCar');
	 * let ret = result.length == 1;
	 *  //@expect(ret == true)
	 * @public
	 */
	queryByTags(condition, options = {}) {
		return this._queryByCondition('tags(' + condition + ')', options, 'tags');
	}
	/**
	 * 根据uuid查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.BaseObject({parent: object, uuid: '1000'});
	 * let child2= new THING.BaseObject({parent: object});
	 * let result = object.queryByUUID('1000');
	 * let ret = result[0].uuid == '1000';
	 *  //@expect(ret == true)
	 * @public
	 */
	queryByUUID(condition, options = {}) {
		return this._queryByAttribute(this, options, (c) => { return c.uuid == condition });
	}
	/**
	 * 根据类型查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.Box({parent: object, id: '10000'});
	 * let child2= new THING.BaseObject({parent: object});
	 * let result = object.queryByType('Box');
	 * let ret = result[0].id == '10000';
	 *  //@expect(ret == true)
	 * @public
	 */
	queryByType(condition, options = {}) {
		var key = "is" + condition;
		return this._queryByAttribute(this, options, (c) => { return c[key] == true });
	}

	/**
	 * 根据孪生体类型查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.BaseObject({parent: object});
	 * child1.dtType = 'Equipment';
	 * let child2= new THING.BaseObject({parent: object});
	 * let result = object.queryByDTType('Equipment');
	 * let ret = result[0].dtType == 'Equipment';
	 *  //@expect(ret == true)
	 * @public
	 */
	queryByDTType(condition, options = {}) {
		return this._queryByAttribute(this, options, (c) => { return c.dtType === condition });
	}

	/**
	 * 根据userData(用户数据)查询孩子
	 * @param {string} condition 查询条件
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.Box({parent: object});
	 * child1.userData['power'] = 100;
	 * let child2= new THING.BaseObject({parent: object});
	 * let result = object.queryByUserData('power=100');
	 * let ret = result[0].userData.power == 100;
	 *  //@expect(ret == true)
	 * @public
	 */
	queryByUserData(condition, options = {}) {
		return this._queryByCondition(condition, options, 'userData');
	}

	/**
	 * 根据userData查询孩子。
	 * @param {string} condition 查询条件。
	 * @param {ObjectQueryOptions} options 查询选项。
	 * @returns {THING.Selector} 查询结果。
	 * @example
	 * 	let result = object.queryByData('test=1');
	 * 	console.log(result);
	 * @deprecated 2.7
	 * @private
	 */
	queryByData(condition, options = {}) {
		return this.queryByUserData(condition, options);
	}
	/**
	 * 根据正则表达式查询孩子
	 * @param {string} condition 正则表达式
	 * @param {ObjectQueryOptions} options 查询参数
	 * @returns {THING.Selector} 查询结果
	 * @example
	 * let object = new THING.BaseObject();
	 * let child1= new THING.BaseObject({parent: object, name: 'car1'});
	 * let child2= new THING.BaseObject({parent: object, name: 'car2'});
	 * let result = object.queryByRegExp(/car/);
	 * let ret = result.length == 2;
	 *  //@expect(ret == true)
	 * @public
	 */
	queryByRegExp(condition, options = {}) {
		return this.query(condition, options);
	}

	/**
	 * 根据正则表达式查询孩子。
	 * @param {string} condition 查询条件。
	 * @param {ObjectQueryOptions} options 查询选项。
	 * @returns {THING.Selector} 查询结果。
	 * @example
	 * 	let result = object.queryByReg(/Sphere/);
	 * 	console.log(result);
	 * @deprecated 2.7
	 * @private
	 */
	queryByReg(condition, options = {}) {
		return this.queryByRegExp(condition, options);
	}



	_queryByAttribute(root, options, cb) {
		let selectorOptions = Object.assign({}, options, { app: this.app });
		let selector = options['dynamic'] ? new DynamicSelector(this, condition, selectorOptions) : new Selector(selectorOptions);
		let recursive = Utils.parseValue(options['recursive'], true);
		let includeSelf = options['includeSelf'];
		// RootObject query from all objects
		if (root.isRootObject && recursive) {
			selector._queryByAttribute(this.app.objectManager.objects, cb, selector);
		}
		else {
			let objects = [];
			if (includeSelf) {
				if (cb(root) && root.queryable) {
					objects.push(root);
				}
			}
			if (recursive) {
				this.children.traverse(c => {
					if (cb(c) && c.queryable) {
						objects.push(c);
					}
				});
			}
			else {
				objects = objects.concat(this.children.objects.filter((c) => { return cb(c) && c.queryable; }));
			}
			selector.push(objects);
		}
		return selector;
	}

	_queryByCondition(condition, options = {}, mode) {
		let selectorOptions = Object.assign({}, options, { app: this.app });
		let selector = options['dynamic'] ? new DynamicSelector(this, condition, selectorOptions) : new Selector(selectorOptions);
		let recursive = Utils.parseValue(options['recursive'], true);
		let includeSelf = options['includeSelf'];
		var objects = [];
		if (Utils.isString(condition)) {
			let expression = Selector.buildExpression(condition, mode);
			if (expression) {
				// RootObject query from all objects
				if (this.isRootObject && recursive) {
					selector._queryByCondition(condition, this.app.objectManager.objects, selector, mode);
				}
				else {
					if (includeSelf) {
						if (Selector.testByExpression(expression, this) && this.queryable) {
							objects.push(this);
						}
					}
					if (recursive) {
						this.children.traverse(child => {
							if (Selector.testByExpression(expression, child) && child.queryable) {
								objects.push(child);
							}
						});
					}
					else {
						this.children.forEach((child) => {
							if (Selector.testByExpression(expression, child) && child.queryable) {
								objects.push(child);
							}
						})
					}
				}
			}
		}
		selector.push(objects);
		return selector;
	}

	/**
	 * 异步模式下根据条件查询孩子。
	 * @param {string} condition 查询条件。
	 * @param {ObjectQueryOptions} options 查询选项。
	 * @returns {Promise<any>} 返回一个Promise对象
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let result = await object.queryAsync('name == "liming"');
	 * console.log(result);
	 */
	queryAsync(condition, options = {}) {
		let recursive = Utils.parseValue(options['recursive'], true);
		let includeSelf = options['includeSelf'];

		return Selector.queryAsync(condition, this, recursive).then(selector => {
			if (includeSelf) {
				if (this.test(condition)) {
					selector.push(this);
				}
			}

			return selector;
		});
	}
	/**
	 * 根据条件查找子对象。
	 * @param {string} condition 查找对象的条件。
	 * @param {ObjectQueryOptions} options 选项。
	 * @returns {THING.BaseObject} 返回一个物体
	 * @private
	 * @example
	 * let object = new THING.BaseObject();
	 * let child = new THING.BaseObject({parent: object});
	 * let result = object.find('name == "liming"');
	 * // @expect(result == child);
	 */
	find(condition, options = {}) {
		let recursive = Utils.parseValue(options['recursive'], true);
		let includeSelf = options['includeSelf'];

		if (includeSelf) {
			if (this.test(condition)) {
				return this;
			}
		}

		let _private = this[__.private];

		if (recursive) {
			if (Utils.isString(condition)) {
				// All
				if (condition == '*') {
					return this.children[0];
				}
				else {
					let expression = Selector.buildExpression(condition);
					if (expression) {
						return this.findChildren(child => {
							return Selector.testByExpression(expression, child);
						});
					}
				}
			}
			// Reg Expression
			else if (Utils.isRegExp(condition)) {
				if (_private.children) {
					return this.findChildren(child => {
						return Selector.testByRegExpName(condition, child);
					});
				}
			}
			// Function
			else if (Utils.isFunction(condition)) {
				if (_private.children) {
					return this.findChildren(child => {
						return Selector.testByFunction(condition, child);
					});
				}
			}
		}
		else {
			if (_private.children) {
				return _private.children.find(condition);
			}
		}

		return null;
	}

	/**
	 * 设置子在children中的索引
	 * @param {THING.BaseObject} child 子对象
	 * @param {number} index 索引
	 * @example
	 * let object = new THING.BaseObject();
	 * let child = new THING.BaseObject({parent: object});
	 * object.setChildIndex(child, 0);
	 * // @expect(object.children[0] == child);
	 */
	setChildIndex(child, index) {
		const oriIndex = this.children.indexOf(child);
		this.children.splice(oriIndex, 1);
		this.children.insert(index, child);
	}

	// #endregion

	get isBaseObject() {
		return true;
	}

	get indexOfParent() {
		return this.parent.children.indexOf(this);
	}

}

export { BaseObject }