import { Utils } from '../common/Utils';
import { BaseComponent } from './BaseComponent';
const __ = {
private: Symbol('private'),
}
/**
* @class BlueprintComponent
* The blueprint component.
* @memberof THING
* @extends THING.BaseComponent
* @public
*/
class BlueprintComponent extends BaseComponent {
static mustCopyWithInstance = true;
/**
* To load blueprint resource(s) and run them.
*/
constructor() {
super();
this[__.private] = {};
let _private = this[__.private];
_private.pendingPromise = null;
_private.resources = [];
_private.debugger = null;
}
onRemove() {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.dispose();
});
_private.resources.length = 0;
if (_private.debugger) {
_private.debugger.dispose();
_private.debugger = null;
}
_private.pendingPromise = null;
super.onRemove();
});
}
}
// #region Private
// #endregion
/**
* @typedef {Object} BlueprintComponentLoadArgs
* @property {String|Array<String>} url The resource URL(s).
* @property {Object|Array<Object>} data The json data(s).
*/
/**
* Load from URL or data.
* @param {BlueprintComponentLoadArgs} options The options.
* @returns {THING.BlueprintComponent}
* @public
* @example
* let object = new THING.Object3D();
* let blueprints = await object.blueprint.load({ url: './blueprints/myBP.json' });
* // @expect(blueprints.length == 1)
*/
load(options = {}) {
let _private = this[__.private];
let url = options['url'];
let data = options['data'] || [];
let resourceManager = this.app.resourceManager;
_private.pendingPromise = new Promise((resolve, reject) => {
let blueprints = [];
// Get data through url when has url(can use cache in async mode).
if (url) {
if (Utils.isString(url)) {
url = [url];
}
url.forEachAsync((_url) => {
return resourceManager.loadBlueprintAsync(_url).then(datas => {
datas.forEach(data => {
let blueprint = this._loadBlueprintData(data);
blueprints.push(blueprint);
});
}, (err) => {
reject(err);
})
}).then(() => {
resolve(blueprints);
});
}
// Get data through url(in sync mode).
else if (data) {
if (data.info) {
let bodyData = resourceManager.getBlueprintBodyData(data);
// Load blueprint resource(s)
bodyData.forEach(body => {
let blueprint = this._loadBlueprintData(body);
blueprints.push(blueprint);
});
}
else {
let blueprint = this._loadBlueprintData(data);
blueprints.push(blueprint);
}
resolve(blueprints);
}
});
return _private.pendingPromise;
}
_loadBlueprintData(data) {
let _private = this[__.private];
let resources = _private.resources;
let blueprint = Utils.createObject('Blueprint', { app: this.app, object: this.object });
resources.push(blueprint);
blueprint.load(data);
return blueprint;
}
/**
* Run all blueprints.
* @public
*/
run() {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.getRunner().start();
});
}, (err) => {
Utils.error(err)
});
}
}
/**
* clear all blueprints.
* @public
*/
clear() {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.dispose();
});
_private.resources = []
});
}
}
/**
* Stop all blueprints.
* @public
*/
stop() {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.getRunner().stop();
});
});
}
}
/**
* Set variable by name.
* @param {String} name The variable name.
* @param {*} value The variable value.
* @public
*/
setVar(name, value) {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.setVar(name, value);
});
});
}
}
/**
* Set variables.
* @param {Object} value The variables.
* @public
*/
setVars(value) {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.setVars(value);
});
});
}
}
/**
* Register event.
* @param {String} type The event type.
* @param {Function} callback The callback function.
* @public
*/
addEventListener(type, callback) {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.addEventListener(type, callback);
});
});
}
}
/**
* Unregister event.
* @param {String} type The event type.
* @param {Function} callback The callback function.
* @public
*/
removeEventListener(type, callback) {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.removeEventListener(type, callback);
});
});
}
}
/**
* Trigger event.
* @param {String} type The event type.
* @param {Object} event The event info.
* @public
*/
triggerEvent(type, event) {
let _private = this[__.private];
if (_private.pendingPromise) {
_private.pendingPromise.then(() => {
_private.resources.forEach(resource => {
resource.triggerEvent(type, event);
});
});
}
}
getDebugger() {
let _private = this[__.private];
_private.debugger = _private.debugger || Utils.createObject('BlueprintDebugger');
_private.resources.forEach(resource => {
resource.setDebugger(_private.debugger);
});
return _private.debugger;
}
}
export { BlueprintComponent }