61d77489769742c32b6b261f1ee32e274724ceb7
[controller.git] / opendaylight / web / flows / src / main / resources / js / page.js
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 //PAGE flows
10 one.f = {};
11
12 // specify dashlets and layouts
13 one.f.dashlet = {
14   flows : {
15     id : 'flows',
16     name : 'Flow Entries'
17   },
18   nodes : {
19     id : 'nodes',
20     name : 'Nodes'
21   },
22   detail : {
23     id : 'detail',
24     name : 'Flow Detail'
25   }
26 };
27
28 one.f.menu = {
29   left : {
30     top : [
31       one.f.dashlet.flows
32       ],
33     bottom : [
34       one.f.dashlet.nodes
35       ]
36   },
37   right : {
38     top : [],
39     bottom : [
40       one.f.dashlet.detail
41       ]
42   }
43 };
44
45 one.f.address = {
46   root : "/controller/web/flows",
47   flows : {
48     main : "/main",
49     flows : "/node-flows",
50     nodes : "/node-ports",
51     flow : "/flow",
52     modifyFlow : "/modifyFlow",
53     deleteFlows:"/flow/deleteFlows"
54   }
55 }
56
57 /** NODES **/
58 one.f.nodes = {
59   id : {
60     dashlet: {
61       datagrid: "one_f_nodes_id_dashlet_datagrid"
62     }
63   },
64   registry : {},
65   dashlet : function($dashlet) {
66     var $h4 = one.lib.dashlet.header("Nodes");
67     $dashlet.append($h4);
68
69     one.f.nodes.ajax.dashlet(function(data) {
70       var $gridHTML = one.lib.dashlet.datagrid.init(one.f.nodes.id.dashlet.datagrid, {
71         searchable: true,
72           filterable: false,
73           pagination: true,
74           flexibleRowsPerPage: true
75       }, "table-striped table-condensed");
76       $dashlet.append($gridHTML);
77       var dataSource = one.f.nodes.data.nodesDataGrid(data);
78       $("#" + one.f.nodes.id.dashlet.datagrid).datagrid({dataSource: dataSource});
79     });
80   },
81   ajax : {
82     dashlet : function(callback) {
83       $.getJSON(one.f.address.root+one.f.address.flows.flows, function(data) {
84         callback(data);
85       });
86     }
87   },
88   data : {
89     nodesDataGrid: function(data) {
90       var gridData = [];
91       $.each(data, function(nodeName, flow) {
92         var nodeFlowObject = {};
93         nodeFlowObject["nodeName"] = nodeName;
94         nodeFlowObject["flows"] = flow;
95         nodeFlowObject["rowData"] = nodeName + flow + "-foobar";
96         gridData.push(nodeFlowObject);
97       });
98
99       var source = new StaticDataSource({
100         columns: [
101       {
102         property: 'nodeName',
103           label: 'Node',
104           sortable: true
105       },
106           {
107             property: 'flows',
108           label: 'Flows',
109           sortable: true
110           }
111       ],
112           data: gridData,
113           delay: 0
114       });
115       return source;
116     }
117   },
118   body : {
119     dashlet : function(body, callback) {
120       var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed'];
121       var $table = one.lib.dashlet.table.table(attributes);
122
123       var headers = ['Node', 'Flows'];
124       var $thead = one.lib.dashlet.table.header(headers);
125       $table.append($thead);
126
127       var $tbody = one.lib.dashlet.table.body(body);
128       $table.append($tbody);
129
130       return $table;
131     }
132   }
133 }
134
135 /** FLOW DETAIL **/
136 one.f.detail = {
137   id : {},
138   registry : {},
139   dashlet : function($dashlet, details) {
140     var $h4 = one.lib.dashlet.header("Flow Details");
141     $dashlet.append($h4);
142
143     // details
144     if (details == undefined) {
145       var $none = $(document.createElement('div'));
146       $none.addClass('none');
147       var $p = $(document.createElement('p'));
148       $p.text('Please select a flow');
149       $p.addClass('text-center').addClass('text-info');
150
151       $dashlet.append($none)
152         .append($p);
153     }
154   },
155   data : {
156     dashlet : function(data) {
157       var body = [];
158       var tr = {};
159       var entry = [];
160
161       entry.push(data['name']);
162       entry.push(data['node']);
163       entry.push(data['flow']['priority']);
164       entry.push(data['flow']['hardTimeout']);
165       entry.push(data['flow']['idleTimeout']);
166
167       tr.entry = entry;
168       body.push(tr);
169       return body;
170     },
171     description : function(data) {
172       var body = [];
173       var tr = {};
174       var entry = [];
175       entry.push(data['flow']['ingressPort']);
176       entry.push(data['flow']['etherType']);
177       entry.push(data['flow']['vlanId']);
178       entry.push(data['flow']['vlanPriority']);
179       entry.push(data['flow']['srcMac']);
180       entry.push(data['flow']['dstMac']);
181       entry.push(data['flow']['srcIp']);
182       entry.push(data['flow']['dstIp']);
183       entry.push(data['flow']['tosBits']);
184       entry.push(data['flow']['srcPort']);
185       entry.push(data['flow']['dstPort']);
186       entry.push(data['flow']['protocol']);
187       entry.push(data['flow']['cookie']);
188
189       tr.entry = entry;
190       body.push(tr);
191       return body;
192     },
193     actions : function(data) {
194       var body = [];
195       var tr = {};
196       var entry = [];
197       var actions = '';
198
199       $(data['flow']['actions']).each(function(index, value) {
200         var locEqualTo = value.indexOf("=");
201         if ( locEqualTo == -1 ) {
202           actions += value + ', ';
203         } else {
204           var action = value.substr(0,locEqualTo);
205           if( action == "OUTPUT") {
206             var portIds = value.substr(locEqualTo+1).split(",");
207             actions += action + "=";
208             var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.selectedNode]['ports'];
209             for(var i =0; i < portIds.length ; i++) {
210               var portName = allPorts[portIds[i]];
211               actions += portName + ", ";
212             }
213           } else {
214             actions += value + ', ';
215           }
216         }
217       });
218       actions = actions.slice(0,-2);
219       entry.push(actions);
220
221       tr.entry = entry;
222       body.push(tr);
223       return body;
224     }
225   },
226   body : {
227     dashlet : function(body) {
228       // create table
229       var header = ['Flow Name', 'Node', 'Priority', 'Hard Timeout', 'Idle Timeout'];
230       var $thead = one.lib.dashlet.table.header(header);
231       var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
232       var $table = one.lib.dashlet.table.table(attributes);
233       $table.append($thead);
234
235       var $tbody = one.lib.dashlet.table.body(body);
236       $table.append($tbody);
237
238       return $table;
239     },
240     description : function(body) {
241       var header = ['Input Port', 'Ethernet Type', 'VLAN ID', 'VLAN Priority', 'Source MAC', 'Dest MAC', 'Source IP', 'Dest IP', 'ToS', 'Source Port', 'Dest Port', 'Protocol', 'Cookie'];
242       var $thead = one.lib.dashlet.table.header(header);
243       var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
244       var $table = one.lib.dashlet.table.table(attributes);
245       $table.append($thead);
246
247       var $tbody = one.lib.dashlet.table.body(body);
248       $table.append($tbody);
249
250       return $table;
251     },
252     actions : function(body) {
253       var header = ['Actions'];
254       var $thead = one.lib.dashlet.table.header(header);
255       var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
256       var $table = one.lib.dashlet.table.table(attributes);
257       $table.append($thead);
258
259       var $tbody = one.lib.dashlet.table.body(body);
260       $table.append($tbody);
261
262       return $table;
263     }
264   }
265 }
266
267 /** FLOW ENTRIES **/
268 one.f.flows = {
269   id : {
270     dashlet : {
271       add : "one_f_flows_id_dashlet_add",
272       removeMultiple : "one_f_flows_id_dashlet_removeMultiple",
273       remove : "one_f_flows_id_dashlet_remove",
274       toggle : "one_f_flows_id_dashlet_toggle",
275       edit : "one_f_flows_id_dashlet_edit",
276       datagrid : "one_f_flows_id_dashlet_datagrid",
277       selectAllFlows : "one_f_flows_id_dashlet_selectAllFlows"
278     },
279     modal : {
280       install : "one_f_flows_id_modal_install",
281       edit : "one_f_flows_id_modal_edit",
282       add : "one_f_flows_id_modal_add",
283       close : "one_f_flows_id_modal_close",
284       modal : "one_f_flows_id_modal_modal",
285       dialog : {
286         modal : "one_f_flows_id_modal_dialog_modal",
287         remove : "one_f_flows_id_modal_dialog_remove",
288         close : "one_f_flows_id_modal_dialog_close"
289       },
290       action : {
291         button : "one_f_flows_id_modal_action_button",
292         modal : "one_f_flows_id_modal_action_modal",
293         add : "one_f_flows_id_modal_action_add",
294         close : "one_f_flows_id_modal_action_close",
295         table : "one_f_flows_id_modal_action_table",
296         addOutputPorts : "one_f_flows_id_modal_action_addOutputPorts",
297         setVlanId : "one_f_flows_id_modal_action_setVlanId",
298         setVlanPriority : "one_f_flows_id_modal_action_setVlanPriority",
299         modifyDatalayerSourceAddress : "one_f_flows_id_modal_action_modifyDatalayerSourceAddress",
300         modifyDatalayerDestinationAddress : "one_f_flows_id_modal_action_modifyDatalayerDestinationAddress",
301         modifyNetworkSourceAddress : "one_f_flows_modal_action_modifyNetworkSourceAddress",
302         modifyNetworkDestinationAddress : "one_f_flows_modal_action_modifyNetworkDestinationAddress",
303         modifyTosBits : "one_f_flows_modal_action_modifyTosBits",
304         modifyTransportSourcePort : "one_f_flows_modal_action_modifyTransportSourcePort",
305         modifyTransportDestinationPort : "one_f_flows_modal_action_modifyTransportDestinationPort",
306         modal : {
307           modal : "one_f_flows_modal_action_modal_modal",
308           remove : "one_f_flows_modal_action_modal_remove",
309           cancel : "one_f_flows_modal_action_modal_cancel"
310         }
311       },
312       form : {
313         name : "one_f_flows_id_modal_form_name",
314         nodes : "one_f_flows_id_modal_form_nodes",
315         port : "one_f_flows_id_modal_form_port",
316         priority : "one_f_flows_id_modal_form_priority",
317         hardTimeout : "one_f_flows_id_modal_form_hardTimeout",
318         idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
319         cookie : "one_f_flows_id_modal_form_cookie",
320         etherType : "one_f_flows_id_modal_form_etherType",
321         vlanId : "one_f_flows_id_modal_form_vlanId",
322         vlanPriority : "one_f_flows_id_modal_form_vlanPriority",
323         srcMac : "one_f_flows_id_modal_form_srcMac",
324         dstMac : "one_f_flows_id_modal_form_dstMac",
325         srcIp : "one_f_flows_id_modal_form_srcIp",
326         dstIp : "one_f_flows_id_modal_form_dstIp",
327         tosBits : "one_f_flows_id_modal_form_tosBits",
328         srcPort : "one_f_flows_id_modal_form_srcPort",
329         dstPort : "one_f_flows_id_modal_form_dstPort",
330         protocol : "one_f_flows_id_modal_form_protocol",
331         action : 'one-f-flows-id-modal-form-action'
332       }
333     }
334   },
335   registry : {},
336   dashlet : function($dashlet, callback) {
337     // load body
338     one.f.flows.ajax.dashlet(function(data) {
339       var $h4 = one.lib.dashlet.header("Flow Entries");
340       $dashlet.append($h4);
341       if (one.f.flows.registry.privilege === 'WRITE') {
342         var button = one.lib.dashlet.button.single("Add Flow Entry", one.f.flows.id.dashlet.add, "btn-primary", "btn-mini");
343         var $button = one.lib.dashlet.button.button(button);
344
345         $button.click(function() {
346           var $modal = one.f.flows.modal.initialize();
347           $modal.modal();
348         });
349         $dashlet.append($button);
350         var button = one.lib.dashlet.button.single("Remove Flow Entry", one.f.flows.id.dashlet.removeMultiple, "btn-danger", "btn-mini");
351         var $button = one.lib.dashlet.button.button(button);
352
353         $button.click(function() {
354           var checkedCheckBoxes = $('.flowEntry[type=checkbox]:checked');
355           if (checkedCheckBoxes.size() === 0) {
356             return false;
357           }
358
359           var requestData = [];
360
361           checkedCheckBoxes.each(function(index, value) {
362             var flowEntry = {};
363             flowEntry['name'] = checkedCheckBoxes[index].name;
364             flowEntry['node'] = checkedCheckBoxes[index].getAttribute("node");
365             requestData.push(flowEntry);  
366           });
367           one.f.flows.modal.removeMultiple.dialog(requestData);
368         });
369         $dashlet.append($button);
370
371       }
372       var $gridHTML = one.lib.dashlet.datagrid.init(one.f.flows.id.dashlet.datagrid, {
373         searchable: true,
374           filterable: false,
375           pagination: true,
376           flexibleRowsPerPage: true
377       }, "table-striped table-condensed");
378       $dashlet.append($gridHTML);
379       var dataSource = one.f.flows.data.flowsDataGrid(data);
380       $("#" + one.f.flows.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
381         $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).click(function() {
382           $("#" + one.f.flows.id.dashlet.datagrid).find(':checkbox').prop('checked',
383             $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).is(':checked'));
384         });
385
386         $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
387           $tr = $(tr);
388           $span = $("td span", $tr);
389           var flowstatus = $span.data("flowstatus");
390           if($span.data("installinhw") != null) {
391             var installInHw = $span.data("installinhw").toString();
392             if(installInHw == "true" && flowstatus == "Success") {
393               $tr.addClass("success");
394             } else {
395               $tr.addClass("warning");
396             }
397           }
398           // attach mouseover to show pointer cursor
399           $tr.mouseover(function() {
400             $(this).css("cursor", "pointer");
401           });
402           // attach click event
403           $tr.click(function() {
404             var $td = $($(this).find("td")[1]);
405             var id = $td.text();
406             var node = $td.find("span").data("nodeid");
407             one.f.flows.detail(id, node);
408           });
409           $(".flowEntry").click(function(e){
410             if (!$('.flowEntry[type=checkbox]:not(:checked)').length) {
411               $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
412             .prop("checked",
413               true);
414             } else {
415               $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
416             .prop("checked",
417               false);
418             }
419             e.stopPropagation();
420           });
421         });
422       });
423
424       // details callback
425       if(callback != undefined) callback();
426     });
427   },
428   detail : function(id, node) {
429     // clear flow details
430     var $detailDashlet = one.main.dashlet.right.bottom;
431     $detailDashlet.empty();
432     var $h4 = one.lib.dashlet.header("Flow Overview");
433     $detailDashlet.append($h4);
434
435     // details
436     var flows = one.f.flows.registry.flows;
437     one.f.flows.registry['selectedId'] = id;
438     one.f.flows.registry['selectedNode'] = node;
439     var flow;
440     $(flows).each(function(index, value) {
441       if (value.name == id && value.nodeId == node) {
442         flow = value;
443       }
444     });
445     if (one.f.flows.registry.privilege === 'WRITE') {
446       // remove button
447       var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
448       var $button = one.lib.dashlet.button.button(button);
449       $button.click(function() {
450         var $modal = one.f.flows.modal.dialog.initialize(id, node);
451         $modal.modal();
452       });
453       // edit button
454       var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
455       var $editButton = one.lib.dashlet.button.button(editButton);
456       $editButton.click(function() {
457         var install = flow['flow']['installInHw'];
458         var $modal = one.f.flows.modal.initialize(true,install);
459         $modal.modal().on('shown',function(){
460           var $port = $('#'+one.f.flows.id.modal.form.port);
461           $('#'+one.f.flows.id.modal.form.nodes).trigger("change");
462         });
463       });
464       // toggle button
465       var toggle;
466       if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
467         toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
468       } else {
469         toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
470       }
471       var $toggle = one.lib.dashlet.button.button(toggle);
472       $toggle.click(function() {
473         one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
474           if(data == "Success") {
475             one.main.dashlet.right.bottom.empty();
476             one.f.detail.dashlet(one.main.dashlet.right.bottom);
477             one.main.dashlet.left.top.empty();
478             one.f.flows.dashlet(one.main.dashlet.left.top, function() {
479               // checks are backwards due to stale registry
480               if(flow['flow']['installInHw'] == 'true') {
481                 one.lib.alert('Uninstalled Flow');
482               } else {
483                 one.lib.alert('Installed Flow');
484               }
485               one.f.flows.detail(id, node)
486             });
487           } else {
488             one.lib.alert('Cannot toggle flow: '+data);
489           }
490         });
491       });
492
493       $detailDashlet.append($button).append($editButton).append($toggle);
494     }
495     // append details
496     var body = one.f.detail.data.dashlet(flow);
497     var $body = one.f.detail.body.dashlet(body);
498     $detailDashlet.append($body);
499     var body = one.f.detail.data.description(flow);
500     var $body = one.f.detail.body.description(body);
501     $detailDashlet.append($body);
502     var body = one.f.detail.data.actions(flow);
503     var $body = one.f.detail.body.actions(body);
504     $detailDashlet.append($body);
505   },
506   modal : {
507     dialog : {
508       initialize : function(id, node) {
509         var h3 = "Remove Flow";
510         var $p = one.f.flows.modal.dialog.body(id);
511         var footer = one.f.flows.modal.dialog.footer();
512         var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $p, footer);
513         $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
514           $modal.modal('hide');
515         });
516         $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(function() {
517           one.f.flows.modal.ajax.removeflow(id, node, function(data) {
518             if (data == "Success") {
519               $modal.modal('hide');
520               one.main.dashlet.right.bottom.empty();
521               one.f.detail.dashlet(one.main.dashlet.right.bottom);
522               one.main.dashlet.left.top.empty();
523               one.f.flows.dashlet(one.main.dashlet.left.top);
524               one.lib.alert('Flow removed');
525             } else {
526               one.lib.alert('Cannot remove flow: '+data);
527             }
528           });
529         });
530         return $modal;
531       },
532       footer : function() {
533         var footer = [];
534
535         var removeButton = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.modal.dialog.remove, "btn-danger", "");
536         var $removeButton = one.lib.dashlet.button.button(removeButton);
537         footer.push($removeButton);
538
539         var closeButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.dialog.close, "", "");
540         var $closeButton = one.lib.dashlet.button.button(closeButton);
541         footer.push($closeButton);
542
543         return footer;
544       },
545       body : function(id) {
546         var $p = $(document.createElement('p'));
547         $p.append('Remove flow '+id+'?');
548         return $p;
549       }
550     },
551     initialize : function(edit,install) {
552       var h3;
553       if(edit) {
554         h3 = "Edit Flow Entry";
555         var footer = one.f.flows.modal.footerEdit();
556
557       } else {
558         h3 = "Add Flow Entry";
559         var footer = one.f.flows.modal.footer();
560       }
561
562       var $modal = one.lib.modal.spawn(one.f.flows.id.modal.modal, h3, "", footer);
563
564       // bind close button
565       $('#'+one.f.flows.id.modal.close, $modal).click(function() {
566         $modal.modal('hide');
567       });
568
569       if (edit) {
570         // bind edit flow button
571         $('#'+one.f.flows.id.modal.edit, $modal).click(function() {
572           one.f.flows.modal.save($modal, install, true);
573         });
574       } else {
575         // bind add flow button
576         $('#'+one.f.flows.id.modal.add, $modal).click(function() {
577           one.f.flows.modal.save($modal, 'false');
578         });
579
580         // bind install flow button
581         $('#'+one.f.flows.id.modal.install, $modal).click(function() {
582           one.f.flows.modal.save($modal, 'true');
583         });
584       }
585
586       var nodes = one.f.flows.registry.nodes;
587       var nodeports = one.f.flows.registry.nodeports;
588       var $body = one.f.flows.modal.body(nodes, nodeports, edit);
589       one.lib.modal.inject.body($modal, $body,edit);
590
591       return $modal;
592     },
593     save : function($modal, install, edit) {
594       var result = {};
595
596       result['name'] = $('#'+one.f.flows.id.modal.form.name, $modal).val();
597       result['ingressPort'] = $('#'+one.f.flows.id.modal.form.port, $modal).val();
598       result['priority'] = $('#'+one.f.flows.id.modal.form.priority, $modal).val();
599       result['hardTimeout'] = $('#'+one.f.flows.id.modal.form.hardTimeout, $modal).val();
600       result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
601       result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
602       result['etherType'] = $('#'+one.f.flows.id.modal.form.etherType, $modal).val();
603       result['vlanId'] = $('#'+one.f.flows.id.modal.form.vlanId, $modal).val();
604       result['vlanPriority'] = $('#'+one.f.flows.id.modal.form.vlanPriority, $modal).val();
605       result['dlSrc'] = $('#'+one.f.flows.id.modal.form.srcMac, $modal).val();
606       result['dlDst'] = $('#'+one.f.flows.id.modal.form.dstMac, $modal).val();
607       result['nwSrc'] = $('#'+one.f.flows.id.modal.form.srcIp, $modal).val();
608       result['nwDst'] = $('#'+one.f.flows.id.modal.form.dstIp, $modal).val();
609       result['tosBits'] = $('#'+one.f.flows.id.modal.form.tosBits, $modal).val();
610       result['tpSrc'] = $('#'+one.f.flows.id.modal.form.srcPort, $modal).val();
611       result['tpDst'] = $('#'+one.f.flows.id.modal.form.dstPort, $modal).val();
612       result['protocol'] = $('#'+one.f.flows.id.modal.form.protocol, $modal).val();
613       result['installInHw'] = install;
614
615       var nodeId = $('#'+one.f.flows.id.modal.form.nodes, $modal).val();
616
617       $.each(result, function(key, value) {
618         if (value == "") delete result[key];
619       });
620
621       var action = [];
622       var $table = $('#'+one.f.flows.id.modal.action.table, $modal);
623       $($table.find('tbody').find('tr')).each(function(index, value) {
624         if (!$(this).find('td').hasClass('empty')) {
625           action.push($(value).data('action'));
626         }
627       });
628       result['actions'] = action;
629
630       // frontend validation
631       if (result['name'] == undefined) {
632         alert('Need flow name');
633         return;
634       }
635       if (nodeId == '') {
636         alert('Select node');
637         return;
638       }
639       if (action.length == 0) {
640         alert('Please specify an action');
641         return;
642       }
643
644       // package for ajax call
645       var resource = {};
646       resource['body'] = JSON.stringify(result);
647       if(edit){
648         resource['action'] = 'edit';
649       } else {
650         resource['action'] = 'add';
651       }
652
653       resource['nodeId'] = nodeId;
654
655       if (edit) {
656         one.f.flows.modal.ajax.saveflow(resource, function(data) {
657           if (data == "Success") {
658             $modal.modal('hide').on('hidden', function () {
659               one.f.flows.detail(result['name'], nodeId);
660             });
661             one.lib.alert('Flow Entry edited');
662             one.main.dashlet.left.top.empty();
663             one.f.flows.dashlet(one.main.dashlet.left.top);
664           } else {
665             alert('Could not edit flow: '+data);
666           }
667         });
668       } else {
669         one.f.flows.modal.ajax.saveflow(resource, function(data) {
670           if (data == "Success") {
671             $modal.modal('hide');
672             one.lib.alert('Flow Entry added');
673             one.main.dashlet.left.top.empty();
674             one.f.flows.dashlet(one.main.dashlet.left.top);
675           } else {
676             alert('Could not add flow: '+data);
677           }
678         });
679       }
680     },
681     ajax : {
682       nodes : function(successCallback) {
683         $.getJSON(one.f.address.root+one.f.address.flows.nodes, function(data) {
684           var nodes = one.f.flows.modal.data.nodes(data);
685           var nodeports = data;
686           one.f.flows.registry['nodes'] = nodes;
687           one.f.flows.registry['nodeports'] = nodeports;
688
689           successCallback(nodes, nodeports);
690         });
691       },
692       saveflow : function(resource, callback) {
693         $.post(one.f.address.root+one.f.address.flows.flow, resource, function(data) {
694           callback(data);
695         });
696       },
697       removeflow : function(id, node, callback) {
698         resource = {};
699         resource['action'] = 'remove';
700         $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
701           callback(data);
702         });
703       },
704       toggleflow : function(id, node, callback) {
705         resource = {};
706         resource['action'] = 'toggle';
707         $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
708           callback(data);
709         });
710       }
711     },
712     data : {
713       nodes : function(data) {
714         result = {};
715         $.each(data, function(key, value) {
716           result[key] = value['name'];
717         });
718         return result;
719       }
720     },
721     body : function(nodes, nodeports, edit) {
722       var $form = $(document.createElement('form'));
723       var $fieldset = $(document.createElement('fieldset'));
724       var existingFlow;
725       // flow description
726       var $legend = one.lib.form.legend("");
727       $legend.css('visibility', 'hidden');
728       $fieldset.append($legend);
729       // name
730       var $label = one.lib.form.label("Name");
731       var $input = one.lib.form.input("Flow Name");
732       $input.attr('id', one.f.flows.id.modal.form.name);
733       if(edit) {
734         $input.attr('disabled', 'disabled');
735         var flows = one.f.flows.registry.flows;
736         $(flows).each(function(index, value) {
737           if (value.name == one.f.flows.registry.selectedId && value.nodeId == one.f.flows.registry.selectedNode) {
738             existingFlow = value.flow;
739           }
740         });
741         $input.val(existingFlow.name);
742       }
743
744       $fieldset.append($label).append($input);
745       // node
746       var $label = one.lib.form.label("Node");
747       var $select = one.lib.form.select.create(nodes);
748       one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
749       $select.val($select.find("option:first").val());
750       $select.attr('id', one.f.flows.id.modal.form.nodes);
751       if(edit) {
752         $select.attr('disabled', 'disabled');
753         $select.val(existingFlow.node.type + "|"+ existingFlow.node.nodeIDString);
754       }
755
756       // bind onchange
757       $select.change(function() {
758         // retrieve port value
759         var node = $(this).find('option:selected').attr('value');
760         var $ports = $('#'+one.f.flows.id.modal.form.port);
761         if (node == '') {
762           one.lib.form.select.inject($ports, {});
763           return;
764         }
765         one.f.flows.registry['currentNode'] = node;
766         var ports = nodeports[node]['ports'];
767         one.lib.form.select.inject($ports, ports);
768         one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
769         $ports.val($ports.find("option:first").val());
770         if(edit) {
771           $ports.val( existingFlow.ingressPort );
772         }
773         $.getJSON(one.f.address.root+'/valid-flows/'+node, function(response) {
774           var $select = $('#'+one.f.flows.id.modal.form.action, $fieldset);
775           one.lib.form.select.inject($select, response);
776           one.lib.form.select.prepend($select, {'' : 'Please Select an Action'});
777           // when selecting an action
778           $select.change(function() {
779             var action = $(this).find('option:selected');
780             one.f.flows.modal.action.parse(action.attr('value'));
781             $select[0].selectedIndex = 0;
782           });
783         });
784       });
785
786       $fieldset.append($label).append($select);
787       // input port
788       var $label = one.lib.form.label("Input Port");
789       var $select = one.lib.form.select.create();
790
791       $select.attr('id', one.f.flows.id.modal.form.port);
792       $fieldset.append($label).append($select);
793       // priority
794       var $label = one.lib.form.label("Priority");
795       var $input = one.lib.form.input("Priority");
796       $input.attr('id', one.f.flows.id.modal.form.priority);
797       $input.val('500');
798       $fieldset.append($label).append($input);
799       if(edit) {
800         $input.val(existingFlow.priority);
801       }
802       // hardTimeout
803       var $label = one.lib.form.label("Hard Timeout");
804       var $input = one.lib.form.input("Hard Timeout");
805       $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
806       if(edit) {
807         $input.val(existingFlow.hardTimeout);
808       }
809       $fieldset.append($label).append($input);
810
811       // idleTimeout
812       var $label = one.lib.form.label("Idle Timeout");
813       var $input = one.lib.form.input("Idle Timeout");
814       $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
815       $fieldset.append($label).append($input);
816       if(edit) {
817         $input.val(existingFlow.idleTimeout);
818       }
819       // cookie
820       var $label = one.lib.form.label("Cookie");
821       var $input = one.lib.form.input("Cookie");
822       $input.attr('id', one.f.flows.id.modal.form.cookie);
823       $fieldset.append($label).append($input);
824       if(edit) {
825         $input.val(existingFlow.cookie);
826       }
827
828       // layer 2
829       var $legend = one.lib.form.legend("Layer 2");
830       $fieldset.append($legend);
831       // etherType
832       var $label = one.lib.form.label("Ethernet Type");
833       var $input = one.lib.form.input("Ethernet Type");
834       $input.attr('id', one.f.flows.id.modal.form.etherType);
835       $input.val('0x800');
836       $fieldset.append($label).append($input);
837       if(edit) {
838         $input.val(existingFlow.etherType);
839       }
840       // vlanId
841       var $label = one.lib.form.label("VLAN Identification Number");
842       var $input = one.lib.form.input("VLAN Identification Number");
843       $input.attr('id', one.f.flows.id.modal.form.vlanId);
844       var $help = one.lib.form.help("Range: 0 - 4095");
845       $fieldset.append($label).append($input).append($help);
846       if(edit) {
847         $input.val(existingFlow.vlanId);
848       }
849
850       // vlanPriority
851       var $label = one.lib.form.label("VLAN Priority");
852       var $input = one.lib.form.input("VLAN Priority");
853       $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
854       var $help = one.lib.form.help("Range: 0 - 7");
855       $fieldset.append($label).append($input).append($help);
856       if(edit) {
857         $input.val(existingFlow.vlanPriority);
858       }
859
860       // srcMac
861       var $label = one.lib.form.label("Source MAC Address");
862       var $input = one.lib.form.input("3c:97:0e:75:c3:f7");
863       $input.attr('id', one.f.flows.id.modal.form.srcMac);
864       $fieldset.append($label).append($input);
865       if(edit) {
866         $input.val(existingFlow.srcMac);
867       }
868       // dstMac
869       var $label = one.lib.form.label("Destination MAC Address");
870       var $input = one.lib.form.input("7c:d1:c3:e8:e6:99");
871       $input.attr('id', one.f.flows.id.modal.form.dstMac);
872       $fieldset.append($label).append($input);
873       if(edit) {
874         $input.val(existingFlow.dstMac);
875       }
876       // layer 3
877       var $legend = one.lib.form.legend("Layer 3");
878       $fieldset.append($legend);
879
880       // srcIp
881       var $label = one.lib.form.label("Source IP Address");
882       var $input = one.lib.form.input("192.168.3.128");
883       $input.attr('id', one.f.flows.id.modal.form.srcIp);
884       $fieldset.append($label).append($input);
885       if(edit) {
886         $input.val(existingFlow.srcIp);
887       }
888       // dstIp
889       var $label = one.lib.form.label("Destination IP Address");
890       var $input = one.lib.form.input("2001:2334::0/32");
891       $input.attr('id', one.f.flows.id.modal.form.dstIp);
892       $fieldset.append($label).append($input);
893       if(edit) {
894         $input.val(existingFlow.dstIp);
895       }
896       // tosBits
897       var $label = one.lib.form.label("ToS Bits");
898       var $input = one.lib.form.input("ToS Bits");
899       $input.attr('id', one.f.flows.id.modal.form.tosBits);
900       var $help = one.lib.form.help("Range: 0 - 63");
901       $fieldset.append($label).append($input).append($help);
902       if(edit) {
903         $input.val(existingFlow.tosBits);
904       }
905
906       // layer 4
907       var $legend = one.lib.form.legend("Layer 4");
908       $fieldset.append($legend);
909       // srcPort
910       var $label = one.lib.form.label("Source Port");
911       var $input = one.lib.form.input("Source Port");
912       $input.attr('id', one.f.flows.id.modal.form.srcPort);
913       var $help = one.lib.form.help("Range: 0 - 65535");
914       $fieldset.append($label).append($input).append($help);
915       if(edit) {
916         $input.val(existingFlow.srcPort);
917       }
918       // dstPort
919       var $label = one.lib.form.label("Destination Port");
920       var $input = one.lib.form.input("Destination Port");
921       $input.attr('id', one.f.flows.id.modal.form.dstPort);
922       var $help = one.lib.form.help("Range: 0 - 65535");
923       $fieldset.append($label).append($input).append($help);
924       if(edit) {
925         $input.val(existingFlow.dstPort);
926       }
927       // protocol
928       var $label = one.lib.form.label("Protocol");
929       var $input = one.lib.form.input("Protocol");
930       $input.attr('id', one.f.flows.id.modal.form.protocol);
931       $fieldset.append($label).append($input);
932       if(edit) {
933         $input.val(existingFlow.protocol);
934       }
935       // actions
936       var $legend = one.lib.form.label("Actions");
937       $fieldset.append($legend);
938       // actions table
939       var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
940       var $table = one.lib.dashlet.table.table(tableAttributes);
941       $table.attr('id', one.f.flows.id.modal.action.table);
942       var tableHeaders = ["Action", "Data"];
943       var $thead = one.lib.dashlet.table.header(tableHeaders);
944       var $tbody = one.lib.dashlet.table.body("", tableHeaders);
945       $table.append($thead).append($tbody);
946       // actions
947       var actions = {
948         "" : "Please Select an Action",
949         "DROP" : "Drop",
950         "LOOPBACK" : "Loopback",
951         "FLOOD" : "Flood",
952         "FLOOD_ALL" : "Flood All",
953         "CONTROLLER" : "Controller",
954         "SW_PATH" : "Software Path",
955         "HW_PATH" : "Hardware Path",
956         "OUTPUT" : "Add Output Ports",
957         "ENQUEUE" : "Enqueue",
958         "SET_VLAN_ID" : "Set VLAN ID",
959         "SET_VLAN_PCP" : "Set VLAN Priority",
960         "SET_VLAN_CFI" : "Set VLAN CFI",
961         "POP_VLAN" : "Strip VLAN Header",
962         "PUSH_VLAN" : "Push VLAN",
963         "SET_DL_SRC" : "Modify Datalayer Source Address",
964         "SET_DL_DST" : "Modify Datalayer Destination Address",
965         "SET_DL_TYPE" : "Set Ethertype",
966         "SET_NW_SRC" : "Modify Network Source Address",
967         "SET_NW_DST" :"Modify Network Destination Address",
968         "SET_NW_TOS" : "Modify ToS Bits",
969         "SET_TP_SRC" : "Modify Transport Source Port",
970         "SET_TP_DST" : "Modify Transport Destination Port"
971       };
972       var $select = one.lib.form.select.create(actions);
973       $select.attr('id', one.f.flows.id.modal.form.action);
974       // when selecting an action
975       $select.change(function() {
976         var action = $(this).find('option:selected');
977         one.f.flows.modal.action.parse(action.attr('value'));
978         $select[0].selectedIndex = 0;
979       });
980
981       if(edit) {
982         $(existingFlow.actions).each(function(index, value){
983           setTimeout(function(){
984             var locEqualTo = value.indexOf("=");
985             if ( locEqualTo == -1 ) {
986               one.f.flows.modal.action.add.add(actions[value], value);
987             } else {
988               var action = value.substr(0,locEqualTo);
989               if( action == "OUTPUT") {
990                 var portIds = value.substr(locEqualTo+1).split(",");
991                 var ports = [];
992                 var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
993                 for(var i =0; i < portIds.length ; i++) {
994                   var portName = allPorts[portIds[i]];
995                   ports.push(portName);
996                 }
997                 one.f.flows.modal.action.add.addPortsToTable(ports.join(", "), portIds.join(","));
998               } else {
999                 var val = value.substr(locEqualTo+1);
1000                 one.f.flows.modal.action.add.addDataToTable(actions[action], val, action)
1001               }
1002             }
1003           }, 1000)
1004         });
1005       }
1006       $fieldset.append($select).append($table);
1007
1008       // return
1009       $form.append($fieldset);
1010       return $form;
1011     },
1012     action : {
1013       parse : function(option) {
1014         switch (option) {
1015           case "OUTPUT" :
1016             var h3 = "Add Output Port";
1017             var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addOutputPorts, one.f.flows.modal.action.add.addOutputPorts);
1018             $modal.modal();
1019             break;
1020           case "SET_VLAN_ID" :
1021             var h3 = "Set VLAN ID";
1022             var placeholder = "VLAN Identification Number";
1023             var id = one.f.flows.id.modal.action.setVlanId;
1024             var help = "Range: 0 - 4095";
1025             var action = 'SET_VLAN_ID';
1026             var name = "VLAN ID";
1027             var body = function() {
1028               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1029             };
1030             var add = function($modal) {
1031               one.f.flows.modal.action.add.set(name, id, action, $modal);
1032             };
1033             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1034             $modal.modal();
1035             break;
1036           case "SET_VLAN_PCP" :
1037             var h3 = "Set VLAN Priority";
1038             var placeholder = "VLAN Priority";
1039             var id = one.f.flows.id.modal.action.setVlanPriority;
1040             var help = "Range: 0 - 7";
1041             var action = 'SET_VLAN_PCP';
1042             var name = "VLAN Priority";
1043             var body = function() {
1044               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1045             };
1046             var add = function($modal) {
1047               one.f.flows.modal.action.add.set(name, id, action, $modal);
1048             };
1049             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1050             $modal.modal();
1051             break;
1052           case "SET_VLAN_CFI" :
1053             var h3 = "Set VLAN CFI";
1054             var placeholder = "VLAN CFI";
1055             var id = one.f.flows.id.modal.action.setVlanPriority;
1056             var help = "Range: 0 - 1";
1057             var action = 'SET_VLAN_CFI';
1058             var name = "VLAN CFI";
1059             var body = function() {
1060               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1061             };
1062             var add = function($modal) {
1063               one.f.flows.modal.action.add.set(name, id, action, $modal);
1064             };
1065             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1066             $modal.modal();
1067             break;
1068           case "POP_VLAN" :
1069             var name = "Strip VLAN Header";
1070             var action = 'POP_VLAN';
1071             one.f.flows.modal.action.add.add(name, action);
1072             break;
1073           case "PUSH_VLAN" :
1074             var h3 = "Push VLAN";
1075             var placeholder = "VLAN";
1076             var id = one.f.flows.id.modal.action.setVlanPriority;
1077             var help = "Range: 0 - 4095";
1078             var action = 'PUSH_VLAN';
1079             var name = "VLAN";
1080             var body = function() {
1081               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1082             };
1083             var add = function($modal) {
1084               one.f.flows.modal.action.add.set(name, id, action, $modal);
1085             };
1086             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1087             $modal.modal();
1088             break;
1089           case "SET_DL_SRC" :
1090             var h3 = "Set Source MAC Address";
1091             var placeholder = "Source MAC Address";
1092             var id = one.f.flows.id.modal.action.modifyDatalayerSourceAddress;
1093             var help = "Example: 00:11:22:aa:bb:cc";
1094             var action = 'SET_DL_SRC';
1095             var name = "Source MAC";
1096             var body = function() {
1097               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1098             };
1099             var add = function($modal) {
1100               one.f.flows.modal.action.add.set(name, id, action, $modal);
1101             };
1102             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1103             $modal.modal();
1104             break;
1105           case "SET_DL_DST" :
1106             var h3 = "Set Destination MAC Address";
1107             var placeholder = "Destination MAC Address";
1108             var id = one.f.flows.id.modal.action.modifyDatalayerDestinationAddress;
1109             var help = "Example: 00:11:22:aa:bb:cc";
1110             var action = 'SET_DL_DST';
1111             var name = "Destination MAC";
1112             var body = function() {
1113               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1114             };
1115             var add = function($modal) {
1116               one.f.flows.modal.action.add.set(name, id, action, $modal);
1117             };
1118             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1119             $modal.modal();
1120             break;
1121           case "SET_DL_TYPE" :
1122             var h3 = "Set Ethertype";
1123             var placeholder = "Ethertype";
1124             var id = one.f.flows.id.modal.action.setVlanPriority;
1125             var help = "Range: 0 - 65535";
1126             var action = 'SET_DL_TYPE';
1127             var name = "Ethertype";
1128             var body = function() {
1129               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1130             };
1131             var add = function($modal) {
1132               one.f.flows.modal.action.add.set(name, id, action, $modal);
1133             };
1134             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1135             $modal.modal();
1136             break;
1137           case "SET_NW_SRC" :
1138             var h3 = "Set IP Source Address";
1139             var placeholder = "Source IP Address";
1140             var id = one.f.flows.id.modal.action.modifyNetworkSourceAddress;
1141             var help = "Example: 127.0.0.1";
1142             var action = 'SET_NW_SRC';
1143             var name = "Source IP";
1144             var body = function() {
1145               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1146             };
1147             var add = function($modal) {
1148               one.f.flows.modal.action.add.set(name, id, action, $modal);
1149             };
1150             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1151             $modal.modal();
1152             break;
1153           case "SET_NW_DST" :
1154             var h3 = "Set IP Destination Address";
1155             var placeholder = "Destination IP Address";
1156             var id = one.f.flows.id.modal.action.modifyNetworkDestinationAddress;
1157             var help = "Example: 127.0.0.1";
1158             var action = 'SET_NW_DST';
1159             var name = "Destination IP";
1160             var body = function() {
1161               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1162             };
1163             var add = function($modal) {
1164               one.f.flows.modal.action.add.set(name, id, action, $modal);
1165             };
1166             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1167             $modal.modal();
1168             break;
1169           case "SET_NW_TOS" :
1170             var h3 = "Set IPv4 ToS";
1171             var placeholder = "IPv4 ToS";
1172             var id = one.f.flows.id.modal.action.modifyTosBits;
1173             var help = "Range: 0 - 63";
1174             var action = 'SET_NW_TOS';
1175             var name = "ToS Bits";
1176             var body = function() {
1177               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1178             };
1179             var add = function($modal) {
1180               one.f.flows.modal.action.add.set(name, id, action, $modal);
1181             };
1182             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1183             $modal.modal();
1184             break;
1185           case "SET_TP_SRC" :
1186             var h3 = "Set Transport Source Port";
1187             var placeholder = "Transport Source Port";
1188             var id = one.f.flows.id.modal.action.modifyTransportSourcePort;
1189             var help = "Range: 1 - 65535";
1190             var action = 'SET_TP_SRC';
1191             var name = "Source Port";
1192             var body = function() {
1193               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1194             };
1195             var add = function($modal) {
1196               one.f.flows.modal.action.add.set(name, id, action, $modal);
1197             };
1198             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1199             $modal.modal();
1200             break;
1201           case "SET_TP_DST" :
1202             var h3 = "Set Transport Destination Port";
1203             var placeholder = "Transport Destination Port";
1204             var id = one.f.flows.id.modal.action.modifyTransportDestinationPort;
1205             var help = "Range: 1 - 65535";
1206             var action = 'SET_TP_DST';
1207             var name = "Destination Port";
1208             var body = function() {
1209               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1210             };
1211             var add = function($modal) {
1212               one.f.flows.modal.action.add.set(name, id, action, $modal);
1213             };
1214             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1215             $modal.modal();
1216             break;
1217           case "DROP" :
1218             var name = "Drop";
1219             var action = 'DROP';
1220             one.f.flows.modal.action.add.add(name, action);
1221             break;
1222           case "LOOPBACK" :
1223             var name = "Loopback";
1224             var action = 'LOOPBACK';
1225             one.f.flows.modal.action.add.add(name, action);
1226             break;
1227           case "FLOOD" :
1228             var name = "Flood";
1229             var action = 'FLOOD';
1230             one.f.flows.modal.action.add.add(name, action);
1231             break;
1232           case "FLOOD_ALL" :
1233             var name = "Flood All";
1234             var action = 'FLOOD_ALL';
1235             one.f.flows.modal.action.add.add(name, action);
1236             break;
1237           case "SW_PATH" :
1238             var name = "Software Path";
1239             var action = 'SW_PATH';
1240             one.f.flows.modal.action.add.add(name, action);
1241             break;
1242           case "HW_PATH" :
1243             var name = "Hardware Path";
1244             var action = 'HW_PATH';
1245             one.f.flows.modal.action.add.add(name, action);
1246             break;
1247           case "CONTROLLER" :
1248             var name = "Controller";
1249             var action = 'CONTROLLER';
1250             one.f.flows.modal.action.add.add(name, action);
1251             break;
1252           case "ENQUEUE" :
1253             var name = "Enqueue";
1254             var action = 'ENQUEUE';
1255             one.f.flows.modal.action.add.add(name, action);
1256             break;
1257         }
1258       },
1259       initialize : function(h3, bodyCallback, addCallback) {
1260         var footer = one.f.flows.modal.action.footer();
1261         var $body = bodyCallback();
1262         var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal, h3, $body, footer);
1263         // bind close button
1264         $('#'+one.f.flows.id.modal.action.close, $modal).click(function() {
1265           $modal.modal('hide');
1266         });
1267         // bind add flow button
1268         $('#'+one.f.flows.id.modal.action.add, $modal).click(function() {
1269           addCallback($modal);
1270         });
1271         return $modal;
1272       },
1273       add : {
1274         addOutputPorts : function($modal) {
1275           var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
1276           var ports = '';
1277           var pid = '';
1278           $options.each(function(index, value) {
1279             ports = ports+$(value).text()+", ";
1280             pid = pid+$(value).attr('value')+",";
1281           });
1282           ports = ports.slice(0,-2);
1283           pid = pid.slice(0,-1);
1284           one.f.flows.modal.action.add.addPortsToTable(ports, pid);
1285           $modal.modal('hide');
1286         },
1287         addPortsToTable : function(ports, pid){
1288           var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
1289           $tr.attr('id', 'OUTPUT');
1290           $tr.data('action', 'OUTPUT='+pid);
1291           $tr.click(function() {
1292             one.f.flows.modal.action.add.modal.initialize(this);
1293           });
1294           one.f.flows.modal.action.table.append($tr);
1295         },
1296         add : function(name, action) {
1297           var $tr = one.f.flows.modal.action.table.add(name);
1298           $tr.attr('id', action);
1299           $tr.data('action', action);
1300           $tr.click(function() {
1301             one.f.flows.modal.action.add.modal.initialize(this);
1302           });
1303           one.f.flows.modal.action.table.append($tr);
1304         },
1305         set : function(name, id, action, $modal) {
1306           var $input = $('#'+id);
1307           var value = $input.val();
1308           one.f.flows.modal.action.add.addDataToTable(name,value,action)
1309             $modal.modal('hide');
1310         },
1311         addDataToTable : function(name,value,action) {
1312           var $tr = one.f.flows.modal.action.table.add(name, value);
1313           $tr.attr('id', action);
1314           $tr.data('action', action+'='+value);
1315           $tr.click(function() {
1316             one.f.flows.modal.action.add.modal.initialize(this);
1317           });
1318           one.f.flows.modal.action.table.append($tr);
1319         },
1320         remove : function(that) {
1321           $(that).remove();
1322           var $table = $('#'+one.f.flows.id.modal.action.table);
1323           if ($table.find('tbody').find('tr').size() == 0) {
1324             var $tr = $(document.createElement('tr'));
1325             var $td = $(document.createElement('td'));
1326             $td.attr('colspan', '3');
1327             $tr.addClass('empty');
1328             $td.text('No data available');
1329             $tr.append($td);
1330             $table.find('tbody').append($tr);
1331           }
1332         },
1333         modal : {
1334           initialize : function(that) {
1335             var h3 = "Remove Action";
1336             var footer = one.f.flows.modal.action.add.modal.footer();
1337             var $body = one.f.flows.modal.action.add.modal.body();
1338             var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
1339
1340             // bind cancel button
1341             $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
1342               $modal.modal('hide');
1343             });
1344
1345             // bind remove button
1346             $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
1347               one.f.flows.modal.action.add.remove(that);
1348               $modal.modal('hide');
1349             });
1350
1351             $modal.modal();
1352           },
1353           body : function() {
1354             var $p = $(document.createElement('p'));
1355             $p.append("Remove this action?");
1356             return $p;
1357           },
1358           footer : function() {
1359             var footer = [];
1360
1361             var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
1362             var $removeButton = one.lib.dashlet.button.button(removeButton);
1363             footer.push($removeButton);
1364
1365             var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
1366             var $cancelButton = one.lib.dashlet.button.button(cancelButton);
1367             footer.push($cancelButton);
1368
1369             return footer;
1370           }
1371         }
1372       },
1373       table : {
1374         add : function(action, data) {
1375           var $tr = $(document.createElement('tr'));
1376           var $td = $(document.createElement('td'));
1377           $td.append(action);
1378           $tr.append($td);
1379           var $td = $(document.createElement('td'));
1380           if (data != undefined) $td.append(data);
1381           $tr.append($td);
1382           return $tr;
1383         },
1384         append : function($tr) {
1385           var $table = $('#'+one.f.flows.id.modal.action.table);
1386           var $empty = $table.find('.empty').parent();
1387           if ($empty.size() > 0) $empty.remove();
1388           $table.append($tr);
1389         }
1390       },
1391       body : {
1392         common : function() {
1393           var $form = $(document.createElement('form'));
1394           var $fieldset = $(document.createElement('fieldset'));
1395           return [$form, $fieldset];
1396         },
1397         addOutputPorts : function() {
1398           var common = one.f.flows.modal.action.body.common();
1399           var $form = common[0];
1400           var $fieldset = common[1];
1401           // output port
1402           $label = one.lib.form.label("Select Output Ports");
1403           if (one.f.flows.registry.currentNode == undefined){
1404             return; //Selecting Output ports without selecting node throws an exception
1405           }
1406           var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
1407           $select = one.lib.form.select.create(ports, true);
1408           $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
1409           $fieldset.append($label).append($select);
1410           $form.append($fieldset);
1411           return $form;
1412         },
1413         set : function(label, placeholder, id, help) {
1414           var common = one.f.flows.modal.action.body.common();
1415           var $form = common[0];
1416           var $fieldset = common[1];
1417           // input
1418           $label = one.lib.form.label(label);
1419           $input = one.lib.form.input(placeholder);
1420           $input.attr('id', id);
1421           $help = one.lib.form.help(help);
1422           // append
1423           $fieldset.append($label).append($input).append($help);
1424           $form.append($fieldset);
1425           return $form;
1426         }
1427       },
1428       footer : function() {
1429         var footer = [];
1430         var addButton = one.lib.dashlet.button.single("Add Action", one.f.flows.id.modal.action.add, "btn-primary", "");
1431         var $addButton = one.lib.dashlet.button.button(addButton);
1432         footer.push($addButton);
1433
1434         var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.action.close, "", "");
1435         var $closeButton = one.lib.dashlet.button.button(closeButton);
1436         footer.push($closeButton);
1437
1438         return footer;
1439       }
1440     },
1441     footer : function() {
1442       var footer = [];
1443
1444       var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
1445       var $installButton = one.lib.dashlet.button.button(installButton);
1446       footer.push($installButton);
1447
1448       var addButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.add, "btn-primary", "");
1449       var $addButton = one.lib.dashlet.button.button(addButton);
1450       footer.push($addButton);
1451
1452       var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
1453       var $closeButton = one.lib.dashlet.button.button(closeButton);
1454       footer.push($closeButton);
1455
1456       return footer;
1457     },
1458     footerEdit : function() {
1459       var footer = [];
1460
1461       var editButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.edit, "btn-success", "");
1462       var $editButton = one.lib.dashlet.button.button(editButton);
1463       footer.push($editButton);
1464
1465       var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
1466       var $closeButton = one.lib.dashlet.button.button(closeButton);
1467       footer.push($closeButton);
1468
1469       return footer;
1470     },
1471     removeMultiple: {
1472       dialog: function(flows) {
1473         var h3 = 'Remove Flow Entry';
1474         var flowList = [];
1475         for (var i = 0; i < flows.length; i++) {
1476           flowList.push(flows[i]["name"]);
1477         }
1478         var footer = one.f.flows.modal.removeMultiple.footer();
1479         var $body = one.f.flows.modal.removeMultiple.body(flowList);
1480         var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $body, footer);
1481
1482         // bind close button
1483         $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
1484           $modal.modal('hide');
1485         });
1486
1487         // bind remove rule button
1488         $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(this, function(e) {
1489           var resource = {};
1490           resource['body'] = JSON.stringify(flows);
1491
1492           $.post(one.f.address.root+one.f.address.flows.deleteFlows, resource, function(response) {
1493             $modal.modal('hide');
1494             if(response == "Success") {
1495               one.lib.alert("Flow Entry(s) successfully removed");
1496             } else {
1497               one.lib.alert(response);
1498             }
1499             one.main.dashlet.right.bottom.empty();
1500             one.f.detail.dashlet(one.main.dashlet.right.bottom);
1501             one.main.dashlet.left.top.empty();
1502             one.f.flows.dashlet(one.main.dashlet.left.top);
1503           });
1504         });
1505         $modal.modal();
1506       },
1507       footer : function() {
1508         var footer = [];
1509         var remove = one.lib.dashlet.button.single('Remove Flow Entry',one.f.flows.id.modal.dialog.remove, 'btn-danger', '');
1510         var $remove = one.lib.dashlet.button.button(remove);
1511         footer.push($remove);
1512
1513         var cancel = one.lib.dashlet.button.single('Cancel', one.f.flows.id.modal.dialog.close, '', '');
1514         var $cancel = one.lib.dashlet.button.button(cancel);
1515         footer.push($cancel);
1516
1517         return footer;
1518       },
1519       body : function (flows) {
1520         var $p = $(document.createElement('p'));
1521         var p = 'Remove the following Flow Entry(s)?';
1522         //creata a BS label for each rule and append to list
1523         $(flows).each(function(){
1524           var $span = $(document.createElement('span'));
1525           $span.append(this);
1526           p += '<br/>' + $span[0].outerHTML;
1527         });
1528         $p.append(p);
1529         return $p;
1530       }
1531     }
1532   },
1533   ajax : {
1534     dashlet : function(callback) {
1535       $.getJSON(one.f.address.root+one.f.address.flows.main, function(data) {
1536         one.f.flows.registry['flows'] = data.flows;
1537         one.f.flows.registry['privilege'] = data.privilege;
1538         one.f.flows.modal.ajax.nodes(function(){/*Empty function. Do nothing. */})
1539
1540         callback(data);
1541       });
1542     }
1543   },
1544   data : {
1545     flowsDataGrid: function(data) {
1546       var source = new StaticDataSource({
1547         columns: [
1548       {
1549         property: 'selector',
1550       label: "<input type='checkbox' id='"+one.f.flows.id.dashlet.datagrid.selectAllFlows+"'/>",
1551       sortable: false
1552       },
1553       {
1554         property: 'name',
1555       label: 'Flow Name',
1556       sortable: true
1557       },
1558       {
1559         property: 'node',
1560       label: 'Node',
1561       sortable: true
1562       }
1563       ],
1564       data: data.flows,
1565       formatter: function(items) {
1566         $.each(items, function(index, item) {
1567           var $checkbox = document.createElement("input");
1568           $checkbox.setAttribute("type", "checkbox");
1569           $checkbox.setAttribute("name", item.name);
1570           $checkbox.setAttribute("node", item.nodeId);
1571           $checkbox.setAttribute('class','flowEntry')
1572           item.selector = $checkbox.outerHTML;
1573         item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
1574           ' data-flowstatus=' + item["flow"]["status"] + 
1575           ' data-nodeId=' + item["nodeId"] + '>' + item["name"] + '</span>';
1576         });
1577
1578       },
1579       delay: 0
1580       });
1581       return source;
1582     },
1583     dashlet : function(data) {
1584       var body = [];
1585       $(data).each(function(index, value) {
1586         var tr = {};
1587         var entry = [];
1588
1589
1590         entry.push(value['name']);
1591         entry.push(value['node']);
1592         if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
1593         tr['type'] = ['success'];
1594         else if (value['flow']['installInHw'] == 'false' && value['flow']['status'] == 'Success')
1595         tr['type'] = ['warning'];
1596         else 
1597         tr['type'] = ['warning'];
1598       tr['entry'] = entry;
1599       tr['id'] = value['nodeId'];
1600
1601       body.push(tr);
1602       });
1603       return body;
1604     }
1605   },
1606   body : {
1607     dashlet : function(body, callback) {
1608       var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed', 'table-cursor'];
1609       var $table = one.lib.dashlet.table.table(attributes);
1610
1611       var headers = ['Flow Name', 'Node'];
1612
1613       var $thead = one.lib.dashlet.table.header(headers);
1614       $table.append($thead);
1615
1616       var $tbody = one.lib.dashlet.table.body(body);
1617       $table.append($tbody);
1618       return $table;
1619     }
1620   }
1621 }
1622
1623 /** INIT **/
1624 // populate nav tabs
1625 $(one.f.menu.left.top).each(function(index, value) {
1626   var $nav = $(".nav", "#left-top");
1627   one.main.page.dashlet($nav, value);
1628 });
1629
1630 $(one.f.menu.left.bottom).each(function(index, value) {
1631   var $nav = $(".nav", "#left-bottom");
1632   one.main.page.dashlet($nav, value);
1633 });
1634
1635 $(one.f.menu.right.bottom).each(function(index, value) {
1636   var $nav = $(".nav", "#right-bottom");
1637   one.main.page.dashlet($nav, value);
1638 });
1639
1640 one.f.populate = function($dashlet, header) {
1641   var $h4 = one.lib.dashlet.header(header);
1642   $dashlet.append($h4);
1643 };
1644
1645 // bind dashlet nav
1646 $('.dash .nav a', '#main').click(function() {
1647   // de/activation
1648   var $li = $(this).parent();
1649   var $ul = $li.parent();
1650   one.lib.nav.unfocus($ul);
1651   $li.addClass('active');
1652   // clear respective dashlet
1653   var $dashlet = $ul.parent().find('.dashlet');
1654   one.lib.dashlet.empty($dashlet);
1655   // callback based on menu
1656   var id = $(this).attr('id');
1657   var menu = one.f.dashlet;
1658   switch (id) {
1659     case menu.flows.id:
1660       one.f.flows.dashlet($dashlet);
1661       break;
1662     case menu.nodes.id:
1663       one.f.nodes.dashlet($dashlet);
1664       break;
1665     case menu.detail.id:
1666       one.f.detail.dashlet($dashlet);
1667       break;
1668   };
1669 });
1670
1671 // activate first tab on each dashlet
1672 $('.dash .nav').each(function(index, value) {
1673   $($(value).find('li')[0]).find('a').click();
1674 });