7cefef605373ff65803341824f3ad07f408e8a3a
[myslice.git] / plugins / univbrisfv / static / js / univbrisfv.js
1 /**
2  * Description: display a query result in a datatables-powered <table>
3  * Copyright (c) 2012-2013 UPMC Sorbonne Universite - INRIA
4  * License: GPLv3
5  */ 
6
7 (function($){
8
9     var debug=false;
10     debug=true
11
12     pk_flowspace_index=0;
13     opt_flowspace_index=0;
14     pk_mode=0;
15     fvf_add=1;
16     fvf_nrow=0;
17     
18
19     var UnivbrisFv = Plugin.extend({
20
21         
22         init: function(options, element) {
23             //alert("foam init called");
24             this.classname="univbrisfv";
25             this._super(options, element);
26                 
27             //alert(this.options.hidden_columns);
28             /* Member variables */
29             // in general we expect 2 queries here
30             // query_uuid refers to a single object (typically a slice)
31             // query_all_uuid refers to a list (typically resources or users)
32             // these can return in any order so we keep track of which has been received yet
33             //this.received_all_query = false;
34             //this.received_query = false;
35
36             // We need to remember the active filter for datatables filtering
37             this.filters = Array(); 
38
39             // an internal buffer for records that are 'in' and thus need to be checked 
40             this.buffered_records_to_check = [];
41             // an internal buffer for keeping lines and display them in one call to fnAddData
42             this.buffered_lines = [];
43
44             /* Events */
45             // xx somehow non of these triggers at all for now
46             //this.elmt().on('show', this, this.on_show);
47             //this.elmt().on('shown.bs.tab', this, this.on_show);
48             //this.elmt().on('resize', this, this.on_resize);
49
50             //var query = manifold.query_store.find_analyzed_query(this.options.query_uuid);
51             //this.object = query.object;
52
53             //// we need 2 different keys
54             // * canonical_key is the primary key as derived from metadata (typically: urn)
55             //   and is used to communicate about a given record with the other plugins
56             // * init_key is a key that both kinds of records 
57             //   (i.e. records returned by both queries) must have (typically: hrn or hostname)
58             //   in general query_all will return well populated records, but query
59             //   returns records with only the fields displayed on startup
60             var keys = manifold.metadata.get_key(this.object);
61             this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined;
62             // 
63             this.init_key = this.options.init_key;
64             // have init_key default to canonical_key
65             this.init_key = this.init_key || this.canonical_key;
66             // sanity check
67             if ( ! this.init_key ) messages.warning ("UnivbrisFv : cannot find init_key");
68             if ( ! this.canonical_key ) messages.warning ("UnivbrisFv : cannot find canonical_key");
69             if (debug) messages.debug("UnivbrisFv: canonical_key="+this.canonical_key+" init_key="+this.init_key);
70
71             /* Setup query and record handlers */
72             //this.listen_query(options.query_uuid);
73             //this.listen_query(options.query_all_uuid, 'all');
74
75             /* GUI setup and event binding */
76             this.initialize_table();
77             
78         },
79
80         /* PLUGIN EVENTS */
81
82         on_show: function(e) {
83             if (debug) messages.debug("univbrisfv.on_show");
84             var self = e.data;
85             self.table.fnAdjustColumnSizing();
86         },        
87
88         on_resize: function(e) {
89             if (debug) messages.debug("univbrisfv.on_resize");
90             var self = e.data;
91             self.table.fnAdjustColumnSizing();
92         },        
93
94         /* GUI EVENTS */
95
96         /* GUI MANIPULATION */
97
98         initialize_table: function() 
99         {
100
101             
102             /* Transforms the table into DataTable, and keep a pointer to it */
103             var self = this;
104             //alert(self.options);
105             var actual_options = {
106                 // Customize the position of Datatables elements (length,filter,button,...)
107                 // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time
108                 //sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>",
109                 sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>><'buttons'>",
110                 //sDom: "<'row'<'col-xs-9'r>t<'buttons'>",
111                 // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now
112                 // hopefully this would come with dataTables v1.10 ?
113                 // in any case, search for 'sPaginationType' all over the code for more comments
114                 sPaginationType: 'bootstrap',
115                 // Handle the null values & the error : Datatables warning Requested unknown parameter
116                 // http://datatables.net/forums/discussion/5331/datatables-warning-...-requested-unknown-parameter/p2
117                 aoColumnDefs: [{sDefaultContent: '',aTargets: [ '_all' ]}],
118                 // WARNING: this one causes tables in a 'tabs' that are not exposed at the time this is run to show up empty
119                 // sScrollX: '100%',       /* Horizontal scrolling */
120                 bProcessing: true,      /* Loading */
121                 fnDrawCallback: function() { self._querytable_draw_callback.call(self);}
122                 //fnFooterCallback: function() {self._univbrisfv_footer_callback.call(self,nFoot, aData, iStart, iEnd, aiDisplay)};}
123                 // XXX use $.proxy here !
124             };
125             // the intention here is that options.datatables_options as coming from the python object take precedence
126             // xxx DISABLED by jordan: was causing errors in datatables.js
127             // xxx turned back on by Thierry - this is the code that takes python-provided options into account
128             // check your datatables_options tag instead 
129             // however, we have to accumulate in aoColumnDefs from here (above) 
130             // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs)
131             if ( 'aoColumnDefs' in this.options.datatables_options) {
132                 actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']);
133                 delete this.options.datatables_options['aoColumnDefs'];
134             }
135             $.extend(actual_options, this.options.datatables_options );
136
137             
138             this.table = $("#univbris_flowspace_selection__table").dataTable(actual_options);   
139             
140             
141             
142             //alert(this.table.$("name"));
143
144             /* Setup the SelectAll button in the dataTable header */
145             /* xxx not sure this is still working */
146             var oSelectAll = $('#datatableSelectAll-'+ this.options.plugin_uuid);
147             oSelectAll.html("<span class='glyphicon glyphicon-ok' style='float:right;display:inline-block;'></span>Select All");
148             oSelectAll.button();
149             oSelectAll.css('font-size','11px');
150             oSelectAll.css('float','right');
151             oSelectAll.css('margin-right','15px');
152             oSelectAll.css('margin-bottom','5px');
153             oSelectAll.unbind('click');
154             oSelectAll.click(this._selectAll);
155
156             /* Add a filtering function to the current table 
157              * Note: we use closure to get access to the 'options'
158              */
159             $.fn.dataTableExt.afnFiltering.push(function( oSettings, aData, iDataIndex ) { 
160                 /* No filtering if the table does not match */
161                 if (oSettings.nTable.id != self.options.plugin_uuid + '__table')
162                     return true;
163                 return self._querytable_filter.call(self, oSettings, aData, iDataIndex);
164             });
165
166            //alert(this.options.hidden_columns);
167
168             /* Processing hidden_columns */
169             $.each(this.options.hidden_columns, function(i, field) {
170                 //manifold.raise_event(self.options.query_all_uuid, FIELD_REMOVED, field);
171                 //alert (field);
172                 self.hide_column(field);
173                 //self.hide_column(field);
174             });
175
176             //document.getElementById('buttons').text-align='center';
177
178             /**$('<table><tr><td><button id="add_flowspace" type="button" style="height: 25px; width: 400px; text-align: center" onclick="fnAddflowspace()">Define another packet  flowspace</button></td>').appendTo('div.buttons');
179
180             $('<table><tr><td><button id="add_flowspace" type="button" style="height: 25px; width: 400px" onclick="fnAddflowspace()">Define another optical  flowspace</button></td>').appendTo('div.buttons');
181
182             $('<td><button id="submit_flowspace" type="button" style="height: 25px; width: 400px" onclick="fnButsubmit()">Submit flowspaces</button></td></tr></table>').appendTo('div.buttons');
183
184             $('<td><button id="submit_flowspace" type="button" style="height: 25px; width: 400px" onclick="fnButsubmit()">Define controller location</button></td></tr></table>').appendTo('div.buttons');**/
185         
186            
187             //jQuery( "#univbris_flowspace_selection" ).hide();
188
189               //$('<a href="http://localhost:8000/login/" id="next_link">next link</a>').appendTo('div.submit');
190
191                 //this.new_record("t");
192                 //this.new_record("t");
193                 //this.new_record("t");
194                 //this.new_record("t");
195                 //this.new_record("t");
196                 this._querytable_draw_callback();
197                 jQuery("#univbris_flowspace_selection").hide(); 
198                 
199
200         }, // initialize_table
201
202
203         fnButsubmit:function(e){
204                 alert("verifying before submitting");
205
206                 sync_query_uuid=e.data.options.sync_query_uuid;
207                 try{
208
209                          var controller= $('#controller_loc').val();
210
211                          //validating controller field
212                          //alert (controller.length);
213                          if (controller.length>=7){
214                                 //alert(controller.substring(0,4))
215                                 if(controller.substring(0,4)=="tcp:" | controller.substring(0,4)=="ssl:"){
216                                         var controller_ip=controller.substring(4,controller.length);
217                                         //alert(controller_ip)
218                                         var index=controller_ip.indexOf(":")
219                                         if (index!=-1){
220                                                 var controller_ip1=controller_ip.substring(0,index);
221                                                 //alert(controller_ip1);
222                                                 var ip_validator= /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 
223                                                 if (!controller_ip1.match(ip_validator)){
224                                                   throw "Incorrect IP format";
225                                                 }
226                                                 //else{
227                                                 //  throw "incorrect ip";
228                                                 //}
229
230                                                 var controller_port=controller_ip.substring(index+1,controller_ip.length);
231                                                 if(!isNaN(controller_port)){
232                                                         controller_port=parseInt(controller_port,10);
233                                                         if (!((controller_port >0) & (controller_port <65536))){
234                                                         //if(controller_port >0){
235                                                                 throw "Incorrect controller port";
236                                                         }
237                                                         //else{
238                                                         //      throw "correct port";
239                                                         //}
240                                                 }
241                                                 else{
242                                                         throw "Incorrect controller port";
243                                                 }
244                                         }
245                                         else{
246                                                 throw "Incorrect controller specified";
247                                         } 
248                                 }
249                                 else{
250                                         throw "Controller must start with tcp: or ssl:";
251                                 }
252
253                          }
254                          else{
255                             throw "Incorrect controller specified";
256                          }
257                          //end of validation of controller field
258          
259                          var rows = $("#univbris_flowspace_selection__table").dataTable().fnGetNodes();
260                          var cells=[];
261                          
262                          var json_rspec={};
263                          json_rspec["controller"]=controller;
264                          var groups_rspec=[];
265                          var matches_rspec=[];
266
267                          if (rows.length <=0) {
268                                 throw "No Flowspace defined"
269                          }
270
271
272                          var queryStringToJSON = function (url) {
273                 if (url === '') return '';
274                 var pairs = (url || location.search).slice(1).split('&');
275                 var result = {};
276                 for (var idx in pairs) {
277                     if ($.isNumeric(idx)) {
278                             var pair = pairs[idx].split('=');
279                             if (!!pair[0]){
280                                         result[pair[0].toLowerCase()] = decodeURIComponent(pair[1].replace(/\+/g, " ") || '');
281                         }
282                     }
283                 }
284                 return result;
285                         }
286
287                          for(var i=0;i<rows.length;i++){
288                                 var htmlStr=$(rows[i]).find("td:eq(0)").html();
289                                 var parser=new DOMParser();
290                                 var htmlDoc=parser.parseFromString(htmlStr, "text/html");
291                                 var para=htmlDoc.getElementsByTagName('p');
292                                 if(typeof para.item(0).id != 'undefined'){
293                                         cells.push(para.item(0).id);
294                                         var m_form=para.item(0).id.split(",");
295                                         var result=queryStringToJSON("?"+m_form[0]);
296                                         matches_rspec.push(result);
297                                         //console.log(m_form[1]);
298                                         var result2=queryStringToJSON("?"+m_form[1]);
299                                         result2["flowspace_name"]=result["flowspace_name"];
300                                         groups_rspec.push(result2);
301                                 }
302                          }
303
304                         json_rspec["groups"]=groups_rspec;
305                         json_rspec["matches"]=matches_rspec;    
306
307                         //console.log(JSON.stringify(json_rspec));
308
309
310                         //var controller= $('#controller_loc').val();
311
312                         //cells.push("controller="+controller);
313
314                         
315                         
316
317                         //var str="";           
318
319                         //Just for show: built output string 
320                         //for(var i=0;i<cells.length;i++){
321                         //      str+=cells[i]+"\n";
322
323                         //}
324                     //alert(str);
325             data = {
326                 state: STATE_SET,
327                 key  : null,
328                 op   : STATE_SET_ADD,
329                 value: json_rspec 
330             }
331             manifold.raise_event(sync_query_uuid, FIELD_STATE_CHANGED, data);
332
333                     //alert("sending to manifold backend to build rspec");
334
335                 }
336                 catch(err){
337                         alert(err)
338                 }
339                 
340                                 
341         },
342
343
344
345         fnAddflowspace:function(e){
346                 sync_query_uuid=e.data.options.sync_query_uuid;
347                 pk_mode=1;
348                 hideFvfError();
349                 var port_table=$("#univbris_foam_ports_selection__table").dataTable();
350                 var nodes = $('input',port_table.fnGetNodes());
351                 for(var i=0;i<nodes.length;i++){
352                         nodes[i].checked=false;
353                         nodes[i].disabled=false;
354                 }
355
356                 fvf_add=1;
357                 $("#uob_fv_table_form").trigger("reset");
358                 var port_table = $("#univbris_flowspace_selection__table").DataTable();
359                 //alert("table length" + this.table.fnGetNodes().length);       
360                 $("#flowspace_name").val("pk_flowspace_"+ pk_flowspace_index);
361                 //pk_flowspace_index=1+pk_flowspace_index;
362                 $("[id='addflowspaceform']").show();
363                 $("#uob_fv_table_form :input").prop("disabled", false);
364                 $("[name='flowspace_name']").prop("disabled", true);
365                 $("[id='cancel_addflowspaceform']").text('cancel');
366                 $("[id='addflowspaceform']").text('add flowspace');
367                 
368                 try{
369                         manifold.raise_event(e.data.options.sync_query_uuid,CLEAR_FILTERS);
370                         var filter=[];
371                         filter.push("link type");
372                         filter.push("!=");
373                         filter.push("optical");
374                         manifold.raise_event(e.data.options.sync_query_uuid,FILTER_ADDED,filter);
375                 }
376                 catch(err){
377                         alert("raise error:"+err);
378                 }
379
380                 var svg_links = svg.selectAll(".link");
381                 for(var i=0;i<svg_links[0].length;i++){
382                         svg_links[0][i].style.stroke= '#ccc';
383                         svg_links[0][i].style.strokeWidth= '4px';
384                 };
385
386
387                 jQuery("#univbris_flowspace_selection").hide(); 
388                 jQuery("#uob_fv_table_form").show();
389                 jQuery( "#univbris_foam_ports_selection" ).show();
390                 
391                 
392                 topoviewer_state={mode:"edit",link_type:"non-optical"};
393
394                 jQuery('#topo_plugin').show();
395                 
396         },
397
398         fnAddcflowspace:function(e){
399                 pk_mode=0;
400                 sync_query_uuid=e.data.options.sync_query_uuid;
401                 hideFvfError();
402                 var port_table=$("#univbris_foam_ports_selection__table").dataTable();
403                 var nodes = $('input',port_table.fnGetNodes());
404                 for(var i=0;i<nodes.length;i++){
405                         nodes[i].checked=false;
406                         nodes[i].disabled=false;
407                 }
408
409                 $("#uob_ofv_table_form").trigger("reset");
410                 $("#oflowspace_name").val("opt_flowspace_"+ opt_flowspace_index);
411                 fvf_add=1;
412                 $("[id='addflowspaceform']").show();
413                 $("#uob_ofv_table_form :input").prop("disabled", false);
414                 $("[name='oflowspace_name']").prop("disabled", true);
415                 $("[id='cancel_addflowspaceform']").text('cancel');
416                 $("[id='addflowspaceform']").text('add flowspace');
417
418                 try{
419                         manifold.raise_event(e.data.options.sync_query_uuid,CLEAR_FILTERS);
420                         var filter=[];
421                         filter.push("link type");
422                         filter.push("!=");
423                         filter.push("packet");
424                         manifold.raise_event(e.data.options.sync_query_uuid,FILTER_ADDED,filter);
425                         filter=[];
426                         filter.push("link type");
427                         filter.push("!=");
428                         filter.push("compute");
429                         manifold.raise_event(e.data.options.sync_query_uuid,FILTER_ADDED,filter);
430                         filter=[];
431                         filter.push("link type");
432                         filter.push("!=");
433                         filter.push("federation");
434                         manifold.raise_event(e.data.options.sync_query_uuid,FILTER_ADDED,filter);
435                 }
436                 catch(err){
437                         alert("raise error:"+err);
438                 }
439
440                 var svg_links = svg.selectAll(".link");
441                 for(var i=0;i<svg_links[0].length;i++){
442                         svg_links[0][i].style.stroke= '#ccc';
443                         svg_links[0][i].style.strokeWidth= '4px';
444                 };
445
446                 jQuery( "#univbris_flowspace_selection" ).hide();
447                 jQuery("#uob_ofv_table_form").show();
448                 jQuery( "#univbris_foam_ports_selection" ).show();
449
450
451
452                 topoviewer_state={mode:"edit",link_type:"optical"};
453
454                 jQuery("#topo_plugin").show();          
455         },
456
457         
458
459         fnDelete:function(e){
460                         e.preventDefault();
461                         //alert("delwete");
462                         var nRow = $(this).parents('tr')[0];
463                         this.table = $("#univbris_flowspace_selection__table").dataTable();
464                         this.table.fnDeleteRow( nRow );
465         },
466
467         fnEdit:function(e){     
468                         e.preventDefault();
469                         fvf_add=0;
470                         hideFvfError();
471                         
472                         try{
473                                 var nRow = $(this).parents('tr')[0];
474                                 fvf_nrow=nRow;
475                                 var row= $("#univbris_flowspace_selection__table").dataTable().fnGetData(nRow);
476                                 var parser=new DOMParser();
477                                 var htmlDoc=parser.parseFromString(row[0], "text/html");
478                                 //alert("html_doc"+htmlDoc);
479                                 var para=htmlDoc.getElementsByTagName('p');
480                         }
481                         catch(err){
482                                 alert("error:"+err);
483
484                         }
485                         //alert("p id:"+ para.item(0).id);
486                         var m_form=para.item(0).id.split(",");
487                         //console.log(htmlDoc.getElementsByTagName('a'));
488                         $("#uob_fv_table_form").trigger("reset");
489                         $("#uob_fv_table_form :input").prop("disabled", false);
490                         $("[name='flowspace_name']").prop("disabled", false);
491                         $("#uob_fv_table_form").deserialize(m_form[0]);
492
493                         try{
494                                 deserializeDT(m_form[1]);
495                         }
496                         catch (err){
497                                 alert("error:"+err);
498                         }
499
500                          var port_table=$("#univbris_foam_ports_selection__table").dataTable();
501                          var nodes = $('input',port_table.fnGetNodes());
502                          var svg_links = svg.selectAll(".link");
503
504                          for(n=0;n<nodes.length;n++){
505                                 for(var i=0;i<svg_links[0].length;i++){
506                                         if(svg_links[0][i].__data__.value==nodes[n].id){
507                                                 if(nodes[n].checked==true){
508                                                         svg_links[0][i].style.stroke= 'black';
509                                                         svg_links[0][i].style.strokeWidth= '5px';
510                                                 }
511                                                 else{
512                                                         svg_links[0][i].style.stroke= '#ccc';
513                                                         svg_links[0][i].style.strokeWidth= '4px';
514                                                 }
515                                                 break;
516                                         }
517                                 }
518                                 nodes[n].disabled=false;
519                         };
520                         
521                         //alert($("#flowspace_name").val());
522
523                         if  ($("#flowspace_name").val().search("pk")==0){
524                                 topoviewer_state={mode:"edit",link_type:"non-optical"};
525                         }
526                         else{
527                                 topoviewer_state={mode:"edit",link_type:"optical"};
528                         }
529
530                         
531                         
532                         $("[name='flowspace_name']").prop("disabled", true);
533                         $("[id='cancel_addflowspaceform']").prop("disabled", false);
534                         $("[id='addflowspaceform']").prop("disabled", false);
535                         $("[id='addflowspaceform']").text('modify');
536                         $("[id='addflowspaceform']").show();                    
537                         jQuery( "#univbris_foam_ports_selection" ).show();                              
538                         jQuery("#uob_fv_table_form").show();
539                         jQuery("#univbris_flowspace_selection").hide();
540                         jQuery('#topo_plugin').show();
541                         
542         },
543
544
545
546         
547
548         /**
549          * @brief Determine index of key in the table columns 
550          * @param key
551          * @param cols
552          */
553         getColIndex: function(key, cols) {
554             var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; });
555             return (tabIndex.length > 0) ? tabIndex[0] : -1;
556         }, // getColIndex
557
558         // create a checkbox <input> tag
559         // computes 'id' attribute from canonical_key
560         // computes 'init_id' from init_key for initialization phase
561         // no need to used convoluted ids with plugin-uuid or others, since
562         // we search using table.$ which looks only in this table
563         checkbox_html : function (record) {
564             var result="";
565             // Prefix id with plugin_uuid
566             result += "<input";
567             result += " class='univbrisfv-checkbox'";
568          // compute id from canonical_key
569             var id = record[this.canonical_key]
570          // compute init_id form init_key
571             var init_id=record[this.init_key];
572          // set id - for retrieving from an id, or for posting events upon user's clicks
573             result += " id='"+record[this.canonical_key]+"'";
574          // set init_id
575             result += "init_id='" + init_id + "'";
576          // wrap up
577             result += " type='checkbox'";
578             result += " autocomplete='off'";
579             result += "></input>";
580             return result;
581         }, 
582
583          fake_checkbox_html : function (record) {
584             //alert("fake fun called");
585             var result="";
586             // Prefix id with plugin_uuid
587             result += "<input";
588             //result += " class='univbrisfv-checkbox'";
589          // set id - for retrieving from an id, or for posting events upon user's clicks
590             result += " id='"+ record +"'";
591             result += " name='"+ record +"'";
592          // set init_id
593             result += " init_id='" + record + "'";
594          // wrap up
595             result += " type='checkbox'";
596             result += " autocomplete='off'";
597             result += "></input>";
598             ///alert(result);
599             return result;
600         }, 
601
602
603         new_record: function(record)
604         {
605            
606          // this models a line in dataTables, each element in the line describes a cell
607             line = new Array();
608      
609             // go through table headers to get column names we want
610             // in order (we have temporarily hack some adjustments in names)
611             var cols = this.table.fnSettings().aoColumns;
612             var colnames = cols.map(function(x) {return x.sTitle})
613             var nb_col = cols.length;
614             /* if we've requested checkboxes, then forget about the checkbox column for now */
615             if (this.options.checkboxes) nb_col -= 1;
616             
617             //alert(colnames);
618             /*replace production*/
619             /* fill in stuff depending on the column name */
620              var cols = this.table.fnSettings().aoColumns;
621             //alert("col "+cols);
622             var colnames = cols.map(function(x) {return x.sTitle})
623             var nb_col = cols.length;
624                         //alert("nb_col: "+ nb_col);
625             /* if we've requested checkboxes, then forget about the checkbox column for now */
626             if (this.options.checkboxes) nb_col -= 1;
627                         //alert("nb_col: "+ nb_col);
628             //alert(colnames);
629             /*replace production*/
630             /* fill in stuff depending on the column name */
631             for (var j = 0; j < nb_col; j++) {
632                 if (typeof colnames[j] == 'undefined') {
633                     line.push('...');
634                 } else if (colnames[j] == 'Flowspace Selector') {
635                     //alert("added");
636                     line.push("first");
637                 }
638                 
639
640                 /*if (typeof colnames[j] == 'undefined') {
641                     line.push('...');
642                 } else if (colnames[j] == 'hostname') {
643                     if (record['type'] == 'resource,link')
644                         //TODO: we need to add source/destination for links
645                         line.push('');
646                     else
647                         line.push(record['hostname']);
648
649                 } else if (colnames[j] == 'hrn' && typeof(record) != 'undefined') {
650                     line.push('<a href="../resource/'+record['urn']+'"><span class="glyphicon glyphicon-search"></span></a> '+record['hrn']);
651                 } else {
652                     if (record[colnames[j]])
653                         line.push(record[colnames[j]]);
654                     else
655                         line.push('');
656                 }*/
657             }
658     
659             // catch up with the last column if checkboxes were requested 
660             if (this.options.checkboxes) {
661                 // Use a key instead of hostname (hard coded...)
662                 line.push(this.checkbox_html(record));
663                 }
664     
665             // adding an array in one call is *much* more efficient
666                 // this.table.fnAddData(line);
667                 this.buffered_lines.push(line);
668                 this.table.fnAddData(this.buffered_lines);
669                 //this.table.redraw();
670                 //this._querytable_draw_callback();
671         },
672
673         clear_table: function()
674         {
675             this.table.fnClearTable();
676         },
677
678         redraw_table: function()
679         {
680             this.table.fnDraw();
681         },
682
683         show_column: function(field)
684         {
685             var oSettings = this.table.fnSettings();
686             var cols = oSettings.aoColumns;
687             var index = this.getColIndex(field,cols);
688             if (index != -1)
689                 this.table.fnSetColumnVis(index, true);
690         },
691
692         hide_column: function(field)
693         {
694             var oSettings = this.table.fnSettings();
695             var cols = oSettings.aoColumns;
696             var index = this.getColIndex(field,cols);
697             //index=-1;
698             //alert(field + ": index: " + index );
699             if (index != -1)
700                 //alert(field + ": hidden with index: " + index );
701                 this.table.fnSetColumnVis(index, false);
702         },
703
704         // this is used at init-time, at which point only init_key can make sense
705         // (because the argument record, if it comes from query, might not have canonical_key set
706         set_checkbox_from_record: function (record, checked) {
707             if (checked === undefined) checked = true;
708             var init_id = record[this.init_key];
709             if (debug) messages.debug("univbrisfv.set_checkbox_from_record, init_id="+init_id);
710             // using table.$ to search inside elements that are not visible
711             var element = this.table.$('[init_id="'+init_id+'"]');
712             element.attr('checked',checked);
713         },
714
715         // id relates to canonical_key
716         set_checkbox_from_data: function (id, checked) {
717             if (checked === undefined) checked = true;
718             if (debug) messages.debug("univbrisfv.set_checkbox_from_data, id="+id);
719             // using table.$ to search inside elements that are not visible
720             var element = this.table.$("[id='"+id+"']");
721             element.attr('checked',checked);
722         },
723
724         /*************************** QUERY HANDLER ****************************/
725
726         on_filter_added: function(filter)
727         {
728             this.filters.push(filter);
729             this.redraw_table();
730         },
731
732         on_filter_removed: function(filter)
733         {
734             // Remove corresponding filters
735             this.filters = $.grep(this.filters, function(x) {
736                 return x != filter;
737             });
738             this.redraw_table();
739         },
740         
741         on_filter_clear: function()
742         {
743             // XXX
744             this.redraw_table();
745         },
746
747         on_field_added: function(field)
748         {
749             this.show_column(field);
750         },
751
752         on_field_removed: function(field)
753         {
754             this.hide_column(field);
755         },
756
757         on_field_clear: function()
758         {
759             alert('UnivbrisFv::clear_fields() not implemented');
760         },
761
762         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
763         /*************************** ALL QUERY HANDLER ****************************/
764
765         on_all_filter_added: function(filter)
766         {
767             // XXX
768             this.redraw_table();
769         },
770
771         on_all_filter_removed: function(filter)
772         {
773             // XXX
774             this.redraw_table();
775         },
776         
777         on_all_filter_clear: function()
778         {
779             // XXX
780             this.redraw_table();
781         },
782
783         on_all_field_added: function(field)
784         {
785             this.show_column(field);
786         },
787
788         on_all_field_removed: function(field)
789         {
790             this.hide_column(field);
791         },
792
793         on_all_field_clear: function()
794         {
795             alert('UnivbrisFv::clear_fields() not implemented');
796         },
797
798
799         /*************************** RECORD HANDLER ***************************/
800
801         on_new_record: function(record)
802         {
803             if (this.received_all_query) {
804                 // if the 'all' query has been dealt with already we may turn on the checkbox
805                 this.set_checkbox_from_record(record, true);
806             } else {
807                 this.buffered_records_to_check.push(record);
808             }
809         },
810
811         on_clear_records: function()
812         {
813         },
814
815         // Could be the default in parent
816         on_query_in_progress: function()
817         {
818             this.spin();
819         },
820
821         on_query_done: function()
822         {
823             this.received_query = true;
824             // unspin once we have received both
825             if (this.received_all_query && this.received_query) this.unspin();
826         },
827         
828         on_field_state_changed: function(data)
829         {
830             switch(data.request) {
831                 case FIELD_REQUEST_ADD:
832                 case FIELD_REQUEST_ADD_RESET:
833                     this.set_checkbox_from_data(data.value, true);
834                     break;
835                 case FIELD_REQUEST_REMOVE:
836                 case FIELD_REQUEST_REMOVE_RESET:
837                     this.set_checkbox_from_data(data.value, false);
838                     break;
839                 default:
840                     break;
841             }
842         },
843
844         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
845         // all
846         on_all_field_state_changed: function(data)
847         {
848             switch(data.request) {
849                 case FIELD_REQUEST_ADD:
850                 case FIELD_REQUEST_ADD_RESET:
851                     this.set_checkboxfrom_data(data.value, true);
852                     break;
853                 case FIELD_REQUEST_REMOVE:
854                 case FIELD_REQUEST_REMOVE_RESET:
855                     this.set_checkbox_from_data(data.value, false);
856                     break;
857                 default:
858                     break;
859             }
860         },
861
862         on_all_new_record: function(record)
863         {
864             this.new_record(record);
865         },
866
867         on_all_clear_records: function()
868         {
869             this.clear_table();
870
871         },
872
873         on_all_query_in_progress: function()
874         {
875             // XXX parent
876             this.spin();
877         }, // on_all_query_in_progress
878
879         on_all_query_done: function()
880         {
881             if (debug) messages.debug("1-shot initializing dataTables content with " + this.buffered_lines.length + " lines");
882
883
884             this.table.fnAddData (this.buffered_lines);
885             this.buffered_lines=[];
886             
887             var self = this;
888             // if we've already received the slice query, we have not been able to set 
889             // checkboxes on the fly at that time (dom not yet created)
890             $.each(this.buffered_records_to_check, function(i, record) {
891                 if (debug) messages.debug ("querytable delayed turning on checkbox " + i + " record= " + record);
892                 self.set_checkbox_from_record(record, true);
893             });
894             this.buffered_records_to_check = [];
895
896             this.received_all_query = true;
897             // unspin once we have received both
898             if (this.received_all_query && this.received_query) this.unspin();
899
900         }, // on_all_query_done
901
902         /************************** PRIVATE METHODS ***************************/
903
904         /** 
905          * @brief QueryTable filtering function
906          */
907         _querytable_filter: function(oSettings, aData, iDataIndex)
908         {
909             var ret = true;
910             $.each (this.filters, function(index, filter) { 
911                 /* XXX How to manage checkbox ? */
912                 var key = filter[0]; 
913                 var op = filter[1];
914                 var value = filter[2];
915
916                 /* Determine index of key in the table columns */
917                 var col = $.map(oSettings.aoColumns, function(x, i) {if (x.sTitle == key) return i;})[0];
918
919                 /* Unknown key: no filtering */
920                 if (typeof(col) == 'undefined')
921                     return;
922
923                 col_value=unfold.get_value(aData[col]);
924                 /* Test whether current filter is compatible with the column */
925                 if (op == '=' || op == '==') {
926                     if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
927                         ret = false;
928                 }else if (op == '!=') {
929                     if ( col_value == value || col_value==null || col_value=="" || col_value=="n/a")
930                         ret = false;
931                 } else if(op=='<') {
932                     if ( parseFloat(col_value) >= value || col_value==null || col_value=="" || col_value=="n/a")
933                         ret = false;
934                 } else if(op=='>') {
935                     if ( parseFloat(col_value) <= value || col_value==null || col_value=="" || col_value=="n/a")
936                         ret = false;
937                 } else if(op=='<=' || op=='≤') {
938                     if ( parseFloat(col_value) > value || col_value==null || col_value=="" || col_value=="n/a")
939                         ret = false;
940                 } else if(op=='>=' || op=='≥') {
941                     if ( parseFloat(col_value) < value || col_value==null || col_value=="" || col_value=="n/a")
942                         ret = false;
943                 }else{
944                     // How to break out of a loop ?
945                     alert("filter not supported");
946                     return false;
947                 }
948
949             });
950             return ret;
951         },
952
953         _querytable_draw_callback: function()
954         {
955             /* 
956              * Handle clicks on checkboxes: reassociate checkbox click every time
957              * the table is redrawn    
958              */
959             this.elts('querytable-checkbox').unbind('click').click(this, this._check_click);
960             $("#submit_flowspace").unbind('click').click(this, this.fnButsubmit);
961             $("#add_flowspace").unbind('click').click(this, this.fnAddflowspace);
962             $("#add_opt_flowspace").unbind('click').click(this, this.fnAddcflowspace);
963             $('#univbris_flowspace_selection__table .edit').unbind('click').click(this, this.fnEdit);
964             $('#univbris_flowspace_selection__table .delete').unbind('click').click(this, this.fnDelete);
965             /*var edits=this.elts.all.find('.edit');
966             edits.each(function(){
967                 this.unbind('click').click(this,this.fnEdit);
968              }
969             */
970             if (!this.table)
971                 return;
972
973             /* Remove pagination if we show only a few results */
974             var wrapper = this.table; //.parent().parent().parent();
975             var rowsPerPage = this.table.fnSettings()._iDisplayLength;
976             var rowsToShow = this.table.fnSettings().fnRecordsDisplay();
977             var minRowsPerPage = this.table.fnSettings().aLengthMenu[0];
978
979             if ( rowsToShow <= rowsPerPage || rowsPerPage == -1 ) {
980                 $('.querytable_paginate', wrapper).css('visibility', 'hidden');
981             } else {
982                 $('.querytable_paginate', wrapper).css('visibility', 'visible');
983             }
984
985             if ( rowsToShow <= minRowsPerPage ) {
986                 $('.querytable_length', wrapper).css('visibility', 'hidden');
987             } else {
988                 $('.querytable_length', wrapper).css('visibility', 'visible');
989             }
990
991             
992
993
994         },
995
996
997
998         _check_click: function(e) 
999         {
1000             e.stopPropagation();
1001
1002             var self = e.data;
1003             var id=this.id;
1004
1005             // this.id = key of object to be added... what about multiple keys ?
1006             if (debug) messages.debug("querytable._check_click key="+this.canonical_key+"->"+id+" checked="+this.checked);
1007             //manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, id);
1008             //return false; // prevent checkbox to be checked, waiting response from manifold plugin api
1009             
1010         },
1011
1012         _selectAll: function() 
1013         {
1014             // requires jQuery id
1015             var uuid=this.id.split("-");
1016             var oTable=$("#querytable-"+uuid[1]).dataTable();
1017             // Function available in QueryTable 1.9.x
1018             // Filter : displayed data only
1019             var filterData = oTable._('tr', {"filter":"applied"});   
1020             /* TODO: WARNING if too many nodes selected, use filters to reduce nuber of nodes */        
1021             if(filterData.length<=100){
1022                 $.each(filterData, function(index, obj) {
1023                     var last=$(obj).last();
1024                     var key_value=unfold.get_value(last[0]);
1025                     if(typeof($(last[0]).attr('checked'))=="undefined"){
1026                         $.publish('selected', 'add/'+key_value);
1027                     }
1028                 });
1029             }
1030         },
1031
1032     });
1033
1034    
1035
1036     $.plugin('UnivbrisFv', UnivbrisFv);
1037
1038   /* define the 'dom-checkbox' type for sorting in datatables 
1039      http://datatables.net/examples/plug-ins/dom_sort.html
1040      using trial and error I found that the actual column number
1041      was in fact given as a third argument, and not second 
1042      as the various online resources had it - go figure */
1043     $.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, _, iColumn ) {
1044         return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) {
1045             return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0';
1046         } );
1047     }
1048
1049    
1050
1051 })(jQuery);
1052
1053
1054