const EventEmitter = require('events');
////////////////////////////////////////////////
// the default device manager
const {Manager} = require('../devices/cleware-switch1');
////////////////////////////////////////////////
/**
* Selects a physical traffic light to use.
* @memberof selectors
* @extends EventEmitter
* @package
*/
class PhysicalTrafficLightSelector extends EventEmitter {
/**
* Selects a physical traffic light to use.
* Checks-out and uses a specific traffic light or the first available one
* to issue commands.
* @see physical.DeviceManager#startMonitoring
* @param {object} [options] - Options.
* @param {physical.DeviceManager} [options.manager] - The Device Manager to use.
* @param {string|number} [options.serialNum] - The serial number of the
* traffic light to use, if available. Cleware USB traffic lights have
* a numeric serial number.
*/
constructor({manager = Manager, serialNum = null} = {}) {
super();
this.manager = manager;
this.serialNum = serialNum;
this.devicesBySerialNum = {};
this.manager.startMonitoring();
this.manager.on('added', () => {
if (this._device) return; // there's currently a device checked-out
/**
* Traffic light enabled event.
* Only fired if there's currently no checked-out traffic light.
* @event selectors.PhysicalTrafficLightSelector#enabled
*/
this.emit('enabled');
});
}
/**
* Called to close this instance and to stop monitoring for devices.
* Should be done as the last operation before exiting the process.
* @see physical.DeviceManager#stopMonitoring
*/
close() {
this.manager.stopMonitoring();
}
/**
* Retrieves a traffic light for exclusive usage of the caller,
* or `null` if one could not be found or checked-out.
* Traffic lights are released (checked-in) when disconnected.
* @returns {physical.PhysicalTrafficLight} - A traffic light, or `null`.
*/
resolveTrafficLight() {
if (this._device) return this._device.trafficLight;
let device = this._selectDevice();
if (!device || !device.trafficLight.checkOut()) return null;
this._device = device;
this._registerDeviceIfNeeded(device);
return device.trafficLight;
}
_selectDevice() {
let devices = this.manager.allDevices()
.filter(d => d.trafficLight.isAvailable);
return this.serialNum
? devices.filter(d => d.serialNum == this.serialNum)[0] // eslint-disable-line eqeqeq
: devices[0];
}
_registerDeviceIfNeeded(device) {
let sn = device.serialNum;
if (this.devicesBySerialNum[sn]) return; // already registered
this.devicesBySerialNum[sn] = device;
device.on('disconnected', () => {
if (this._device !== device) return; // not the current device
device.trafficLight.checkIn();
this._device = null;
/**
* Traffic light disabled event.
* Only fired if the specific traffic light that was checked-out was disconnected.
* @event selectors.PhysicalTrafficLightSelector#disabled
*/
this.emit('disabled');
});
}
/**
* Logs information about known devices.
* @param {object} [logger=console] - A Console-like object for logging.
*/
logInfo(logger = console) {
this.manager.logInfo(logger);
}
}
////////////////////////////////////////////////
module.exports = {
PhysicalTrafficLightSelector,
SelectorCtor: PhysicalTrafficLightSelector
};