1 | 'use strict';
|
2 |
|
3 | var INC = 'inc';
|
4 | var DEC = 'dec';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | function TimedNumber(conf) {
|
18 | this.validate(conf);
|
19 | this.conf = conf;
|
20 | this.current = this.conf.init;
|
21 | this.lastUpdate = this.conf.lastUpdate || Date.now();
|
22 | }
|
23 |
|
24 |
|
25 | TimedNumber.prototype.getValue = function () {
|
26 | switch (this.conf.type) {
|
27 | case INC:
|
28 | return this.calculateCurrentValueForInc();
|
29 | case DEC:
|
30 | return this.calculateCurrentValueForDec();
|
31 | }
|
32 | };
|
33 |
|
34 |
|
35 | TimedNumber.prototype.inc = function (value) {
|
36 | if (!value || isNaN(value)) {
|
37 | return false;
|
38 | }
|
39 | if (this.current + value > this.conf.max) {
|
40 | return false;
|
41 | }
|
42 |
|
43 | if (this.current === this.conf.init) {
|
44 |
|
45 | this.lastUpdate = Date.now();
|
46 | }
|
47 |
|
48 |
|
49 | this.current += value;
|
50 |
|
51 | this.lastUpdate = Date.now();
|
52 |
|
53 | return true;
|
54 | };
|
55 |
|
56 |
|
57 | TimedNumber.prototype.dec = function (value) {
|
58 | if (!value || isNaN(value)) {
|
59 | return false;
|
60 | }
|
61 | if (this.current - value < this.conf.min) {
|
62 | return false;
|
63 | }
|
64 |
|
65 | if (this.current === this.conf.init) {
|
66 |
|
67 | this.lastUpdate = Date.now();
|
68 | }
|
69 |
|
70 |
|
71 | this.current -= value;
|
72 |
|
73 | this.lastUpdate = Date.now();
|
74 |
|
75 | return true;
|
76 | };
|
77 |
|
78 |
|
79 | TimedNumber.prototype.reset = function () {
|
80 | this.current = this.conf.init;
|
81 | this.lastUpdate = Date.now();
|
82 | };
|
83 |
|
84 |
|
85 | TimedNumber.prototype.getMaxValue = function () {
|
86 | return this.conf.max;
|
87 | };
|
88 |
|
89 |
|
90 | TimedNumber.prototype.getMinValue = function () {
|
91 | return this.conf.min;
|
92 | };
|
93 |
|
94 |
|
95 | TimedNumber.prototype.getInterval = function () {
|
96 | return this.conf.interval;
|
97 | };
|
98 |
|
99 |
|
100 | TimedNumber.prototype.getStep = function () {
|
101 | return this.conf.step;
|
102 | };
|
103 |
|
104 |
|
105 | TimedNumber.prototype.getLastUpdate = function () {
|
106 | return this.lastUpdate;
|
107 | };
|
108 |
|
109 |
|
110 | TimedNumber.prototype.toObject = function () {
|
111 | var obj = {};
|
112 | obj.current = this.current;
|
113 | obj.lastUpdate = this.lastUpdate;
|
114 | for (var key in this.conf) {
|
115 | obj[key] = this.conf[key];
|
116 | }
|
117 | return obj;
|
118 | };
|
119 |
|
120 |
|
121 | TimedNumber.prototype.validate = function (conf) {
|
122 | if (!conf.hasOwnProperty('max') || isNaN(conf.max)) {
|
123 | throw new Error('invalid max: ' + conf.max);
|
124 | }
|
125 | if (!conf.hasOwnProperty('min') || isNaN(conf.min) || conf.min >= conf.max) {
|
126 | throw new Error('invalid min: ' + conf.min);
|
127 | }
|
128 | if (!conf.hasOwnProperty('interval') || isNaN(conf.interval) || conf.interval <= 0) {
|
129 | throw new Error('invalid interval: ' + conf.interval);
|
130 | }
|
131 | if (!conf.hasOwnProperty('type') || (conf.type !== INC && conf.type !== DEC)) {
|
132 | throw new Error('invalid type: ' + conf.type);
|
133 | }
|
134 | if (!conf.hasOwnProperty('init') || isNaN(conf.init) || conf.init <= 0) {
|
135 | throw new Error('invalid init: ' + conf.init);
|
136 | }
|
137 | if (!conf.hasOwnProperty('step') || isNaN(conf.step) || conf.step <= 0) {
|
138 | throw new Error('invalid step: ' + conf.step);
|
139 | }
|
140 | if (conf.type === INC && conf.step > conf.max) {
|
141 | throw new Error('step must not be greater than max');
|
142 | }
|
143 | if (conf.type === DEC && conf.step < conf.min) {
|
144 | throw new Error('step must not be smaller than min');
|
145 | }
|
146 | };
|
147 |
|
148 |
|
149 | TimedNumber.prototype.calculateCurrentValueForInc = function () {
|
150 | if (this.current === this.conf.max) {
|
151 | return this.current;
|
152 | }
|
153 | var now = Date.now();
|
154 | var timePast = now - this.lastUpdate;
|
155 | var steps = Math.floor(timePast / this.conf.interval);
|
156 | var incValue = this.conf.step * steps;
|
157 | this.current = (this.current + incValue <= this.conf.max) ? this.current + incValue : this.conf.max;
|
158 | if (incValue) {
|
159 | this.lastUpdate = now;
|
160 | }
|
161 | return this.current;
|
162 | };
|
163 |
|
164 |
|
165 | TimedNumber.prototype.calculateCurrentValueForDec = function () {
|
166 | if (this.current === this.conf.min) {
|
167 | return this.current;
|
168 | }
|
169 | var now = Date.now();
|
170 | var timePast = now - this.lastUpdate;
|
171 | var steps = Math.floor(timePast / this.conf.interval);
|
172 | var decValue = this.conf.step * steps;
|
173 | this.current = (this.current - decValue >= this.conf.min) ? this.current - decValue : this.conf.min;
|
174 | if (decValue) {
|
175 | this.lastUpdate = now;
|
176 | }
|
177 | return this.current;
|
178 | };
|
179 |
|
180 | module.exports = TimedNumber;
|
181 |
|