add QuotaExceededError exception handling to saveConfig function
[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                 try {
148                         localStorage.setItem('config', JSON.stringify(this.config));
149                 } catch (e) {
150                         if (e.code === 22) //QuotaExceededError
151                                 this.ui.showErrors([{name: 'Not enough memory. Please remove unnecessary files'}]);
152                 }
153         };
154
155         ExercisePlanner.prototype.stopTraining = function () {
156                 this.removeAllAlarms();
157                 this.ui.setStatusRun(this.config.trainingEnabled);
158         };
159
160         ExercisePlanner.prototype.startTraining = function () {
161                 this.ui.setStatusRun(this.config.trainingEnabled);
162                 this.startAlarms();
163         };
164
165         /**
166          * Toggle start/stop alarms for workouts
167          */
168         ExercisePlanner.prototype.appStartStop = function () {
169                 this.config.trainingEnabled = !this.config.trainingEnabled;
170                 if (this.config.trainingEnabled) {
171                         this.startTraining();
172                 } else {
173                         this.stopTraining();
174                 }
175                 this.saveConfig();
176         };
177
178         /**
179          * Closing application with the configuration data saving
180          */
181         ExercisePlanner.prototype.exit = function () {
182                 this.saveConfig();
183                 this.stopMusic();
184                 tizen.application.getCurrentApplication().exit();
185         };
186
187         /**
188          * Sets frequency value and calculates new alarms
189          * @param value
190          */
191         ExercisePlanner.prototype.setFrequency = function (value) {
192                 this.config.frequency[this.config.currentTypeOfPeriods] = parseInt(value, 10);
193
194                 this.saveConfig();
195                 this.generateAlarms();
196                 this.updateGraph(this.config.currentTypeOfPeriods);
197                 this.showNextAlarm();
198         };
199
200         /**
201          * Set Strength value
202          * @param value
203          */
204         ExercisePlanner.prototype.setStrength = function (value) {
205                 this.config.strength[this.config.currentTypeOfPeriods] = parseInt(value, 10);
206                 this.saveConfig();
207         };
208
209         /**
210          * Sending array of exercises to UI for update
211          */
212         ExercisePlanner.prototype.updateExercises = function () {
213                 this.ui.fillExercises(this.config.exercises);
214         };
215
216         /**
217          * Sending array of time ranges to UI for update
218          * & update graph schedule
219          */
220         ExercisePlanner.prototype.updateTimesRanges = function () {
221
222                 this.ui.fillTimesRanges(this.config.timesRanges);
223                 this.ui.graphSchedule.updateTimeRanges();
224         };
225
226         /**
227          * Store exercises in config (and save)
228          * @param newData
229          */
230         ExercisePlanner.prototype.saveExercises = function (newData) {
231                 var i, l;
232
233                 if (newData) {
234                         for (i = 0, l = newData.length; i < l; i += 1) {
235                                 this.config.exercises[i].enabled = newData[i].checked;
236                         }
237                         this.generateNearestExercise();
238                         this.saveConfig();
239                 }
240         };
241
242         /**
243          * When will earliest workout
244          * and show in UI
245          */
246         ExercisePlanner.prototype.showNextAlarm = function showNextAlarm() {
247                 var alarms,
248                         currentDate = new Date();
249
250                 if (this.alarms.everyday.length > 0) {
251                         alarms = this.alarms.everyday;
252                 } else {
253                         alarms = (this.todayIsWorkday()) ? this.alarms.workday : this.alarms.weekend;
254                 }
255
256                 alarms = alarms.filter(function (item) {
257                         return (item.getTime() > currentDate.getTime());
258                 }).sort(function (a, b) {
259                         return a.date - b.date;
260                 });
261
262                 if (this.config.availableExercises.length > 0) {
263                         this.ui.showAlarmInMonitor({
264                                 alarm: alarms[0],
265                                 exerciseName: this.config.availableExercises[this.config.nearestExercise].name,
266                                 numberOfTimes: this.getStrength(this.config.strength.workday, this.config.count)
267                         });
268                 }
269                 this.saveConfig();
270         };
271
272         /**
273          * Change type of periods [workday/weekend] and update graph
274          * @param type
275          */
276         ExercisePlanner.prototype.changeTypeOfPeriods = function changeTypeOfPeriods(type) {
277                         this.config.currentTypeOfPeriods = type;
278                         this.updateGraph(this.config.currentTypeOfPeriods);
279         };
280
281         /**
282          * Check new exercise name for duplication in existings;
283          * @param name
284          * @returns
285          */
286         ExercisePlanner.prototype.checkExerciseName = function (name) {
287                 var i, l;
288                 name = $.trim(name);
289
290                 for (i = 0, l = this.config.exercises.length; i < l; i += 1) {
291                         if (this.config.exercises[i].name === name) {
292                                 return false;
293                         }
294                 }
295
296                 return true;
297         };
298
299         /**
300          * Add new exercise sent from UI
301          * @param name
302          * @returns {Boolean}
303          */
304         ExercisePlanner.prototype.addExercise = function (name) {
305                 if (this.checkExerciseName(name) === true) {
306                         this.config.exercises.push({
307                                 name: name,
308                                 enabled: false
309                         });
310                         this.saveConfig();
311                         this.ui.fillExercises(this.config.exercises);
312                         return true;
313                 }
314
315                 this.ui.showErrors([{name: 'Given exercise already exists!'}]);
316                 return false;
317         };
318
319         /**
320          * Get number of workouts by frequency
321          * @param value
322          * @returns {number}
323          */
324         ExercisePlanner.prototype.getNumberOfWorkoutsByFrequency = function getNumberOfWorkoutsByFrequency(value) {
325                 var iMap = [1, 2, 4, 8, 16, 24, 150],
326                         // -- times per 24h; proportion to set periods of available time;
327                         numberOfWorkouts = iMap[value];
328
329                 return numberOfWorkouts || 2;
330         };
331
332         /**
333          * Get number of exercises in workout by strength value and optional ;
334          * @param value
335          * @param count
336          * @returns {number}
337          */
338         ExercisePlanner.prototype.getStrength = function strengthMap(value, count) {
339                 var sMap = [1, 1, 2, 4, 10, 20],
340                         base = sMap[value] || 2;
341
342                 count = count || 1;
343                 return Math.round(base * (count / 10 + 1));
344         };
345
346         /**
347          * Generate name of exercise for nearest workout
348          */
349         ExercisePlanner.prototype.generateNearestExercise = function () {
350                 this.config.availableExercises = this.config.exercises.filter(function (item) {
351                         return item.enabled;
352                 });
353                 this.config.nearestExercise = parseInt(Math.random() * this.config.availableExercises.length, 10);
354         };
355
356
357         /**
358          * If user want change work days this method will changing;
359          * @returns {Boolean}
360          */
361         ExercisePlanner.prototype.todayIsWorkday = function todayIsWorkday() {
362                 var day = (new Date()).getDay();
363                 return (day >= 1 && day <= 5);
364         };
365
366         /**
367          * Activate alarms in API.
368          */
369         ExercisePlanner.prototype.startAlarms = function startAlarms() {
370                 // clear old alarms;
371                 this.removeAllAlarms();
372
373                 // add new alarms
374                 this.addAlarmsAllWeek(this.alarms);
375
376                 this.generateNearestExercise();
377                 this.showNextAlarm();
378         };
379
380         /**
381          * Update Graph object
382          * @param {String} typeOfPeriods ['workday'|'weekend']
383          */
384         ExercisePlanner.prototype.updateGraph = function updateGraph(typeOfPeriods) {
385                 var alarms;
386                 if (!this.ui.graphSchedule) {
387                         throw {
388                                 message: 'graph schedule not exists.'
389                         };
390                 }
391
392                 typeOfPeriods = typeOfPeriods || ((this.todayIsWorkday()) ? 'workday' : 'weekend');
393
394                 if (typeOfPeriods === 'workday') {
395                         alarms = this.alarms.workday;
396                 } else {
397                         alarms = this.alarms.weekend;
398                 }
399                 if (alarms.length === 0) {
400                         alarms = this.alarms.everyday;
401                 }
402                 this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray());
403                 this.ui.graphSchedule.pushTimeOfFlags(alarms);
404                 this.ui.graphSchedule.showFlags();
405         };
406
407         /**
408          * Callback function on visibility change;
409          */
410         ExercisePlanner.prototype.onVisibilityChange = function () {
411
412                 switch (document.webkitVisibilityState) {
413                 case 'visible':
414                         this.applicationStartTime = new Date();
415                         this.currentAlarm = this.findCurrentAlarm();
416                         if (this.currentAlarm.length > 0) {
417                                 this.ui.showWaitOk();
418                                 this.startMusic();
419                         }
420                         break;
421                 }
422         };
423
424         /**
425          * Turn off all alarms today
426          */
427         ExercisePlanner.prototype.todayOffAll = function todayOffAll() {
428                 // set begin date to tomorrow;
429                 this.beginDate = new Date();
430                 this.beginDate.setDate(this.beginDate.getDate() + 1);
431                 // recreate alarms;
432                 this.generateAlarms();
433                 this.exit();
434         };
435
436         // Initialize function
437         ExercisePlanner.prototype.init = function init() {
438                 var onUiInitialize = function onUiInitialize() {
439                         // register watcher on visibility change;
440                         document.addEventListener('webkitvisibilitychange', this.onVisibilityChange.bind(this));
441                         this.showNextAlarm();
442                         this.onVisibilityChange();
443                 }.bind(this);
444
445                 this.selfId = tizen.application.getAppContext().appId;
446                 this.ui = new UI();
447                 this.ui.app = this;
448
449                 this.loadConfig();
450                 this.config.currentTypeOfPeriods = (this.todayIsWorkday()) ? 'workday' : 'weekend';
451
452                 this.generateAlarms();
453                 this.ui.initialize(onUiInitialize);
454         };
455 }());