Source: selector/AsyncSelector.js

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

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

/**
 * @class AsyncSelector
 * The async selector.
 * @memberof THING
 */
class AsyncSelector {

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

		_private.queryResolves = new Map();

		_private.queryOrderID = 1;
		_private.commands = [];

		_private.worker = null;

		// Create selector worker
		_private.worker = new Worker(param['workerUrl']);
		_private.worker.onmessage = (ev) => {
			let data = ev.data;
			let type = data.type;

			switch (type) {
				case 'queryResult':
					let queryOrderID = data.queryOrderID;
					let orderIDs = data.orderIDs;

					let resolve = _private.queryResolves.get(queryOrderID);
					if (resolve) {
						_private.queryResolves.delete(queryOrderID);

						resolve({ orderIDs });
					}

					break;

				default:
					break;
			}
		}
	}

	// #region Private

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

		let commands = _private.commands;

		// Flush commands
		if (commands.length) {
			_private.worker.postMessage({
				type: 'commands',
				commands
			});

			commands.length = 0;
		}
	}

	// #endregion

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

		let parent = object.parent;

		_private.commands.push({
			type: 'addObject',
			object: {
				types: object.__types,
				orderId: object.orderId,
				parentObjectOrderID: parent ? parent.orderId : null,
				id: object.id,
				uuid: object.uuid,
				name: object.name,
				queryable: object.queryable,
			}
		});
	}

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

		_private.commands.push({
			type: 'removeObject',
			orderId: object.orderId
		});
	}

	updateObjectAttribute(object, key, value) {
		let _private = this[__.private];

		_private.commands.push({
			type: key,
			orderId: object.orderId,
			value
		});
	}

	queryAsync(root, recursive, condition) {
		let _private = this[__.private];

		return new Promise((resolve, reject) => {
			this._flushCommands();

			// Create query parameters
			let param = {
				type: 'query',
				queryOrderID: _private.queryOrderID++,
				rootOrderID: root.orderId,
				recursive,
				condition
			};

			// Wait for query result
			_private.queryResolves.set(param.queryOrderID, resolve);

			// Start to query in background thread
			_private.worker.postMessage(param);
		});
	}

	selectAsync(objects, condition) {
		let _private = this[__.private];

		return new Promise((resolve, reject) => {
			this._flushCommands();

			// Create query parameters
			let param = {
				type: 'select',
				queryOrderID: _private.queryOrderID++,
				objectOrderIDs: objects.map(object => { return object.orderId; }),
				condition
			};

			// Wait for query result
			_private.queryResolves.set(param.queryOrderID, resolve);

			// Start to query in background thread
			_private.worker.postMessage(param);
		});
	}

}

export { AsyncSelector };