[ExercisePlanner] updated ExercisePlanner sources
[samples/web/ExercisePlanner.git] / js / app.js
1 /*jslint devel:true*/
2 /*global tizen, $, app, localStorage, Audio, document, unlockScreen, UI */
3 var ExercisePlanner = function () {
4         "use strict";
5 };
6
7 (function () {
8         "use strict";
9
10         ExercisePlanner.prototype = {
11                 /**
12                  * Definition of time for sleep
13                  */
14                 TIME_OF_SLEEP: 8,
15
16                 /**
17                  * Definition one day in hours
18                  */
19                 ONE_DAY: 24,
20
21                 /**
22                  * Stored time of application start
23                  */
24                 applicationStartTime: new Date(),
25
26                 /**
27                  * Cofiguration data will saved for next launch;
28                  * There are default values after install;
29                  */
30                 config: {
31
32                         frequency: {
33                                 workday: 3, // 6 for test
34                                 weekend: 3
35                         },
36
37                         strength: {
38                                 workday: 1,
39                                 weekend: 1
40                         },
41
42                         /**
43                          * List of workouts;
44                          * - timeRanges:style [ everyday, weekend, workday ]; ( workday : mon-fri )
45                          */
46                         exercises: [{
47                                 name: 'bends',
48                                 enabled: true
49                         }, {
50                                 name: 'squats',
51                                 enabled: true
52                         }, {
53                                 name: 'push-ups',
54                                 enabled: false
55                         }],
56
57                         /**
58                          * List of generate available exercises;
59                          */
60                         availableExercises: [],
61
62                         // deprecated for this version;
63                         increasingStrength: true,
64
65                         /**
66                          * Default time ranges
67                          */
68                         timesRanges: [{
69                                 nr: 0,
70                                 start: 8,
71                                 stop: 16,
72                                 duration: 8,
73                                 enabled: true,
74                                 style: 'everyday'
75                         }, {
76                                 nr: 1,
77                                 start: 18,
78                                 stop: 22,
79                                 duration: 4,
80                                 enabled: true,
81                                 style: 'weekend'
82                         }],
83
84                         nearestExercise: -1,
85
86                         count: 0,
87
88                         trainingEnabled: false
89                 },
90                 alarms: {
91                         everyday: [],
92                         workday: [],
93                         weekend: []
94                 },
95
96                 /**
97                  * Used for update GraphSchedule;
98                  * [ workday / weekend ]
99                  */
100                 currentTypeOfPeriods: 'workday',
101                 /**
102                  * Use on form to edit time period;
103                  */
104                 currentEditingTimePeriod: null,
105                 currentEditingTimePeriodId: -1,
106
107                 /**
108                  * Date when alarm will start generating
109                  */
110                 beginDate: null,
111
112                 /**
113                  * use store temporary data for alarms;
114                  */
115                 cache: {},
116
117                 /**
118                  * HTML5 audio element for play audio when alarm is called
119                  */
120                 audioOfAlert: null,
121
122                 /**
123                  * Instance of User Interface
124                  */
125                 ui: null
126         };
127
128         /**
129          * Load configuration of application
130          * (use localStorage)
131          */
132         ExercisePlanner.prototype.loadConfig = function () {
133                 var configStr = localStorage.getItem('config');
134                 if (configStr) {
135                         this.config = JSON.parse(configStr);
136                 } else {
137                         this.removeAllAlarms();
138                         this.sortTimeRanges();
139                 }
140         };
141
142         /**
143          * Save configuration of application
144          * (use localStorage)
145          */
146         ExercisePlanner.prototype.saveConfig = function () {
147                 localStorage.setItem('config', JSON.stringify(this.config));
148         };
149
150         ExercisePlanner.prototype.stopTraining = function () {
151                 this.removeAllAlarms();
152                 this.ui.setStatusRun(this.config.trainingEnabled);
153         };
154
155         ExercisePlanner.prototype.startTraining = function () {
156                 this.ui.setStatusRun(this.config.trainingEnabled);
157                 this.startAlarms();
158         };
159
160         /**
161          * Toggle start/stop alarms for workouts
162          */
163         ExercisePlanner.prototype.appStartStop = function () {
164                 this.config.trainingEnabled = !this.config.trainingEnabled;
165                 if (this.config.trainingEnabled) {
166                         this.startTraining();
167                 } else {
168                         this.stopTraining();
169                 }
170                 this.saveConfig();
171         };
172
173         /**
174          * Closing application with the configuration data saving
175          */
176         ExercisePlanner.prototype.exit = function () {
177                 this.saveConfig();
178                 this.stopMusic();
179                 tizen.application.getCurrentApplication().exit();
180         };
181
182         /**
183          * Sets frequency value and calculates new alarms
184          * @param value
185          */
186         ExercisePlanner.prototype.setFrequency = function (value) {
187                 this.config.frequency[this.config.currentTypeOfPeriods] = parseInt(value, 10);
188
189                 this.saveConfig();
190                 this.generateAlarms();
191                 this.updateGraph(this.config.currentTypeOfPeriods);
192                 this.showNextAlarm();
193         };
194
195         /**
196          * Set Strength value
197          * @param value
198          */
199         ExercisePlanner.prototype.setStrength = function (value) {
200                 this.config.strength[this.config.currentTypeOfPeriods] = parseInt(value, 10);
201                 this.saveConfig();
202         };
203
204         /**
205          * Sending array of exercises to UI for update
206          */
207         ExercisePlanner.prototype.updateExercises = function () {
208                 this.ui.fillExercises(this.config.exercises);
209         };
210
211         /**
212          * Sending array of time ranges to UI for update
213          * & update graph schedule
214          */
215         ExercisePlanner.prototype.updateTimesRanges = function () {
216
217                 this.ui.fillTimesRanges(this.config.timesRanges);
218                 this.ui.graphSchedule.updateTimeRanges();
219         };
220
221         /**
222          * Store exercises in config (and save)
223          * @param newData
224          */
225         ExercisePlanner.prototype.saveExercises = function (newData) {
226                 var i, l;
227
228                 if (newData) {
229                         for (i = 0, l = newData.length; i < l; i += 1) {
230                                 this.config.exercises[i].enabled = newData[i].checked;
231                         }
232                         this.generateNearestExercise();
233                         this.saveConfig();
234                 }
235         };
236
237         /**
238          * When will earliest workout
239          * and show in UI
240          */
241         ExercisePlanner.prototype.showNextAlarm = function showNextAlarm() {
242                 var alarms,
243                         currentDate = new Date();
244
245                 if (this.alarms.everyday.length > 0) {
246                         alarms = this.alarms.everyday;
247                 } else {
248                         alarms = (this.todayIsWorkday()) ? this.alarms.workday : this.alarms.weekend;
249                 }
250
251                 alarms = alarms.filter(function (item) {
252                         return (item.getTime() > currentDate.getTime());
253                 }).sort(function (a, b) {
254                         return a.date - b.date;
255                 });
256
257                 if (this.config.availableExercises.length > 0) {
258                         this.ui.showAlarmInMonitor({
259                                 alarm: alarms[0],
260                                 exerciseName: this.config.availableExercises[this.config.nearestExercise].name,
261                                 numberOfTimes: this.getStrength(this.config.strength.workday, this.config.count)
262                         });
263                 }
264                 this.saveConfig();
265         };
266
267         /**
268          * Change type of periods [workday/weekend] and update graph
269          * @param type
270          */
271         ExercisePlanner.prototype.changeTypeOfPeriods = function changeTypeOfPeriods(type) {
272                 if (this.config.currentTypeOfPeriods !== type) {
273                         this.config.currentTypeOfPeriods = type;
274                         this.updateGraph(this.config.currentTypeOfPeriods);
275                 }
276         };
277
278         /**
279          * Check new exercise name for duplication in existings;
280          * @param name
281          * @returns
282          */
283         ExercisePlanner.prototype.checkExerciseName = function (name) {
284                 var i, l;
285                 name = $.trim(name);
286
287                 for (i = 0, l = this.config.exercises.length; i < l; i += 1) {
288                         if (this.config.exercises[i].name === name) {
289                                 return false;
290                         }
291                 }
292
293                 return true;
294         };
295
296         /**
297          * Add new exercise sent from UI
298          * @param name
299          * @returns {Boolean}
300          */
301         ExercisePlanner.prototype.addExercise = function (name) {
302                 if (this.checkExerciseName(name) === true) {
303                         this.config.exercises.push({
304                                 name: name,
305                                 enabled: false
306                         });
307                         this.saveConfig();
308                         this.ui.fillExercises(this.config.exercises);
309                         return true;
310                 }
311
312                 this.ui.showErrors([{name: 'Given exercise already exists!'}]);
313                 return false;
314         };
315
316         /**
317          * Get number of workouts by frequency
318          * @param value
319          * @returns {number}
320          */
321         ExercisePlanner.prototype.getNumberOfWorkoutsByFrequency = function getNumberOfWorkoutsByFrequency(value) {
322                 var iMap = [1, 2, 4, 8, 16, 24, 150],
323                         // -- times per 24h; proportion to set periods of available time;
324                         numberOfWorkouts = iMap[value];
325
326                 return numberOfWorkouts || 2;
327         };
328
329         /**
330          * Get number of exercises in workout by strength value and optional ;
331          * @param value
332          * @param count
333          * @returns {number}
334          */
335         ExercisePlanner.prototype.getStrength = function strengthMap(value, count) {
336                 var sMap = [1, 1, 2, 4, 10, 20],
337                         base = sMap[value] || 2;
338
339                 count = count || 1;
340                 return Math.round(base * (count / 10 + 1));
341         };
342
343         /**
344          * Generate name of exercise for nearest workout
345          */
346         ExercisePlanner.prototype.generateNearestExercise = function () {
347                 this.config.availableExercises = this.config.exercises.filter(function (item) {
348                         return item.enabled;
349                 });
350                 this.config.nearestExercise = parseInt(Math.random() * this.config.availableExercises.length, 10);
351         };
352
353
354         /**
355          * If user want change work days this method will changing;
356          * @returns {Boolean}
357          */
358         ExercisePlanner.prototype.todayIsWorkday = function todayIsWorkday() {
359                 var day = (new Date()).getDay();
360                 return (day >= 1 && day <= 5);
361         };
362
363         /**
364          * Activate alarms in API.
365          */
366         ExercisePlanner.prototype.startAlarms = function startAlarms() {
367                 // clear old alarms;
368                 this.removeAllAlarms();
369
370                 // add new alarms
371                 this.addAlarmsAllWeek(this.alarms);
372
373                 this.generateNearestExercise();
374                 this.showNextAlarm();
375         };
376
377         /**
378          * Update Graph object
379          * @param {String} typeOfPeriods ['workday'|'weekend']
380          */
381         ExercisePlanner.prototype.updateGraph = function updateGraph(typeOfPeriods) {
382                 var alarms;
383                 if (!this.ui.graphSchedule) {
384                         throw {
385                                 message: 'graph schedule not exists.'
386                         };
387                 }
388
389                 typeOfPeriods = typeOfPeriods || ((this.todayIsWorkday()) ? 'workday' : 'weekend');
390
391                 if (typeOfPeriods === 'workday') {
392                         alarms = this.alarms.workday;
393                 } else {
394                         alarms = this.alarms.weekend;
395                 }
396                 if (alarms.length === 0) {
397                         alarms = this.alarms.everyday;
398                 }
399                 this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray());
400                 this.ui.graphSchedule.pushTimeOfFlags(alarms);
401                 this.ui.graphSchedule.showFlags();
402         };
403
404         /**
405          * Callback function on visibility change;
406          */
407         ExercisePlanner.prototype.onVisibilityChange = function () {
408
409                 switch (document.webkitVisibilityState) {
410                 case 'visible':
411                         this.applicationStartTime = new Date();
412                         this.currentAlarm = this.findCurrentAlarm();
413                         if (this.currentAlarm.length > 0) {
414                                 this.ui.showWaitOk();
415                                 this.startMusic();
416                         }
417                         break;
418                 }
419         };
420
421         /**
422          * Turn off all alarms today
423          */
424         ExercisePlanner.prototype.todayOffAll = function todayOffAll() {
425                 // set begin date to tomorrow;
426                 this.beginDate = new Date();
427                 this.beginDate.setDate(this.beginDate.getDate() + 1);
428                 // recreate alarms;
429                 this.generateAlarms();
430                 this.exit();
431         };
432
433         // Initialize function
434         ExercisePlanner.prototype.init = function init() {
435                 var onUiInitialize = function onUiInitialize() {
436                         // register watcher on visibility change;
437                         document.addEventListener('webkitvisibilitychange', this.onVisibilityChange.bind(this));
438                         this.showNextAlarm();
439                         this.onVisibilityChange();
440                 }.bind(this);
441
442                 this.selfId = tizen.application.getAppContext().appId;
443                 this.ui = new UI();
444                 this.ui.app = this;
445
446                 this.loadConfig();
447                 this.config.currentTypeOfPeriods = (this.todayIsWorkday()) ? 'workday' : 'weekend';
448
449                 this.generateAlarms();
450                 this.ui.initialize(onUiInitialize);
451         };
452 }());