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