/** @module agg-house */
import AggRoom from './core/agg-room';
import Config from './core/config';
import {AggHouseInvalidArgumentError} from './types/error';
import deepMerge from 'deepmerge';
/** Class that manages aggregators. */
class AggHouse {
/**
* Initialize an AggHouse.
* @param {Object} optionalConfigs Optional configurations.
*/
constructor(optionalConfigs) {
/** @private {!Object} */
this.aggregatorData_ = {};
/** @private {!Array<AggRoom>} */
this.aggregatorRooms_ = [];
/** @private {!Object} */
this.configs_ = Config.initConfigs(optionalConfigs);
}
/**
* Get a configuration value.
* @param {string} name Configuration name.
* @return {*} Configuration value.
*/
getConfig(name) {
return this.configs_[name];
}
/**
* Get data of an aggregator.
* @param {string} aggregatorName Name of aggregator name to get data from.
* @return {!Object} Aggregator data.
* @throws {AggHouseInvalidArgumentError} Throw an error if an aggregator of
* give name has not been loaded.
*/
getData(aggregatorName) {
if (this.aggregatorRooms_.findIndex((ar) =>
ar.name === aggregatorName) < 0) {
throw new AggHouseInvalidArgumentError('\'' + aggregatorName +
'\' is not loaded!');
}
return Object.assign({}, this.aggregatorData_[aggregatorName]);
}
/**
* Get a list of names and versions of loaded aggregators.
* @return {!Array<Object>}
*/
getLoadedAggregators() {
return this.aggregatorRooms_.map((ar) => {
return {
'name': ar.name,
'version': ar.version,
};
});
}
/**
* Create an AggRoom for an aggregator add it to control list.
* @param {!Aggregator} aggregator Aggregator to load.
* @throws {AggHouseInvalidArgumentError} Throw an error if an aggregator of
* the same name is already loaded.
*/
loadAggregator(aggregator) {
let aggRoom = new AggRoom(aggregator, this);
let aggName = aggRoom.name;
if (this.aggregatorData_[aggRoom.name] !== undefined) {
throw new AggHouseInvalidArgumentError('\'' + aggName +
'\' already loaded!');
}
this.aggregatorData_[aggName] = {};
this.aggregatorRooms_.push(aggRoom);
}
/**
* Process incoming update and deliver them to corresponding aggregators.
* @param {!Object} update Update data.
* @param {number} classId Class ID for data.
*/
processUpdate(update, classId) {
let matchedArCounts = 0;
this.aggregatorRooms_.forEach((ar) => {
if (ar.containsClass(classId)) {
ar.sendUpdate(update);
matchedArCounts++;
}
});
console.info(`Sent update to ${matchedArCounts} aggregator(s).`);
}
/**
* Unload an aggregator and dispose its AggRoom.
* @param {!Aggregator|string} aggregator The aggregator to unload.
*/
unloadAggregator(aggregator) {
let aggName = typeof aggregator === 'string' ? aggName : aggName.name;
let aggRoomIndex = this.aggregatorRooms_.findIndex(
(ar) => ar.name === aggName);
if (aggRoomIndex >= 0) {
this.aggregatorRooms_[aggRoomIndex].dispose();
this.aggregatorRooms_.slice(aggRoomIndex, 1);
delete this.aggregatorData_[aggName];
} else {
throw new AggHouseInvalidArgumentError('\'' + aggName +
'\' not found!');
}
}
/**
* Update data produced by an aggregator.
* @param {string} aggregatorName Name of aggregator name to get data from.
* @param {string} newData New data from aggregator.
* @param {boolean|null} isAppending If is appending to or replacing
* original.
* @throws {AggHouseInvalidArgumentError} Throw an error if an aggregator of
* give name has not been loaded.
*/
updateData(aggregatorName, newData, isAppending) {
if (this.aggregatorRooms_.findIndex((ar) =>
ar.name === aggregatorName) < 0) {
throw new AggHouseInvalidArgumentError('\'' + aggregatorName +
'\' is not loaded!');
}
if (isAppending) {
this.aggregatorData_[aggregatorName] = deepMerge(
this.aggregatorData_[aggregatorName], newData);
} else {
this.aggregatorData_[aggregatorName] = newData;
}
}
}
export default AggHouse;