Source: agg-house.js

/** @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;