3 # Copyright (c) 2013 NITLab, University of Thessaly, CERTH, Greece
\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
12 # The above copyright notice and this permission notice shall be included in
\r
13 # all copies or substantial portions of the Software.
\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
24 # This is a MySlice plugin for the NITOS Scheduler
\r
25 # Nitos Scheduler v1
\r
31 var scheduler2Instance;
\r
32 //is ctrl keyboard button pressed
\r
33 var schedulerCtrlPressed = false;
\r
35 var schedulerTblId = "scheduler-reservation-table";
\r
36 var schedulerTblFirstColWidth = 150;
\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
48 var _schedulerCurrentCellPosition = 0;
\r
49 var _leasesDone = false;
\r
50 var _resourcesDone = false;
\r
52 var schedulerDebug = true;
\r
54 var tmpSchedulerLeases = [];
\r
57 scheduler2 = Plugin.extend({
\r
60 * @brief Plugin constructor
\r
61 * @param options : an associative array of setting values
\r
63 * @return : a jQuery collection of objects on which the plugin is
\r
64 * applied, which allows to maintain chainability of calls
\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
\r
72 this.filters = Array();
\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
81 }).keyup(function(evt) {
\r
82 if (evt.which == 17) { // ctrl
\r
83 schedulerCtrlPressed = false;
\r
86 $("#" + schedulerTblId).on('mousedown', 'td', rangeMouseDown).on('mouseup', 'td', rangeMouseUp).on('mousemove', 'td', rangeMouseMove);
\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
92 if (schedulerDebug) console.time("Listening_to_queries");
\r
93 /* Listening to queries */
\r
95 this.listen_query(options.query_uuid);
\r
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
106 /* all_ev QUERY HANDLERS Start */
\r
107 on_all_ev_clear_records: function(data) {
\r
108 //alert('all_ev clear_records');
\r
110 on_all_ev_query_in_progress: function(data) {
\r
111 // alert('all_ev query_in_progress');
\r
113 on_all_ev_new_record: function(data) {
\r
114 //alert('all_ev new_record');
\r
116 on_all_ev_query_done: function(data) {
\r
117 //alert('all_ev query_done');
\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
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
128 on_all_resources_query_in_progress: function(data) {
\r
129 //data is empty on load
\r
131 on_all_resources_new_record: function(data) {
\r
132 //alert(data.toSource());
\r
133 if (data.exclusive == true) {
\r
134 var tmpGran = schedulerDebug && data.granularity == null ? 1800 : data.granularity;
\r
135 SchedulerData.push({
\r
137 index: SchedulerData.length,
\r
139 granularity: tmpGran,
\r
140 leases: schedulerGetLeases(60 / schedulerSlotsPerHour, tmpGran),
\r
144 /*if (schedulerDebug && SchedulerData[SchedulerData.length - 1].org_resource.network_hrn == 'omf') {
\r
145 SchedulerData[SchedulerData.length - 1].granularity = 1800;
\r
148 //alert(data.toSource());
\r
151 on_all_resources_query_done: function(data) {
\r
152 _resourcesDone = true;
\r
153 this._initScheduler();
\r
155 //another plugin has modified something, that requires you to update your display.
\r
156 on_all_resources_field_state_changed: function(data) {
\r
157 //alert('all_resources query_done');
\r
159 /* all_resources QUERY HANDLERS End */
\r
160 /* lease QUERY HANDLERS Start */
\r
161 on_lease_clear_records: function(data) { console.log('clear_records'); },
\r
162 on_lease_query_in_progress: function(data) { console.log('lease_query_in_progress'); },
\r
163 on_lease_new_record: function(data) {
\r
164 if (data.resource.indexOf("nitos") > -1) {
\r
165 tmpSchedulerLeases.push({
\r
166 id: schedulerGetSlotId(data.start_time, data.duration, data.granularity),
\r
167 end_id: schedulerGetSlotId(data.end_time, data.duration, data.granularity),
\r
169 status: 'reserved',
\r
170 resource: data.resource,
\r
171 network: data.network,
\r
172 start_time: new Date(data.start_time * 1000),
\r
173 start_time_unixtimestamp: data.start_time,
\r
174 end_time: new Date(data.end_time * 1000),
\r
175 end_time_unixtimestamp: data.end_time,
\r
176 lease_type: data.lease_type,
\r
177 granularity: data.granularity,
\r
178 duration: data.duration
\r
181 //console.log(data.toSource()); console.log('lease_new_record');
\r
183 on_lease_query_done: function(data) {
\r
184 _leasesDone = true;
\r
185 this._initScheduler();
\r
186 // console.log('lease_query_done');
\r
188 //another plugin has modified something, that requires you to update your display.
\r
189 on_lease_field_state_changed: function(data) { console.log('lease_field_state_changed'); },
\r
190 /* lease QUERY HANDLERS End */
\r
194 on_filter_added: function(filter) {
\r
195 this.filters.push(filter);
\r
196 this._SetFiletredResources(this.filters);
\r
198 var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();
\r
199 if (SchedulerDataViewData.length == 0) {
\r
200 $("#plugin-scheduler").hide();
\r
201 $("#plugin-scheduler-empty").show();
\r
202 tmpScope.clearStuff();
\r
204 $("#plugin-scheduler-empty").hide();
\r
205 $("#plugin-scheduler").show();
\r
206 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);
\r
210 on_filter_removed: function(filter) {
\r
211 // Remove corresponding filters
\r
212 this.filters = $.grep(this.filters, function(x) {
\r
213 return x == filter;
\r
215 this._SetFiletredResources(this.filters);
\r
217 var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();
\r
218 if (SchedulerDataViewData.length == 0) {
\r
219 $("#plugin-scheduler").hide();
\r
220 $("#plugin-scheduler-empty").show();
\r
221 tmpScope.clearStuff();
\r
223 $("#plugin-scheduler-empty").hide();
\r
224 $("#plugin-scheduler").show();
\r
225 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);
\r
229 on_filter_clear: function() {
\r
231 this._SetFiletredResources(this.filters);
\r
233 var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();
\r
234 if (SchedulerDataViewData.length == 0) {
\r
235 $("#plugin-scheduler").hide();
\r
236 $("#plugin-scheduler-empty").show();
\r
237 tmpScope.clearStuff();
\r
239 $("#plugin-scheduler-empty").hide();
\r
240 $("#plugin-scheduler").show();
\r
241 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);
\r
245 on_lease_filter_added: function(filter) {
\r
246 console.log("Filter on Leases added !");
\r
249 // ... be sure to list all events here
\r
251 /* RECORD HANDLERS */
\r
252 on_all_new_record: function(record) {
\r
253 //alert('on_all_new_record');
\r
256 debug: function(logTxt) {
\r
257 if (typeof window.console != 'undefined') {
\r
258 console.debug(logTxt);
\r
262 /* INTERNAL FUNCTIONS */
\r
263 _initScheduler: function() {
\r
264 if (_resourcesDone && _leasesDone) {
\r
265 SchedulerDataViewData = SchedulerData;
\r
266 /* GUI setup and event binding */
\r
272 _initUI: function() {
\r
274 if (schedulerDebug) console.time("_initUI");
\r
275 //init DatePicker Start
\r
276 $("#DateToRes").datepicker({
\r
277 dateFormat: "yy-mm-dd",
\r
280 }).change(function() {
\r
281 //Scheduler2.loadWithDate();
\r
282 SchedulerDateSelected = $("#DateToRes").datepicker("getDate");
\r
283 if (SchedulerDateSelected != null && SchedulerDateSelected != '') {
\r
284 for (var i = 0; i < SchedulerData.length; i++) {
\r
285 SchedulerData[i].leases = schedulerGetLeases(60 / schedulerSlotsPerHour, SchedulerData[i].granularity);
\r
287 scheduler2Instance._FixLeases();
\r
288 $('#tblSlider').slider('value', 0);
\r
289 var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();
\r
290 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);
\r
292 console.log(SchedulerDateSelected);
\r
293 console.log(SchedulerDateSelected.getTime()/1000);
\r
294 var tomorrow = new Date(SchedulerDateSelected);
\r
295 tomorrow.setDate(SchedulerDateSelected.getDate()+1);
\r
296 console.log(tomorrow);
\r
297 console.log(tomorrow.getTime()/1000);
\r
299 // Remove previous date interval
\r
300 manifold.raise_event(scheduler2Instance.options.query_lease_uuid, FILTER_REMOVED, ['start_time', '>']);
\r
301 manifold.raise_event(scheduler2Instance.options.query_lease_uuid, FILTER_REMOVED, ['start_time', '<']);
\r
303 // Add new date interval
\r
304 manifold.raise_event(scheduler2Instance.options.query_lease_uuid, FILTER_ADDED, ['start_time', '>', SchedulerDateSelected.getTime()/1000]);
\r
305 manifold.raise_event(scheduler2Instance.options.query_lease_uuid, FILTER_ADDED, ['start_time', '<', tomorrow.getTime()/1000]);
\r
307 alert("Please select a date, so the scheduler can reserve leases.");
\r
309 }).datepicker('setDate', SchedulerDateSelected);
\r
310 /*.click(function () {
\r
311 $("#ui-datepicker-div").css("z-index", 5);
\r
313 //End init DatePicker
\r
320 $('#tblSlider').slider({
\r
322 max: SchedulerTotalCells - SchedulerTotalVisibleCells,
\r
324 slide: function(event, ui) {
\r
325 //$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);
\r
326 //console.log(ui.value);
\r
327 var angScope = angular.element(document.getElementById('SchedulerCtrl')).scope();
\r
328 if (_schedulerCurrentCellPosition > ui.value) {
\r
329 angScope.moveBackSlot(ui.value, ui.value + SchedulerTotalVisibleCells);
\r
330 } else if (_schedulerCurrentCellPosition < ui.value) {
\r
331 angScope.moveFrontSlot(ui.value, ui.value + SchedulerTotalVisibleCells);
\r
333 _schedulerCurrentCellPosition = ui.value;
\r
339 //btn Submit leases
\r
340 $('#btnSchedulerSubmit').click(function () {
\r
341 var leasesForCommit = new Array();
\r
342 var newLeaseStarted = false;
\r
343 var tmpDateTime = SchedulerDateSelected;
\r
344 for (var i = 0; i < SchedulerData.length; i++)
\r
346 var tpmR = SchedulerData[i];
\r
347 for (var j = 0; j < tpmR.leases.length; j++) {
\r
348 var tpmL = tpmR.leases[j];
\r
349 if (newLeaseStarted == false && tpmL.status == 'selected') {
\r
350 //get date of the slot
\r
351 tmpDateTime = schedulerGetDateTimeFromSlotId(tpmL.id, tmpDateTime);
\r
352 var unixStartTime = tmpDateTime.getTime() / 1000;
\r
354 leasesForCommit.push({
\r
356 granularity: tpmR.granularity,
\r
359 start_time: unixStartTime,
\r
363 newLeaseStarted = true;
\r
364 } else if (newLeaseStarted == true && tpmL.status != 'selected') {
\r
365 //get date of the slot
\r
366 tmpDateTime = schedulerGetDateTimeFromSlotId(tpmL.id, tmpDateTime);
\r
367 var unixEndTime = tmpDateTime.getTime() / 1000;
\r
369 var tmpCL = leasesForCommit[leasesForCommit.length - 1];
\r
370 tmpCL.end_time = unixEndTime;
\r
371 tmpCL.duration = schedulerFindDuration(tmpCL.start_time, tmpCL.end_time, tmpCL.granularity);
\r
372 newLeaseStarted = false;
\r
377 for (var i = 0; i < leasesForCommit.length; i++) {
\r
378 //manifold.raise_event(scheduler.options.query_lease_uuid, SET_ADD, leasesForCommit[i]);
\r
384 //End btn Submit leases
\r
387 $("#plugin-scheduler-loader").hide();
\r
388 $("#plugin-scheduler").show();
\r
389 //fixOddEvenClasses();
\r
390 //$("#" + schedulerTblId + " td:not([class])").addClass("free");
\r
391 if (schedulerDebug) console.timeEnd("_initUI");
\r
394 _FixLeases : function () {
\r
395 for (var i = 0; i < tmpSchedulerLeases.length; i++) {
\r
396 var tmpLea = tmpSchedulerLeases[i];
\r
397 if ((schedulerCompareOnDay(tmpLea.start_time, SchedulerDateSelected) == 0) ||
\r
398 (tmpLea.start_time <= SchedulerDateSelected && SchedulerDateSelected <= tmpLea.end_time) ||
\r
399 (schedulerCompareOnDay(tmpLea.end_time, SchedulerDateSelected) == 0)) {
\r
400 var tmpRes = schedulerFindResourceById(SchedulerData, tmpLea.resource);
\r
401 if (tmpRes != null) {
\r
402 //Replace Lease with current lease from the manifold
\r
403 var orgLease = tmpRes.leases[tmpLea.id];
\r
404 tmpLea['groupid'] = orgLease.groupid;
\r
405 tmpLea['groupIndex'] = orgLease.groupIndex;
\r
406 if (orgLease.groupIndex != 0) {
\r
407 if (!window.console) {
\r
408 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
411 tmpRes.leases[tmpLea.id] = tmpLea;
\r
412 this._ExtractLeaseSlots(tmpRes, tmpRes.leases[tmpLea.id]);
\r
418 _ExtractLeaseSlots: function (tmpRes, lease) {
\r
419 var tmpStartDate = lease.start_time;
\r
420 var tmpEndDate = lease.end_time;
\r
421 var startLoop; var toLoop;
\r
422 if (schedulerCompareOnDay(lease.start_time,lease.end_time) == 0) {
\r
424 startLoop = lease.id;
\r
425 toLoop = lease.end_id;
\r
426 } else if (lease.start_time < SchedulerDateSelected && SchedulerDateSelected < lease.end_time) {
\r
427 //one hole day (more than 3days)
\r
429 toLoop = tmpRes.leases.length;
\r
430 } else if (schedulerCompareOnDay(lease.start_time, SchedulerDateSelected) == 0) {
\r
431 //the same day and extends
\r
432 startLoop = lease.id;
\r
433 toLoop = tmpRes.leases.length;
\r
434 } else if (schedulerCompareOnDay(lease.end_time, SchedulerDateSelected) == 0) {
\r
435 //extends to the last say
\r
437 toLoop = lease.end_id;
\r
439 //var minutGran = tmpRes.granularity * 60;
\r
440 for (var li = lease.id; li < toLoop; li++) {
\r
441 tmpRes.leases[li].status = 'reserved';
\r
445 //tmpRes.leases[tmpLea.id
\r
448 _FixTable: function () {
\r
450 SchedulerTotalCells = SchedulerSlots.length;
\r
451 $('#' + schedulerTblId + ' thead tr th:eq(0)').css("width", schedulerTblFirstColWidth); //.css("display", "block");
\r
452 //this get width might need fix depending on the template
\r
453 var tblwidth = $('#scheduler-tab').parent().outerWidth();
\r
454 SchedulerTotalVisibleCells = parseInt((tblwidth - schedulerTblFirstColWidth) / colWidth);
\r
456 //if (SchedulerData.length == 0) {
\r
457 // //puth some test data
\r
458 // SchedulerData.push({ name: 'xyz+aaa', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'xyz+aaa', type: 'node' });
\r
459 // SchedulerData.push({ name: 'xyz+bbb', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'xyz+bbb', type: 'node' });
\r
460 // SchedulerData.push({ name: 'xyz+ccc', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'xyz+ccc', type: 'node' });
\r
461 // SchedulerData.push({ name: 'nitos1', leases: schedulerGetLeases(60 / schedulerSlotsPerHour), urn: 'nitos1', type: 'node' });
\r
463 var tmpScope = angular.element(document.getElementById('SchedulerCtrl')).scope();
\r
464 tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length);
\r
468 _SetFiletredResources : function (filters) {
\r
469 if (filters.length > 0) {
\r
470 SchedulerDataViewData = new Array();
\r
471 var tmpAddIt = true;
\r
472 for (var i = 0; i < SchedulerData.length; i++) {
\r
474 for (var f = 0; f < filters.length; f++) {
\r
475 tmpAddIt = this._FilterResource(SchedulerData[i], filters[f]);
\r
476 if (tmpAddIt == false) break loopfilters;
\r
479 SchedulerDataViewData.push(SchedulerData[i]);
\r
483 SchedulerDataViewData = SchedulerData;
\r
487 _FilterResource: function (resource, filter) {
\r
488 var key = filter[0];
\r
489 var op = filter[1];
\r
490 var value = filter[2];
\r
491 var colValue = resource.org_resource[key];
\r
493 if (schedulerDebug && colValue == 'omf') colValue = 'nitos';
\r
495 if (op == '=' || op == '==') {
\r
496 if (colValue != value || colValue == null || colValue == "" || colValue == "n/a")
\r
498 } else if (op == 'included') {
\r
499 $.each(value, function (i, x) {
\r
500 if (x == colValue) {
\r
507 } else if (op == '!=') {
\r
508 if (colValue == value || colValue == null || colValue == "" || colValue == "n/a")
\r
515 _SetPeriodInPage: function (start, end) {
\r
519 //Sched2 = new Scheduler2();
\r
521 /* Plugin registration */
\r
522 $.plugin('Scheduler2', scheduler2);
\r
524 // TODO Here use cases for instanciating plugins in different ways like in the pastie.
\r