diff --git a/trafficlights.html b/trafficlights.html new file mode 100644 index 0000000..4d41fa9 --- /dev/null +++ b/trafficlights.html @@ -0,0 +1,13 @@ + + +Traffic Lights + + + +

+ + + + + + \ No newline at end of file diff --git a/trafficlights.js b/trafficlights.js new file mode 100644 index 0000000..d05f2f8 --- /dev/null +++ b/trafficlights.js @@ -0,0 +1,256 @@ +/** + * Constructs EventEmitter + * + * @constructor + * @this {EventEmitter} + */ + +function EventEmitter() { + /** @private */ this.__listeners = {}; + +/** + * Adds event listener + * + * + * @this {EventEmitter} + * @param {string} event + * @param {func} listener + */ + EventEmitter.prototype.addListener = function (event, listener) { + if (this.__listeners[event] === undefined) { + this.__listeners[event] = []; + } + this.__listeners[event].push(listener); + }; + +/** + * Removes event listener + * + * + * @this {EventEmitter} + * @param {string} event + * @param {func} listener + */ + EventEmitter.prototype.removeListener = function (event, listener) { + if (this.__listeners[event] !== undefined) { + for (var i = 0; i < this.__listeners[event].length; i++) { + if (this.__listeners[event][i] === listener) + this.__listeners[event].splice(i,1); + } + } + }; + +/** + * Returns function to call in setTimeout + * + * @private + * @this {EventEmitter} + * @param {string} event + * @param {int} position + * @param {string} data Optional data + */ + EventEmitter.prototype.__returnFunction = function (event, position, data) { + return function () { + this.__listeners[event][position](data); + }.bind(this); + }; + +/** + * Emits event + * + * + * @this {EventEmitter} + * @param {string} event + * @param {string} data Optional data + */ + EventEmitter.prototype.emit = function (event, data) { + if (this.__listeners[event] !== undefined) { + for (var i = 0; i < this.__listeners[event].length; i++) { + setTimeout(this.__returnFunction(event, i, data), 0); + } + } + }; + +} + +/** + * Constructs new TrafficLight object + * + * + * @this {TrafficLight} + * @constructor + * @param {int} redTime + * @param {int} yellowTime + * @param {int} greenTime + */ + +function TrafficLight(redTime, yellowTime, greenTime) { + /** @private */ this.__trammode = null; + /** @private */ this.__tramtimer = null; + /** @private */ this.__timer = null; + /** @private */ this.__tramstate = null; + /** @private */ this.__state = null; + /** @private */ this.__stateChangedTime = null; + /** @private */ this.__redTime = redTime; + /** @private */ this.__yellowTime = yellowTime; + /** @private */ this.__greenTime = greenTime; + /** @private */ this.__tramWaitTime = 3000; + /** @private */ this.__tramGreenTime = 10000; + /** @private */ this.__usefulCoefficient = 0.7; + + +/** + * Sets new timer for color changes and checks if the is only one timer + * + * @private + * @this {TrafficLight} + * @param {int} delay + * @param {func} func + * @param {string} data Optional data + */ + TrafficLight.prototype.__setnewtimer = function (delay, func) { + if (this.__timer) { + clearTimeout(this.__timer); + } + this.__stateChangedTime = new Date(); + this.__timer = setTimeout(func, delay); + }; + +/** + * Returns amount of time this color should be active + * + * @private + * @this {TrafficLight} + */ + TrafficLight.prototype.__currentStateTime = function () { + return this['__' + this.__state + 'Time']; + }; + +/** + * Changes color to red + * + * @this {TrafficLight} + */ + TrafficLight.prototype.toRed = function () { + console.log('Changed to red'); + this.__state = 'red'; + this.__setnewtimer(this.__redTime, function () { + this.toGreen(); + }.bind(this)); + }; + +/** + * Changes color to green + * + * @this {TrafficLight} + */ + TrafficLight.prototype.toGreen = function () { + console.log('Changed to green'); + this.__state = 'green'; + this.__setnewtimer(this.__greenTime, function () { + this.toYellow(); + }.bind(this)); + }; + +/** + * Changes color to yellow + * + * @this {TrafficLight} + */ + TrafficLight.prototype.toYellow = function () { + console.log('Changed to yellow'); + this.__state = 'yellow'; + this.__setnewtimer(this.__yellowTime, function () { + this.toRed(); + }.bind(this)); + }; + +/** + * Exits tram mode + * + * @private + * @this {TrafficLight} + */ + TrafficLight.prototype.__exittrammode = function () { + console.log('Exit tram mode'); + this.__tramstate = null; + this.__trammode = null; + if (new Date() - this.__stateChangedTime > this.__usefulCoefficient * this.__currentStateTime()) { + switch (this.__state) { + case 'red': this.toGreen(); break; + case 'yellow': this.toRed(); break; + case 'green': this.toYellow(); break; + } + } + }; + +/** + * Enters tram mode + * + * @private + * @this {TrafficLight} + */ + TrafficLight.prototype.__entertrammode = function () { + console.log('Entering tram mode'); + this.__trammode = 'using'; + this.__tramstate = 'green'; + this.__tramtimer = setTimeout(function () { + this.__exittrammode(); + }.bind(this), this.__tramGreenTime); + }; + +/** + * Tram mode enter callback for Tram event + * + * @private + * @this {TrafficLight} + */ + TrafficLight.prototype.__tramcallback = function (data) { + if (!this.__trammode) { + console.log('Handling tram event'); + this.__trammode = 'waiting'; + this.__tramtimer = setTimeout(function () { + this.__entertrammode(); + }.bind(this), this.__tramWaitTime); + } + }; + +/** + * Subscribes to Tram event of specified TrafficLight + * + * + * @this {TrafficLight} + * @param {object} event + */ + TrafficLight.prototype.tramsubscribe = function (event) { + event.addListener('tram', function() { + this.__tramcallback(); + }.bind(this)); + }; + + +/** + * Returns current state + * + * + * @this {TrafficLight} + */ + TrafficLight.prototype.state = function () { + if (this.__trammode == 'using') + return this.__tramstate; + return this.__state; + }; + + this.toGreen(); +} + +changeDOM = function () { + document.getElementById('colorParagraph').innerHTML = tl.state(); +}; + + +var tl = new TrafficLight(5000, 5000, 5000); +var event = new EventEmitter(); +tl.tramsubscribe(event); +console.log('Tram event will emit in 3 seconds'); +setTimeout(function(){event.emit('tram')}, 3000); \ No newline at end of file