Chrysostomos for scheduler
[myslice.git] / plugins / scheduler2 / static / js / scheduler2.js
1 /*\r
2 #\r
3 # Copyright (c) 2013 NITLab, University of Thessaly, CERTH, Greece\r
4 #\r
5 # Permission is hereby granted, free of charge, to any person obtaining a copy\r
6 # of this software and associated documentation files (the "Software"), to deal\r
7 # in the Software without restriction, including without limitation the rights\r
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
9 # copies of the Software, and to permit persons to whom the Software is\r
10 # furnished to do so, subject to the following conditions:\r
11 #\r
12 # The above copyright notice and this permission notice shall be included in\r
13 # all copies or substantial portions of the Software.\r
14 #\r
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\r
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
21 # THE SOFTWARE.\r
22 #\r
23 #\r
24 # This is a MySlice plugin for the NITOS Scheduler\r
25 # Nitos Scheduler v1\r
26 #\r
27 */\r
28 \r
29 /* some params */\r
30 var scheduler2;\r
31 var scheduler2Instance;\r
32 //is ctrl keyboard button pressed\r
33 var schedulerCtrlPressed = false;\r
34 //table Id\r
35 var schedulerTblId = "scheduler-reservation-table";\r
36 var schedulerTblFirstColWidth = 150;\r
37 //Some Data\r
38 var schedulerSlotsPerHour = 6;\r
39 var schedulerMaxRows = 12;\r
40 var SchedulerData = [];\r
41 var SchedulerSlots = [];\r
42 var SchedulerDateSelected = new Date();\r
43 var SchedulerDataViewData = [];\r
44 var SchedulerSlotsViewData = [];\r
45 var SchedulerTotalCells;\r
46 var SchedulerTotalVisibleCells;\r
47 //Help Variables\r
48 var _schedulerCurrentCellPosition = 0;\r
49 var _leasesDone = false;\r
50 var _resourcesDone = false;\r
51 //Enable Debug\r
52 var schedulerDebug = true;\r
53 //tmp to delete\r
54 var tmpSchedulerLeases = [];\r
55 \r
56 (function ($) {\r
57     scheduler2 = Plugin.extend({\r
58 \r
59         /** XXX to check\r
60          * @brief Plugin constructor\r
61          * @param options : an associative array of setting values\r
62          * @param element : \r
63          * @return : a jQuery collection of objects on which the plugin is\r
64          *     applied, which allows to maintain chainability of calls\r
65          */\r
66         init: function (options, element) {\r
67             this.classname="scheduler2";\r
68             // Call the parent constructor, see FAQ when forgotten\r
69             this._super(options, element);\r
70             scheduler2Instance = this;\r
71             // We need to remember the active filter for datatables filtering
72             this.filters = Array();\r
73 \r
74 \r
75             SchedulerSlots = schedulerGetSlots(60/schedulerSlotsPerHour);\r
76             //selection from table \r
77             $(window).keydown(function (evt) {\r
78                 if (evt.which == 17) { // ctrl\r
79                     schedulerCtrlPressed = true;\r
80                 }\r
81             }).keyup(function (evt) {\r
82                 if (evt.which == 17) { // ctrl\r
83                     schedulerCtrlPressed = false;\r
84                 }\r
85             });\r
86             $("#" + schedulerTblId).on('mousedown', 'td', rangeMouseDown).on('mouseup', 'td', rangeMouseUp).on('mousemove', 'td', rangeMouseMove);\r
87 \r
88             // Explain this will allow query events to be handled\r
89             // What happens when we don't define some events ?\r
90             // Some can be less efficient\r
91 \r
92             if (schedulerDebug) console.time("Listening_to_queries");\r
93             /* Listening to queries */\r
94
95             this.listen_query(options.query_uuid);
96             this.listen_query(options.query_all_uuid, 'all');\r
97             this.listen_query(options.query_all_resources_uuid, 'all_resources');\r
98             this.listen_query(options.query_lease_uuid, 'lease');\r
99             //this.listen_query(options.query_lease_uuid, 'lease');\r
100             if (schedulerDebug) console.timeEnd("Listening_to_queries");\r
101 \r
102         },\r
103 \r
104         /* Handlers */\r
105 \r
106         /* all_ev QUERY HANDLERS Start */\r
107         on_all_ev_clear_records: function (data) {\r
108             //alert('all_ev clear_records');\r
109         },\r
110         on_all_ev_query_in_progress: function (data) {\r
111            // alert('all_ev query_in_progress');\r
112         },\r
113         on_all_ev_new_record: function (data) {\r
114             //alert('all_ev new_record');\r
115         },\r
116         on_all_ev_query_done: function (data) {\r
117             //alert('all_ev query_done');\r
118         },\r
119         //another plugin has modified something, that requires you to update your display. \r
120         on_all_ev_field_state_changed: function (data) {\r
121             //alert('all_ev query_done');\r
122         },\r
123         /* all_ev QUERY HANDLERS End */\r
124         /* all_resources QUERY HANDLERS Start */\r
125         on_all_resources_clear_records: function (data) {\r
126             //data is empty on load\r
127         },\r
128         on_all_resources_query_in_progress: function (data) {\r
129             //data is empty on load\r
130         },\r
131         on_all_resources_new_record: function (data) {\r
132             //alert(data.toSource());\r
133             if (data.exclusive == true){\r
134                 SchedulerData.push({\r
135                     id: data.urn,\r
136                     index: SchedulerData.length,\r
137                     name: data.hrn,\r
138                     granularity: data.granularity,\r
139                     leases: schedulerGetLeases(60 / schedulerSlotsPerHour, data.granularity),\r
140                     type: data.type,\r
141                     org_resource: data\r
142                 });\r
143                 if (schedulerDebug && SchedulerData[SchedulerData.length - 1].org_resource.network_hrn == 'omf') {\r
144                     SchedulerData[SchedulerData.length - 1].granularity = 1800;\r
145                 }\r
146             }\r
147             //alert(data.toSource());\r
148 \r
149         },\r
150         on_all_resources_query_done: function (data) {\r
151             _resourcesDone = true;\r
152             this._initScheduler();\r
153         },\r
154         //another plugin has modified something, that requires you to update your display. \r
155         on_all_resources_field_state_changed: function (data) {\r
156             //alert('all_resources query_done');\r
157         },\r
158         /* all_resources QUERY HANDLERS End */\r
159         /* lease QUERY HANDLERS Start */\r
160         on_lease_clear_records: function (data) { console.log('clear_records'); },\r
161         on_lease_query_in_progress: function (data) { console.log('lease_query_in_progress'); },\r
162         on_lease_new_record: function (data) {\r
163             if (data.resource.indexOf("nitos")>-1){\r
164                 tmpSchedulerLeases.push({\r
165                     id: schedulerGetSlotId(data.start_time, data.duration, data.granularity),\r
166                     end_id: schedulerGetSlotId(data.end_time, data.duration, data.granularity),\r
167                     slice: data.slice,\r
168                     status: 'reserved',\r
169                     resource: data.resource,\r
170                     network: data.network,\r
171                     start_time: new Date(data.start_time * 1000),\r
172                     start_time_unixtimestamp: data.start_time,\r
173                     end_time: new Date(data.end_time * 1000),\r
174                     end_time_unixtimestamp: data.end_time,\r
175                     lease_type: data.lease_type,\r
176                     granularity: data.granularity,\r
177                     duration: data.duration\r
178                 });\r
179             }\r
180             //console.log(data.toSource()); console.log('lease_new_record');\r
181         },\r
182         on_lease_query_done: function (data) {\r
183             _leasesDone = true;\r
184             this._initScheduler();\r
185             // console.log('lease_query_done');\r
186         },\r
187         //another plugin has modified something, that requires you to update your display. \r
188         on_lease_field_state_changed: function (data) { console.log('lease_field_state_changed'); },\r
189         /* lease QUERY HANDLERS End */\r
190 \r
191 \r
192         // no prefix\r
193         on_filter_added: function (filter) {\r
194             this.filters.push(filter);\r
195             this._SetFiletredResources(this.filters);\r
196             //angular and UI\r
197             var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();\r
198             if (SchedulerDataViewData.length == 0) {\r
199                 $("#plugin-scheduler").hide();\r
200                 $("#plugin-scheduler-empty").show();\r
201                 tmpScope.clearStuff();\r
202             } else {\r
203                 $("#plugin-scheduler-empty").hide();\r
204                 $("#plugin-scheduler").show();\r
205                 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);\r
206             }\r
207         },
208
209         on_filter_removed: function (filter) {
210             // Remove corresponding filters
211             this.filters = $.grep(this.filters, function (x) {\r
212                 return x == filter;\r
213             });\r
214             this._SetFiletredResources(this.filters);\r
215             //angular and UI\r
216             var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();\r
217             if (SchedulerDataViewData.length == 0) {\r
218                 $("#plugin-scheduler").hide();\r
219                 $("#plugin-scheduler-empty").show();\r
220                 tmpScope.clearStuff();\r
221             } else {\r
222                 $("#plugin-scheduler-empty").hide();\r
223                 $("#plugin-scheduler").show();\r
224                 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);\r
225             }\r
226         },
227
228         on_filter_clear: function () {\r
229             this.filters = [];\r
230             this._SetFiletredResources(this.filters);\r
231             //angular and UI\r
232             var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();\r
233             if (SchedulerDataViewData.length == 0) {\r
234                 $("#plugin-scheduler").hide();\r
235                 $("#plugin-scheduler-empty").show();\r
236                 tmpScope.clearStuff();\r
237             } else {\r
238                 $("#plugin-scheduler-empty").hide();\r
239                 $("#plugin-scheduler").show();\r
240                 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);\r
241             }\r
242         },\r
243 \r
244         // ... be sure to list all events here\r
245 \r
246         /* RECORD HANDLERS */\r
247         on_all_new_record: function (record) {\r
248             //alert('on_all_new_record');\r
249         },\r
250 \r
251         debug : function (logTxt) {\r
252             if (typeof window.console != 'undefined') {\r
253                 console.debug(logTxt);\r
254             }\r
255         },\r
256 \r
257         /* INTERNAL FUNCTIONS */\r
258         _initScheduler: function () {\r
259             if (_resourcesDone && _leasesDone)\r
260             {\r
261                 SchedulerDataViewData = SchedulerData;\r
262                 /* GUI setup and event binding */\r
263                 this._FixLeases();\r
264                 this._initUI();\r
265             }\r
266         },\r
267 \r
268         _initUI: function () {\r
269             //alert(1);\r
270             if (schedulerDebug) console.time("_initUI");\r
271             //init DatePicker Start\r
272             $("#DateToRes").datepicker({\r
273                 dateFormat: "yy-mm-dd",\r
274                 minDate: 0,\r
275                 numberOfMonths: 3\r
276             }).change(function () {\r
277                 //Scheduler2.loadWithDate();\r
278                 SchedulerDateSelected = $("#DateToRes").datepicker("getDate");\r
279                 if (SchedulerDateSelected != null && SchedulerDateSelected != '') {\r
280                     for (var i=0; i < SchedulerData.length; i++) {\r
281                         SchedulerData[i].leases = schedulerGetLeases(60 / schedulerSlotsPerHour, SchedulerData[i].granularity);\r
282                     }\r
283                     scheduler2Instance._FixLeases();\r
284                     $('#tblSlider').slider('value', 0);\r
285                     var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();\r
286                     tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);\r
287                 } else {\r
288                     alert("Please select a date, so the scheduler can reserve leases.");\r
289                 }\r
290             }).datepicker('setDate', SchedulerDateSelected);\r
291             /*.click(function () {\r
292                 $("#ui-datepicker-div").css("z-index", 5);\r
293             })*/\r
294             //End init DatePicker\r
295             \r
296             //init Table\r
297             this._FixTable();\r
298             //End init Table\r
299 \r
300             //init Slider\r
301             $('#tblSlider').slider({\r
302                 min: 0,\r
303                 max: SchedulerTotalCells - SchedulerTotalVisibleCells,\r
304                 value: 0,\r
305                 slide: function (event, ui) {\r
306                     //$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);\r
307                     //console.log(ui.value);\r
308                     var angScope = angular.element(document.getElementById('SchedulerCtrl')).scope();\r
309                     if (_schedulerCurrentCellPosition > ui.value) {\r
310                         angScope.moveBackSlot(ui.value, ui.value + SchedulerTotalVisibleCells);\r
311                     }\r
312                     else if (_schedulerCurrentCellPosition < ui.value) {\r
313                         angScope.moveFrontSlot(ui.value, ui.value + SchedulerTotalVisibleCells);\r
314                     }\r
315                     _schedulerCurrentCellPosition = ui.value;\r
316                 }\r
317             });\r
318             //End init Slider\r
319 \r
320             //other stuff\r
321             $("#plugin-scheduler-loader").hide();\r
322             $("#plugin-scheduler").show();\r
323             //fixOddEvenClasses();\r
324             //$("#" + schedulerTblId + " td:not([class])").addClass("free");\r
325             if (schedulerDebug) console.timeEnd("_initUI");\r
326         },\r
327 \r
328         _FixLeases  : function () {\r
329             for (var i = 0; i < tmpSchedulerLeases.length; i++) {\r
330                 var tmpLea = tmpSchedulerLeases[i];\r
331                 if ((schedulerCompareOnDay(tmpLea.start_time, SchedulerDateSelected) == 0) ||\r
332                                 (tmpLea.start_time <= SchedulerDateSelected && SchedulerDateSelected <= tmpLea.end_time) || \r
333                                 (schedulerCompareOnDay(tmpLea.end_time, SchedulerDateSelected) == 0)) {\r
334                     var tmpRes = schedulerFindResourceById(SchedulerData, tmpLea.resource);\r
335                     if (tmpRes != null) {\r
336                         //Replace Lease with current lease from the manifold\r
337                         var orgLease = tmpRes.leases[tmpLea.id];\r
338                         tmpLea['groupid'] = orgLease.groupid;\r
339                         tmpLea['groupIndex'] = orgLease.groupIndex;\r
340                         if (orgLease.groupIndex != 0) {\r
341                             if (!window.console) {\r
342                                 console.warn('there is an error with the leases of the resource :' + tmpRes.name + '\n The lease start in the middle of the granularity!' + '\n The Scheduler plugin might not work!');\r
343                             }\r
344                         }\r
345                         tmpRes.leases[tmpLea.id] = tmpLea;\r
346                         this._ExtractLeaseSlots(tmpRes, tmpRes.leases[tmpLea.id]);\r
347                     }\r
348                 }\r
349             }\r
350         },\r
351 \r
352         _ExtractLeaseSlots: function (tmpRes, lease) {\r
353             var tmpStartDate = lease.start_time;\r
354             var tmpEndDate = lease.end_time;\r
355             var startLoop; var toLoop;\r
356             if (schedulerCompareOnDay(lease.start_time,lease.end_time) == 0) {\r
357                 //in the same date\r
358                 startLoop = lease.id;\r
359                 toLoop = lease.end_id;\r
360             } else if (lease.start_time < SchedulerDateSelected && SchedulerDateSelected < lease.end_time) {\r
361                 //one hole day (more than 3days)\r
362                 startLoop = 0;\r
363                 toLoop = tmpRes.leases.length;\r
364             } else if (schedulerCompareOnDay(lease.start_time, SchedulerDateSelected) == 0) {\r
365                 //the same day and extends\r
366                 startLoop = lease.id;\r
367                 toLoop = tmpRes.leases.length;\r
368             } else if (schedulerCompareOnDay(lease.end_time, SchedulerDateSelected) == 0) {\r
369                 //extends to the last say\r
370                 startLoop = 0;\r
371                 toLoop = lease.end_id;\r
372             }\r
373             //var minutGran = tmpRes.granularity * 60;\r
374             for (var li = lease.id; li < toLoop; li++) {\r
375                 tmpRes.leases[li].status = 'reserved';\r
376             }\r
377             \r
378             //reserved\r
379             //tmpRes.leases[tmpLea.id\r
380         },\r
381 \r
382         _FixTable: function () {\r
383             var colWidth = 50;\r
384             SchedulerTotalCells = SchedulerSlots.length;\r
385             $('#' + schedulerTblId + ' thead tr th:eq(0)').css("width", schedulerTblFirstColWidth); //.css("display", "block");\r
386             //this get width might need fix depending on the template \r
387             var tblwidth = $('#scheduler-tab').parent().outerWidth();\r
388             SchedulerTotalVisibleCells = parseInt((tblwidth - schedulerTblFirstColWidth) / colWidth);\r
389 \r
390             //if (SchedulerData.length == 0) {\r
391             //    //puth some test data\r
392             //    SchedulerData.push({ name: 'xyz+aaa', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'xyz+aaa', type: 'node' });\r
393             //    SchedulerData.push({ name: 'xyz+bbb', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'xyz+bbb', type: 'node' });\r
394             //    SchedulerData.push({ name: 'xyz+ccc', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'xyz+ccc', type: 'node' });\r
395             //    SchedulerData.push({ name: 'nitos1', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'nitos1', type: 'node' });\r
396             //}\r
397             var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();\r
398             tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);\r
399 \r
400         },\r
401 \r
402         _SetFiletredResources : function (filters) {\r
403             if (filters.length > 0) {\r
404                 SchedulerDataViewData = new Array();\r
405                 var tmpAddIt = true;\r
406                 for (var i = 0; i < SchedulerData.length; i++) {\r
407                     loopfilters:\r
408                     for (var f = 0; f < filters.length; f++) {\r
409                         tmpAddIt = this._FilterResource(SchedulerData[i], filters[f]);\r
410                         if (tmpAddIt == false) break loopfilters;\r
411                     }\r
412                     if (tmpAddIt) {\r
413                         SchedulerDataViewData.push(SchedulerData[i]);\r
414                     }\r
415                 }\r
416             } else {\r
417                 SchedulerDataViewData = SchedulerData;\r
418             }\r
419         },\r
420 \r
421         _FilterResource: function (resource, filter) {\r
422             var key = filter[0];\r
423             var op = filter[1];\r
424             var value = filter[2];\r
425             var colValue = resource.org_resource[key];\r
426             var ret = true;\r
427             if (schedulerDebug &&  colValue == 'omf') colValue = 'nitos';\r
428 \r
429             if (op == '=' || op == '==') {\r
430                 if (colValue != value || colValue == null || colValue == "" || colValue == "n/a")
431                     ret = false;\r
432             } else if (op == 'included') {\r
433                 $.each(value, function (i, x) {\r
434                     if (x == colValue) {\r
435                         ret = true;\r
436                         return false;\r
437                     } else {\r
438                         ret = false;\r
439                     }\r
440                 });\r
441             } else if (op == '!=') {\r
442                 if (colValue == value || colValue == null || colValue == "" || colValue == "n/a")
443                     ret = false;\r
444             }\r
445 \r
446             return ret;\r
447         },\r
448 \r
449         _SetPeriodInPage: function (start, end) {\r
450         }\r
451     });\r
452 \r
453     //Sched2 = new Scheduler2();\r
454 \r
455     /* Plugin registration */\r
456     $.plugin('Scheduler2', scheduler2);\r
457 \r
458     // TODO Here use cases for instanciating plugins in different ways like in the pastie.\r
459 \r
460 \r
461 })(jQuery);\r
462 \r
463 \r
464 \r