Merge "Bug 564 - add missing sal-remote dependency."
[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         enqueue : 'one-f-flows-modal-action-enqueue',
307         queue : 'one-f-flows-modal-action-queue',
308         setEthertype : 'one-f-flows-modal-action-setEthertype',
309         pushVlan : 'one-f-flows-modal-action-pushVlan',
310         setVlanCfi : 'one-f-flows-modal-action-setVlanCfi',
311         modal : {
312           modal : "one_f_flows_modal_action_modal_modal",
313           remove : "one_f_flows_modal_action_modal_remove",
314           cancel : "one_f_flows_modal_action_modal_cancel"
315         }
316       },
317       form : {
318         name : "one_f_flows_id_modal_form_name",
319         nodes : "one_f_flows_id_modal_form_nodes",
320         port : "one_f_flows_id_modal_form_port",
321         priority : "one_f_flows_id_modal_form_priority",
322         hardTimeout : "one_f_flows_id_modal_form_hardTimeout",
323         idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
324         cookie : "one_f_flows_id_modal_form_cookie",
325         etherType : "one_f_flows_id_modal_form_etherType",
326         vlanId : "one_f_flows_id_modal_form_vlanId",
327         vlanPriority : "one_f_flows_id_modal_form_vlanPriority",
328         srcMac : "one_f_flows_id_modal_form_srcMac",
329         dstMac : "one_f_flows_id_modal_form_dstMac",
330         srcIp : "one_f_flows_id_modal_form_srcIp",
331         dstIp : "one_f_flows_id_modal_form_dstIp",
332         tosBits : "one_f_flows_id_modal_form_tosBits",
333         srcPort : "one_f_flows_id_modal_form_srcPort",
334         dstPort : "one_f_flows_id_modal_form_dstPort",
335         protocol : "one_f_flows_id_modal_form_protocol",
336         action : 'one-f-flows-id-modal-form-action'
337       }
338     }
339   },
340   registry : {},
341   dashlet : function($dashlet, callback) {
342     // load body
343     one.f.flows.ajax.dashlet(function(data) {
344       var $h4 = one.lib.dashlet.header("Flow Entries");
345       $dashlet.append($h4);
346       if (one.f.flows.registry.privilege === 'WRITE') {
347         var button = one.lib.dashlet.button.single("Add Flow Entry", one.f.flows.id.dashlet.add, "btn-primary", "btn-mini");
348         var $button = one.lib.dashlet.button.button(button);
349
350         $button.click(function() {
351           var $modal = one.f.flows.modal.initialize();
352           $modal.modal();
353         });
354         $dashlet.append($button);
355         var button = one.lib.dashlet.button.single("Remove Flow Entry", one.f.flows.id.dashlet.removeMultiple, "btn-danger", "btn-mini");
356         var $button = one.lib.dashlet.button.button(button);
357
358         $button.click(function() {
359           var checkedCheckBoxes = $('.flowEntry[type=checkbox]:checked');
360           if (checkedCheckBoxes.size() === 0) {
361             return false;
362           }
363
364           var requestData = [];
365
366           checkedCheckBoxes.each(function(index, value) {
367             var flowEntry = {};
368             flowEntry['name'] = checkedCheckBoxes[index].name;
369             flowEntry['node'] = checkedCheckBoxes[index].getAttribute("node");
370             requestData.push(flowEntry);  
371           });
372           one.f.flows.modal.removeMultiple.dialog(requestData);
373         });
374         $dashlet.append($button);
375
376       }
377       var $gridHTML = one.lib.dashlet.datagrid.init(one.f.flows.id.dashlet.datagrid, {
378         searchable: true,
379           filterable: false,
380           pagination: true,
381           flexibleRowsPerPage: true
382       }, "table-striped table-condensed");
383       $dashlet.append($gridHTML);
384       var dataSource = one.f.flows.data.flowsDataGrid(data);
385       $("#" + one.f.flows.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
386         $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).click(function() {
387           $("#" + one.f.flows.id.dashlet.datagrid).find(':checkbox').prop('checked',
388             $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).is(':checked'));
389         });
390
391         $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
392           $tr = $(tr);
393           $span = $("td span", $tr);
394           var flowstatus = $span.data("flowstatus");
395           if($span.data("installinhw") != null) {
396             var installInHw = $span.data("installinhw").toString();
397             if(installInHw == "true" && flowstatus == "Success") {
398               $tr.addClass("success");
399             } else {
400               $tr.addClass("warning");
401             }
402           }
403           // attach mouseover to show pointer cursor
404           $tr.mouseover(function() {
405             $(this).css("cursor", "pointer");
406           });
407           // attach click event
408           $tr.click(function() {
409             var $td = $($(this).find("td")[1]);
410             var id = $td.text();
411             var node = $td.find("span").data("nodeid");
412             one.f.flows.detail(id, node);
413           });
414           $(".flowEntry").click(function(e){
415             if (!$('.flowEntry[type=checkbox]:not(:checked)').length) {
416               $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
417             .prop("checked",
418               true);
419             } else {
420               $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
421             .prop("checked",
422               false);
423             }
424             e.stopPropagation();
425           });
426         });
427       });
428
429       // details callback
430       if(callback != undefined) callback();
431     });
432   },
433   detail : function(id, node) {
434     // clear flow details
435     var $detailDashlet = one.main.dashlet.right.bottom;
436     $detailDashlet.empty();
437     var $h4 = one.lib.dashlet.header("Flow Overview");
438     $detailDashlet.append($h4);
439
440     // details
441     var flows = one.f.flows.registry.flows;
442     one.f.flows.registry['selectedId'] = id;
443     one.f.flows.registry['selectedNode'] = node;
444     var flow;
445     $(flows).each(function(index, value) {
446       if (value.name == id && value.nodeId == node) {
447         flow = value;
448       }
449     });
450     if (one.f.flows.registry.privilege === 'WRITE') {
451       // remove button
452       var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
453       var $button = one.lib.dashlet.button.button(button);
454       $button.click(function() {
455         var $modal = one.f.flows.modal.dialog.initialize(id, node);
456         $modal.modal();
457       });
458       // edit button
459       var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
460       var $editButton = one.lib.dashlet.button.button(editButton);
461       $editButton.click(function() {
462         var install = flow['flow']['installInHw'];
463         var $modal = one.f.flows.modal.initialize(true,install);
464         $modal.modal().on('shown',function(){
465           var $port = $('#'+one.f.flows.id.modal.form.port);
466           $('#'+one.f.flows.id.modal.form.nodes).trigger("change");
467         });
468       });
469       // toggle button
470       var toggle;
471       if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
472         toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
473       } else {
474         toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
475       }
476       var $toggle = one.lib.dashlet.button.button(toggle);
477       $toggle.click(function() {
478         one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
479           if(data == "Success") {
480             one.main.dashlet.right.bottom.empty();
481             one.f.detail.dashlet(one.main.dashlet.right.bottom);
482             one.main.dashlet.left.top.empty();
483             one.f.flows.dashlet(one.main.dashlet.left.top, function() {
484               // checks are backwards due to stale registry
485               if(flow['flow']['installInHw'] == 'true') {
486                 one.lib.alert('Uninstalled Flow');
487               } else {
488                 one.lib.alert('Installed Flow');
489               }
490               one.f.flows.detail(id, node)
491             });
492           } else {
493             one.lib.alert('Cannot toggle flow: '+data);
494           }
495         });
496       });
497
498       $detailDashlet.append($button).append($editButton).append($toggle);
499     }
500     // append details
501     var body = one.f.detail.data.dashlet(flow);
502     var $body = one.f.detail.body.dashlet(body);
503     $detailDashlet.append($body);
504     var body = one.f.detail.data.description(flow);
505     var $body = one.f.detail.body.description(body);
506     $detailDashlet.append($body);
507     var body = one.f.detail.data.actions(flow);
508     var $body = one.f.detail.body.actions(body);
509     $detailDashlet.append($body);
510   },
511   modal : {
512     dialog : {
513       initialize : function(id, node) {
514         var h3 = "Remove Flow";
515         var $p = one.f.flows.modal.dialog.body(id);
516         var footer = one.f.flows.modal.dialog.footer();
517         var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $p, footer);
518         $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
519           $modal.modal('hide');
520         });
521         $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(function() {
522           one.f.flows.modal.ajax.removeflow(id, node, function(data) {
523             if (data == "Success") {
524               $modal.modal('hide');
525               one.main.dashlet.right.bottom.empty();
526               one.f.detail.dashlet(one.main.dashlet.right.bottom);
527               one.main.dashlet.left.top.empty();
528               one.f.flows.dashlet(one.main.dashlet.left.top);
529               one.lib.alert('Flow removed');
530             } else {
531               one.lib.alert('Cannot remove flow: '+data);
532             }
533           });
534         });
535         return $modal;
536       },
537       footer : function() {
538         var footer = [];
539
540         var removeButton = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.modal.dialog.remove, "btn-danger", "");
541         var $removeButton = one.lib.dashlet.button.button(removeButton);
542         footer.push($removeButton);
543
544         var closeButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.dialog.close, "", "");
545         var $closeButton = one.lib.dashlet.button.button(closeButton);
546         footer.push($closeButton);
547
548         return footer;
549       },
550       body : function(id) {
551         var $p = $(document.createElement('p'));
552         $p.append('Remove flow '+id+'?');
553         return $p;
554       }
555     },
556     initialize : function(edit,install) {
557       var h3;
558       if(edit) {
559         h3 = "Edit Flow Entry";
560         var footer = one.f.flows.modal.footerEdit();
561
562       } else {
563         h3 = "Add Flow Entry";
564         var footer = one.f.flows.modal.footer();
565       }
566
567       var $modal = one.lib.modal.spawn(one.f.flows.id.modal.modal, h3, "", footer);
568
569       // bind close button
570       $('#'+one.f.flows.id.modal.close, $modal).click(function() {
571         $modal.modal('hide');
572       });
573
574       if (edit) {
575         // bind edit flow button
576         $('#'+one.f.flows.id.modal.edit, $modal).click(function() {
577           one.f.flows.modal.save($modal, install, true);
578         });
579       } else {
580         // bind add flow button
581         $('#'+one.f.flows.id.modal.add, $modal).click(function() {
582           one.f.flows.modal.save($modal, 'false');
583         });
584
585         // bind install flow button
586         $('#'+one.f.flows.id.modal.install, $modal).click(function() {
587           one.f.flows.modal.save($modal, 'true');
588         });
589       }
590
591       var nodes = one.f.flows.registry.nodes;
592       var nodeports = one.f.flows.registry.nodeports;
593       var $body = one.f.flows.modal.body(nodes, nodeports, edit);
594       one.lib.modal.inject.body($modal, $body,edit);
595
596       return $modal;
597     },
598     save : function($modal, install, edit) {
599       var result = {};
600
601       result['name'] = $('#'+one.f.flows.id.modal.form.name, $modal).val();
602       result['ingressPort'] = $('#'+one.f.flows.id.modal.form.port, $modal).val();
603       result['priority'] = $('#'+one.f.flows.id.modal.form.priority, $modal).val();
604       result['hardTimeout'] = $('#'+one.f.flows.id.modal.form.hardTimeout, $modal).val();
605       result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
606       result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
607       result['etherType'] = $('#'+one.f.flows.id.modal.form.etherType, $modal).val();
608       result['vlanId'] = $('#'+one.f.flows.id.modal.form.vlanId, $modal).val();
609       result['vlanPriority'] = $('#'+one.f.flows.id.modal.form.vlanPriority, $modal).val();
610       result['dlSrc'] = $('#'+one.f.flows.id.modal.form.srcMac, $modal).val();
611       result['dlDst'] = $('#'+one.f.flows.id.modal.form.dstMac, $modal).val();
612       result['nwSrc'] = $('#'+one.f.flows.id.modal.form.srcIp, $modal).val();
613       result['nwDst'] = $('#'+one.f.flows.id.modal.form.dstIp, $modal).val();
614       result['tosBits'] = $('#'+one.f.flows.id.modal.form.tosBits, $modal).val();
615       result['tpSrc'] = $('#'+one.f.flows.id.modal.form.srcPort, $modal).val();
616       result['tpDst'] = $('#'+one.f.flows.id.modal.form.dstPort, $modal).val();
617       result['protocol'] = $('#'+one.f.flows.id.modal.form.protocol, $modal).val();
618       result['installInHw'] = install;
619
620       var nodeId = $('#'+one.f.flows.id.modal.form.nodes, $modal).val();
621
622       $.each(result, function(key, value) {
623         if (value == "") delete result[key];
624       });
625
626       var action = [];
627       var $table = $('#'+one.f.flows.id.modal.action.table, $modal);
628       $($table.find('tbody').find('tr')).each(function(index, value) {
629         if (!$(this).find('td').hasClass('empty')) {
630           action.push($(value).data('action'));
631         }
632       });
633       result['actions'] = action;
634
635       // frontend validation
636       if (result['name'] == undefined) {
637         alert('Need flow name');
638         return;
639       }
640       if (nodeId == '') {
641         alert('Select node');
642         return;
643       }
644       if (action.length == 0) {
645         alert('Please specify an action');
646         return;
647       }
648
649       // package for ajax call
650       var resource = {};
651       resource['body'] = JSON.stringify(result);
652       if(edit){
653         resource['action'] = 'edit';
654       } else {
655         resource['action'] = 'add';
656       }
657
658       resource['nodeId'] = nodeId;
659
660       if (edit) {
661         one.f.flows.modal.ajax.saveflow(resource, function(data) {
662           if (data == "Success") {
663             $modal.modal('hide').on('hidden', function () {
664               one.f.flows.detail(result['name'], nodeId);
665             });
666             one.lib.alert('Flow Entry edited');
667             one.main.dashlet.left.top.empty();
668             one.f.flows.dashlet(one.main.dashlet.left.top);
669           } else {
670             alert('Could not edit flow: '+data);
671           }
672         });
673       } else {
674         one.f.flows.modal.ajax.saveflow(resource, function(data) {
675           if (data == "Success") {
676             $modal.modal('hide');
677             one.lib.alert('Flow Entry added');
678             one.main.dashlet.left.top.empty();
679             one.f.flows.dashlet(one.main.dashlet.left.top);
680           } else {
681             alert('Could not add flow: '+data);
682           }
683         });
684       }
685     },
686     ajax : {
687       nodes : function(successCallback) {
688         $.getJSON(one.f.address.root+one.f.address.flows.nodes, function(data) {
689           var nodes = one.f.flows.modal.data.nodes(data);
690           var nodeports = data;
691           one.f.flows.registry['nodes'] = nodes;
692           one.f.flows.registry['nodeports'] = nodeports;
693
694           successCallback(nodes, nodeports);
695         });
696       },
697       saveflow : function(resource, callback) {
698         $.post(one.f.address.root+one.f.address.flows.flow, resource, function(data) {
699           callback(data);
700         });
701       },
702       removeflow : function(id, node, callback) {
703         resource = {};
704         resource['action'] = 'remove';
705         $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
706           callback(data);
707         });
708       },
709       toggleflow : function(id, node, callback) {
710         resource = {};
711         resource['action'] = 'toggle';
712         $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
713           callback(data);
714         });
715       }
716     },
717     data : {
718       nodes : function(data) {
719         result = {};
720         $.each(data, function(key, value) {
721           result[key] = value['name'];
722         });
723         return result;
724       }
725     },
726     body : function(nodes, nodeports, edit) {
727       var $form = $(document.createElement('form'));
728       var $fieldset = $(document.createElement('fieldset'));
729       var existingFlow;
730       // flow description
731       var $legend = one.lib.form.legend("");
732       $legend.css('visibility', 'hidden');
733       $fieldset.append($legend);
734       // name
735       var $label = one.lib.form.label("Name");
736       var $input = one.lib.form.input("Flow Name");
737       $input.attr('id', one.f.flows.id.modal.form.name);
738       if(edit) {
739         $input.attr('disabled', 'disabled');
740         var flows = one.f.flows.registry.flows;
741         $(flows).each(function(index, value) {
742           if (value.name == one.f.flows.registry.selectedId && value.nodeId == one.f.flows.registry.selectedNode) {
743             existingFlow = value.flow;
744           }
745         });
746         $input.val(existingFlow.name);
747       }
748
749       $fieldset.append($label).append($input);
750       // node
751       var $label = one.lib.form.label("Node");
752       var $select = one.lib.form.select.create(nodes);
753       one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
754       $select.val($select.find("option:first").val());
755       $select.attr('id', one.f.flows.id.modal.form.nodes);
756       if(edit) {
757         $select.attr('disabled', 'disabled');
758         $select.val(existingFlow.node.type + "|"+ existingFlow.node.nodeIDString);
759       }
760
761       // bind onchange
762       $select.change(function() {
763         // retrieve port value
764         var node = $(this).find('option:selected').attr('value');
765         var $ports = $('#'+one.f.flows.id.modal.form.port);
766         if (node == '') {
767           one.lib.form.select.inject($ports, {});
768           return;
769         }
770         one.f.flows.registry['currentNode'] = node;
771         var ports = nodeports[node]['ports'];
772         one.lib.form.select.inject($ports, ports);
773         one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
774         $ports.val($ports.find("option:first").val());
775         if(edit) {
776           $ports.val( existingFlow.ingressPort );
777         }
778         $.getJSON(one.f.address.root+'/valid-flows/'+node, function(response) {
779           var $select = $('#'+one.f.flows.id.modal.form.action, $fieldset);
780           one.lib.form.select.inject($select, response);
781           one.lib.form.select.prepend($select, {'' : 'Please Select an Action'});
782           // when selecting an action
783           $select.change(function() {
784             var action = $(this).find('option:selected');
785             one.f.flows.modal.action.parse(action.attr('value'));
786             $select[0].selectedIndex = 0;
787           });
788         });
789       });
790
791       $fieldset.append($label).append($select);
792       // input port
793       var $label = one.lib.form.label("Input Port");
794       var $select = one.lib.form.select.create();
795
796       $select.attr('id', one.f.flows.id.modal.form.port);
797       $fieldset.append($label).append($select);
798       // priority
799       var $label = one.lib.form.label("Priority");
800       var $input = one.lib.form.input("Priority");
801       $input.attr('id', one.f.flows.id.modal.form.priority);
802       $input.val('500');
803       $fieldset.append($label).append($input);
804       if(edit) {
805         $input.val(existingFlow.priority);
806       }
807       // hardTimeout
808       var $label = one.lib.form.label("Hard Timeout");
809       var $input = one.lib.form.input("Hard Timeout");
810       $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
811       if(edit) {
812         $input.val(existingFlow.hardTimeout);
813       }
814       $fieldset.append($label).append($input);
815
816       // idleTimeout
817       var $label = one.lib.form.label("Idle Timeout");
818       var $input = one.lib.form.input("Idle Timeout");
819       $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
820       $fieldset.append($label).append($input);
821       if(edit) {
822         $input.val(existingFlow.idleTimeout);
823       }
824       // cookie
825       var $label = one.lib.form.label("Cookie");
826       var $input = one.lib.form.input("Cookie");
827       $input.attr('id', one.f.flows.id.modal.form.cookie);
828       $fieldset.append($label).append($input);
829       if(edit) {
830         $input.val(existingFlow.cookie);
831       }
832
833       // layer 2
834       var $legend = one.lib.form.legend("Layer 2");
835       $fieldset.append($legend);
836       // etherType
837       var $label = one.lib.form.label("Ethernet Type");
838       var $input = one.lib.form.input("Ethernet Type");
839       $input.attr('id', one.f.flows.id.modal.form.etherType);
840       $input.val('0x800');
841       $fieldset.append($label).append($input);
842       if(edit) {
843         $input.val(existingFlow.etherType);
844       }
845       // vlanId
846       var $label = one.lib.form.label("VLAN Identification Number");
847       var $input = one.lib.form.input("VLAN Identification Number");
848       $input.attr('id', one.f.flows.id.modal.form.vlanId);
849       var $help = one.lib.form.help("Range: 0 - 4095");
850       $fieldset.append($label).append($input).append($help);
851       if(edit) {
852         $input.val(existingFlow.vlanId);
853       }
854
855       // vlanPriority
856       var $label = one.lib.form.label("VLAN Priority");
857       var $input = one.lib.form.input("VLAN Priority");
858       $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
859       var $help = one.lib.form.help("Range: 0 - 7");
860       $fieldset.append($label).append($input).append($help);
861       if(edit) {
862         $input.val(existingFlow.vlanPriority);
863       }
864
865       // srcMac
866       var $label = one.lib.form.label("Source MAC Address");
867       var $input = one.lib.form.input("3c:97:0e:75:c3:f7");
868       $input.attr('id', one.f.flows.id.modal.form.srcMac);
869       $fieldset.append($label).append($input);
870       if(edit) {
871         $input.val(existingFlow.srcMac);
872       }
873       // dstMac
874       var $label = one.lib.form.label("Destination MAC Address");
875       var $input = one.lib.form.input("7c:d1:c3:e8:e6:99");
876       $input.attr('id', one.f.flows.id.modal.form.dstMac);
877       $fieldset.append($label).append($input);
878       if(edit) {
879         $input.val(existingFlow.dstMac);
880       }
881       // layer 3
882       var $legend = one.lib.form.legend("Layer 3");
883       $fieldset.append($legend);
884
885       // srcIp
886       var $label = one.lib.form.label("Source IP Address");
887       var $input = one.lib.form.input("192.168.3.128");
888       $input.attr('id', one.f.flows.id.modal.form.srcIp);
889       $fieldset.append($label).append($input);
890       if(edit) {
891         $input.val(existingFlow.srcIp);
892       }
893       // dstIp
894       var $label = one.lib.form.label("Destination IP Address");
895       var $input = one.lib.form.input("2001:2334::0/32");
896       $input.attr('id', one.f.flows.id.modal.form.dstIp);
897       $fieldset.append($label).append($input);
898       if(edit) {
899         $input.val(existingFlow.dstIp);
900       }
901       // tosBits
902       var $label = one.lib.form.label("ToS Bits");
903       var $input = one.lib.form.input("ToS Bits");
904       $input.attr('id', one.f.flows.id.modal.form.tosBits);
905       var $help = one.lib.form.help("Range: 0 - 63");
906       $fieldset.append($label).append($input).append($help);
907       if(edit) {
908         $input.val(existingFlow.tosBits);
909       }
910
911       // layer 4
912       var $legend = one.lib.form.legend("Layer 4");
913       $fieldset.append($legend);
914       // srcPort
915       var $label = one.lib.form.label("Source Port");
916       var $input = one.lib.form.input("Source Port");
917       $input.attr('id', one.f.flows.id.modal.form.srcPort);
918       var $help = one.lib.form.help("Range: 0 - 65535");
919       $fieldset.append($label).append($input).append($help);
920       if(edit) {
921         $input.val(existingFlow.srcPort);
922       }
923       // dstPort
924       var $label = one.lib.form.label("Destination Port");
925       var $input = one.lib.form.input("Destination Port");
926       $input.attr('id', one.f.flows.id.modal.form.dstPort);
927       var $help = one.lib.form.help("Range: 0 - 65535");
928       $fieldset.append($label).append($input).append($help);
929       if(edit) {
930         $input.val(existingFlow.dstPort);
931       }
932       // protocol
933       var $label = one.lib.form.label("Protocol");
934       var $input = one.lib.form.input("Protocol");
935       $input.attr('id', one.f.flows.id.modal.form.protocol);
936       $fieldset.append($label).append($input);
937       if(edit) {
938         $input.val(existingFlow.protocol);
939       }
940       // actions
941       var $legend = one.lib.form.label("Actions");
942       $fieldset.append($legend);
943       // actions table
944       var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
945       var $table = one.lib.dashlet.table.table(tableAttributes);
946       $table.attr('id', one.f.flows.id.modal.action.table);
947       var tableHeaders = ["Action", "Data"];
948       var $thead = one.lib.dashlet.table.header(tableHeaders);
949       var $tbody = one.lib.dashlet.table.body("", tableHeaders);
950       $table.append($thead).append($tbody);
951       // actions
952       var actions = {
953         "" : "Please Select an Action",
954         "DROP" : "Drop",
955         "LOOPBACK" : "Loopback",
956         "FLOOD" : "Flood",
957         "FLOOD_ALL" : "Flood All",
958         "CONTROLLER" : "Controller",
959         "SW_PATH" : "Software Path",
960         "HW_PATH" : "Hardware Path",
961         "OUTPUT" : "Add Output Ports",
962         "ENQUEUE" : "Enqueue",
963         "SET_VLAN_ID" : "Set VLAN ID",
964         "SET_VLAN_PCP" : "Set VLAN Priority",
965         "SET_VLAN_CFI" : "Set VLAN CFI",
966         "POP_VLAN" : "Strip VLAN Header",
967         "PUSH_VLAN" : "Push VLAN",
968         "SET_DL_SRC" : "Modify Datalayer Source Address",
969         "SET_DL_DST" : "Modify Datalayer Destination Address",
970         "SET_DL_TYPE" : "Set Ethertype",
971         "SET_NW_SRC" : "Modify Network Source Address",
972         "SET_NW_DST" :"Modify Network Destination Address",
973         "SET_NW_TOS" : "Modify ToS Bits",
974         "SET_TP_SRC" : "Modify Transport Source Port",
975         "SET_TP_DST" : "Modify Transport Destination Port"
976       };
977       var $select = one.lib.form.select.create(actions);
978       $select.attr('id', one.f.flows.id.modal.form.action);
979       // when selecting an action
980       $select.change(function() {
981         var action = $(this).find('option:selected');
982         one.f.flows.modal.action.parse(action.attr('value'));
983         $select[0].selectedIndex = 0;
984       });
985
986       if(edit) {
987         $(existingFlow.actions).each(function(index, value){
988           setTimeout(function(){
989             var locEqualTo = value.indexOf("=");
990             if ( locEqualTo == -1 ) {
991               one.f.flows.modal.action.add.add(actions[value], value);
992             } else {
993               var action = value.substr(0,locEqualTo);
994               if( action == "OUTPUT") {
995                 var portIds = value.substr(locEqualTo+1).split(",");
996                 var ports = [];
997                 var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
998                 for(var i =0; i < portIds.length ; i++) {
999                   var portName = allPorts[portIds[i]];
1000                   ports.push(portName);
1001                 }
1002                 one.f.flows.modal.action.add.addPortsToTable(ports.join(", "), portIds.join(","));
1003               } else {
1004                 var val = value.substr(locEqualTo+1);
1005                 one.f.flows.modal.action.add.addDataToTable(actions[action], val, action)
1006               }
1007             }
1008           }, 1000)
1009         });
1010       }
1011       $fieldset.append($select).append($table);
1012
1013       // return
1014       $form.append($fieldset);
1015       return $form;
1016     },
1017     action : {
1018       parse : function(option) {
1019         switch (option) {
1020           case "OUTPUT" :
1021             var h3 = "Add Output Port";
1022             var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addOutputPorts, one.f.flows.modal.action.add.addOutputPorts);
1023             $modal.modal();
1024             break;
1025           case "SET_VLAN_ID" :
1026             var h3 = "Set VLAN ID";
1027             var placeholder = "VLAN Identification Number";
1028             var id = one.f.flows.id.modal.action.setVlanId;
1029             var help = "Range: 0 - 4095";
1030             var action = 'SET_VLAN_ID';
1031             var name = "VLAN ID";
1032             var body = function() {
1033               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1034             };
1035             var add = function($modal) {
1036               one.f.flows.modal.action.add.set(name, id, action, $modal);
1037             };
1038             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1039             $modal.modal();
1040             break;
1041           case "SET_VLAN_PCP" :
1042             var h3 = "Set VLAN Priority";
1043             var placeholder = "VLAN Priority";
1044             var id = one.f.flows.id.modal.action.setVlanPriority;
1045             var help = "Range: 0 - 7";
1046             var action = 'SET_VLAN_PCP';
1047             var name = "VLAN Priority";
1048             var body = function() {
1049               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1050             };
1051             var add = function($modal) {
1052               one.f.flows.modal.action.add.set(name, id, action, $modal);
1053             };
1054             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1055             $modal.modal();
1056             break;
1057           case "SET_VLAN_CFI" :
1058             var h3 = "Set VLAN CFI";
1059             var placeholder = "VLAN CFI";
1060             var id = one.f.flows.id.modal.action.setVlanCfi;
1061             var help = "Range: 0 - 1";
1062             var action = 'SET_VLAN_CFI';
1063             var name = "VLAN CFI";
1064             var body = function() {
1065               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1066             };
1067             var add = function($modal) {
1068               one.f.flows.modal.action.add.set(name, id, action, $modal);
1069             };
1070             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1071             $modal.modal();
1072             break;
1073           case "POP_VLAN" :
1074             var name = "Strip VLAN Header";
1075             var action = 'POP_VLAN';
1076             one.f.flows.modal.action.add.add(name, action);
1077             break;
1078           case "PUSH_VLAN" :
1079             var h3 = "Push VLAN";
1080             var placeholder = "VLAN";
1081             var id = one.f.flows.id.modal.action.pushVlan;
1082             var help = "Range: 0 - 4095";
1083             var action = 'PUSH_VLAN';
1084             var name = "VLAN";
1085             var body = function() {
1086               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1087             };
1088             var add = function($modal) {
1089               one.f.flows.modal.action.add.set(name, id, action, $modal);
1090             };
1091             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1092             $modal.modal();
1093             break;
1094           case "SET_DL_SRC" :
1095             var h3 = "Set Source MAC Address";
1096             var placeholder = "Source MAC Address";
1097             var id = one.f.flows.id.modal.action.modifyDatalayerSourceAddress;
1098             var help = "Example: 00:11:22:aa:bb:cc";
1099             var action = 'SET_DL_SRC';
1100             var name = "Source MAC";
1101             var body = function() {
1102               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1103             };
1104             var add = function($modal) {
1105               one.f.flows.modal.action.add.set(name, id, action, $modal);
1106             };
1107             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1108             $modal.modal();
1109             break;
1110           case "SET_DL_DST" :
1111             var h3 = "Set Destination MAC Address";
1112             var placeholder = "Destination MAC Address";
1113             var id = one.f.flows.id.modal.action.modifyDatalayerDestinationAddress;
1114             var help = "Example: 00:11:22:aa:bb:cc";
1115             var action = 'SET_DL_DST';
1116             var name = "Destination MAC";
1117             var body = function() {
1118               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1119             };
1120             var add = function($modal) {
1121               one.f.flows.modal.action.add.set(name, id, action, $modal);
1122             };
1123             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1124             $modal.modal();
1125             break;
1126           case "SET_DL_TYPE" :
1127             var h3 = "Set Ethertype";
1128             var placeholder = "Ethertype";
1129             var id = one.f.flows.id.modal.action.setEthertype;
1130             var help = "Range: 0 - 65535";
1131             var action = 'SET_DL_TYPE';
1132             var name = "Ethertype";
1133             var body = function() {
1134               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1135             };
1136             var add = function($modal) {
1137               one.f.flows.modal.action.add.set(name, id, action, $modal);
1138             };
1139             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1140             $modal.modal();
1141             break;
1142           case "SET_NW_SRC" :
1143             var h3 = "Set IP Source Address";
1144             var placeholder = "Source IP Address";
1145             var id = one.f.flows.id.modal.action.modifyNetworkSourceAddress;
1146             var help = "Example: 127.0.0.1";
1147             var action = 'SET_NW_SRC';
1148             var name = "Source IP";
1149             var body = function() {
1150               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1151             };
1152             var add = function($modal) {
1153               one.f.flows.modal.action.add.set(name, id, action, $modal);
1154             };
1155             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1156             $modal.modal();
1157             break;
1158           case "SET_NW_DST" :
1159             var h3 = "Set IP Destination Address";
1160             var placeholder = "Destination IP Address";
1161             var id = one.f.flows.id.modal.action.modifyNetworkDestinationAddress;
1162             var help = "Example: 127.0.0.1";
1163             var action = 'SET_NW_DST';
1164             var name = "Destination IP";
1165             var body = function() {
1166               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1167             };
1168             var add = function($modal) {
1169               one.f.flows.modal.action.add.set(name, id, action, $modal);
1170             };
1171             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1172             $modal.modal();
1173             break;
1174           case "SET_NW_TOS" :
1175             var h3 = "Set IPv4 ToS";
1176             var placeholder = "IPv4 ToS";
1177             var id = one.f.flows.id.modal.action.modifyTosBits;
1178             var help = "Range: 0 - 63";
1179             var action = 'SET_NW_TOS';
1180             var name = "ToS Bits";
1181             var body = function() {
1182               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1183             };
1184             var add = function($modal) {
1185               one.f.flows.modal.action.add.set(name, id, action, $modal);
1186             };
1187             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1188             $modal.modal();
1189             break;
1190           case "SET_TP_SRC" :
1191             var h3 = "Set Transport Source Port";
1192             var placeholder = "Transport Source Port";
1193             var id = one.f.flows.id.modal.action.modifyTransportSourcePort;
1194             var help = "Range: 1 - 65535";
1195             var action = 'SET_TP_SRC';
1196             var name = "Source Port";
1197             var body = function() {
1198               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1199             };
1200             var add = function($modal) {
1201               one.f.flows.modal.action.add.set(name, id, action, $modal);
1202             };
1203             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1204             $modal.modal();
1205             break;
1206           case "SET_TP_DST" :
1207             var h3 = "Set Transport Destination Port";
1208             var placeholder = "Transport Destination Port";
1209             var id = one.f.flows.id.modal.action.modifyTransportDestinationPort;
1210             var help = "Range: 1 - 65535";
1211             var action = 'SET_TP_DST';
1212             var name = "Destination Port";
1213             var body = function() {
1214               return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
1215             };
1216             var add = function($modal) {
1217               one.f.flows.modal.action.add.set(name, id, action, $modal);
1218             };
1219             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
1220             $modal.modal();
1221             break;
1222           case "ENQUEUE" :
1223             var h3 = "Enqueue";
1224             var placeholder = "Enqueue";
1225             var id = one.f.flows.id.modal.action.enqueue;
1226             var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addEnqueue, one.f.flows.modal.action.add.addEnqueue);
1227             $modal.modal();
1228             break;
1229           case "DROP" :
1230             var name = "Drop";
1231             var action = 'DROP';
1232             one.f.flows.modal.action.add.add(name, action);
1233             break;
1234           case "LOOPBACK" :
1235             var name = "Loopback";
1236             var action = 'LOOPBACK';
1237             one.f.flows.modal.action.add.add(name, action);
1238             break;
1239           case "FLOOD" :
1240             var name = "Flood";
1241             var action = 'FLOOD';
1242             one.f.flows.modal.action.add.add(name, action);
1243             break;
1244           case "FLOOD_ALL" :
1245             var name = "Flood All";
1246             var action = 'FLOOD_ALL';
1247             one.f.flows.modal.action.add.add(name, action);
1248             break;
1249           case "SW_PATH" :
1250             var name = "Software Path";
1251             var action = 'SW_PATH';
1252             one.f.flows.modal.action.add.add(name, action);
1253             break;
1254           case "HW_PATH" :
1255             var name = "Hardware Path";
1256             var action = 'HW_PATH';
1257             one.f.flows.modal.action.add.add(name, action);
1258             break;
1259           case "CONTROLLER" :
1260             var name = "Controller";
1261             var action = 'CONTROLLER';
1262             one.f.flows.modal.action.add.add(name, action);
1263             break;
1264         }
1265       },
1266       initialize : function(h3, bodyCallback, addCallback) {
1267         var footer = one.f.flows.modal.action.footer();
1268         var $body = bodyCallback();
1269         var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal, h3, $body, footer);
1270         // bind close button
1271         $('#'+one.f.flows.id.modal.action.close, $modal).click(function() {
1272           $modal.modal('hide');
1273         });
1274         // bind add flow button
1275         $('#'+one.f.flows.id.modal.action.add, $modal).click(function() {
1276           addCallback($modal);
1277         });
1278         return $modal;
1279       },
1280       add : {
1281         addOutputPorts : function($modal) {
1282           var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
1283           var ports = '';
1284           var pid = '';
1285           $options.each(function(index, value) {
1286             ports = ports+$(value).text()+", ";
1287             pid = pid+$(value).attr('value')+",";
1288           });
1289           ports = ports.slice(0,-2);
1290           pid = pid.slice(0,-1);
1291           one.f.flows.modal.action.add.addPortsToTable(ports, pid);
1292           $modal.modal('hide');
1293         },
1294         addEnqueue : function($modal) {
1295           var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
1296           var ports = '';
1297           var pid = '';
1298           $options.each(function(index, value) {
1299             ports = ports+$(value).text()+", ";
1300             pid = pid+$(value).attr('value')+",";
1301           });
1302           var $input = $('#'+one.f.flows.id.modal.action.queue);
1303           var queue = $input.val();
1304           ports = ports.slice(0,-2);
1305           pid = pid.slice(0,-1);
1306           one.f.flows.modal.action.add.addEnqueueToTable(ports, pid, queue);
1307           $modal.modal('hide');
1308         },
1309         addEnqueueToTable : function(ports, pid, queue) {
1310           if (queue !== '' && queue >= 0) {
1311             ports += ':'+queue;
1312           }
1313           var $tr = one.f.flows.modal.action.table.add("Enqueue", ports);
1314           $tr.attr('id', 'ENQUEUE');
1315           if (queue !== '' && queue >= 0) {
1316             $tr.data('action', 'ENQUEUE='+pid+':'+queue);
1317           } else {
1318             $tr.data('action', 'ENQUEUE='+pid+':0'); // default queue to 0
1319           }
1320           $tr.click(function() {
1321             one.f.flows.modal.action.add.modal.initialize(this);
1322           });
1323           one.f.flows.modal.action.table.append($tr);
1324         },
1325         addPortsToTable : function(ports, pid){
1326           var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
1327           $tr.attr('id', 'OUTPUT');
1328           $tr.data('action', 'OUTPUT='+pid);
1329           $tr.click(function() {
1330             one.f.flows.modal.action.add.modal.initialize(this);
1331           });
1332           one.f.flows.modal.action.table.append($tr);
1333         },
1334         add : function(name, action) {
1335           var $tr = one.f.flows.modal.action.table.add(name);
1336           $tr.attr('id', action);
1337           $tr.data('action', action);
1338           $tr.click(function() {
1339             one.f.flows.modal.action.add.modal.initialize(this);
1340           });
1341           one.f.flows.modal.action.table.append($tr);
1342         },
1343         set : function(name, id, action, $modal) {
1344           var $input = $('#'+id);
1345           var value = $input.val();
1346           one.f.flows.modal.action.add.addDataToTable(name,value,action)
1347             $modal.modal('hide');
1348         },
1349         addDataToTable : function(name,value,action) {
1350           var $tr = one.f.flows.modal.action.table.add(name, value);
1351           $tr.attr('id', action);
1352           $tr.data('action', action+'='+value);
1353           $tr.click(function() {
1354             one.f.flows.modal.action.add.modal.initialize(this);
1355           });
1356           one.f.flows.modal.action.table.append($tr);
1357         },
1358         remove : function(that) {
1359           $(that).remove();
1360           var $table = $('#'+one.f.flows.id.modal.action.table);
1361           if ($table.find('tbody').find('tr').size() == 0) {
1362             var $tr = $(document.createElement('tr'));
1363             var $td = $(document.createElement('td'));
1364             $td.attr('colspan', '3');
1365             $tr.addClass('empty');
1366             $td.text('No data available');
1367             $tr.append($td);
1368             $table.find('tbody').append($tr);
1369           }
1370         },
1371         modal : {
1372           initialize : function(that) {
1373             var h3 = "Remove Action";
1374             var footer = one.f.flows.modal.action.add.modal.footer();
1375             var $body = one.f.flows.modal.action.add.modal.body();
1376             var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
1377
1378             // bind cancel button
1379             $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
1380               $modal.modal('hide');
1381             });
1382
1383             // bind remove button
1384             $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
1385               one.f.flows.modal.action.add.remove(that);
1386               $modal.modal('hide');
1387             });
1388
1389             $modal.modal();
1390           },
1391           body : function() {
1392             var $p = $(document.createElement('p'));
1393             $p.append("Remove this action?");
1394             return $p;
1395           },
1396           footer : function() {
1397             var footer = [];
1398
1399             var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
1400             var $removeButton = one.lib.dashlet.button.button(removeButton);
1401             footer.push($removeButton);
1402
1403             var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
1404             var $cancelButton = one.lib.dashlet.button.button(cancelButton);
1405             footer.push($cancelButton);
1406
1407             return footer;
1408           }
1409         }
1410       },
1411       table : {
1412         add : function(action, data) {
1413           var $tr = $(document.createElement('tr'));
1414           var $td = $(document.createElement('td'));
1415           $td.append(action);
1416           $tr.append($td);
1417           var $td = $(document.createElement('td'));
1418           if (data != undefined) $td.append(data);
1419           $tr.append($td);
1420           return $tr;
1421         },
1422         append : function($tr) {
1423           var $table = $('#'+one.f.flows.id.modal.action.table);
1424           var $empty = $table.find('.empty').parent();
1425           if ($empty.size() > 0) $empty.remove();
1426           $table.append($tr);
1427         }
1428       },
1429       body : {
1430         common : function() {
1431           var $form = $(document.createElement('form'));
1432           var $fieldset = $(document.createElement('fieldset'));
1433           return [$form, $fieldset];
1434         },
1435         addOutputPorts : function() {
1436           var common = one.f.flows.modal.action.body.common();
1437           var $form = common[0];
1438           var $fieldset = common[1];
1439           // output port
1440           $label = one.lib.form.label("Select Output Ports");
1441           if (one.f.flows.registry.currentNode == undefined){
1442             return; //Selecting Output ports without selecting node throws an exception
1443           }
1444           var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
1445           $select = one.lib.form.select.create(ports, true);
1446           $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
1447           $fieldset.append($label).append($select);
1448           $form.append($fieldset);
1449           return $form;
1450         },
1451         addEnqueue : function() {
1452           var common = one.f.flows.modal.action.body.common();
1453           var $form = common[0];
1454           var $fieldset = common[1];
1455           // output port
1456           $label = one.lib.form.label("Select Output Ports");
1457           if (one.f.flows.registry.currentNode == undefined){
1458             return; //Selecting Output ports without selecting node throws an exception
1459           }
1460           var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
1461           $select = one.lib.form.select.create(ports);
1462           $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
1463           $fieldset.append($label).append($select);
1464           $label = one.lib.form.label('Queue (Optional)');
1465           $input = one.lib.form.input('Queue')
1466           .attr('id', one.f.flows.id.modal.action.queue);
1467           $help = one.lib.form.help('Range: 1 - 2147483647');
1468           $fieldset.append($label).append($input).append($help);
1469           $form.append($fieldset);
1470           return $form;
1471         },
1472         set : function(label, placeholder, id, help) {
1473           var common = one.f.flows.modal.action.body.common();
1474           var $form = common[0];
1475           var $fieldset = common[1];
1476           // input
1477           $label = one.lib.form.label(label);
1478           $input = one.lib.form.input(placeholder);
1479           $input.attr('id', id);
1480           $help = one.lib.form.help(help);
1481           // append
1482           $fieldset.append($label).append($input).append($help);
1483           $form.append($fieldset);
1484           return $form;
1485         }
1486       },
1487       footer : function() {
1488         var footer = [];
1489         var addButton = one.lib.dashlet.button.single("Add Action", one.f.flows.id.modal.action.add, "btn-primary", "");
1490         var $addButton = one.lib.dashlet.button.button(addButton);
1491         footer.push($addButton);
1492
1493         var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.action.close, "", "");
1494         var $closeButton = one.lib.dashlet.button.button(closeButton);
1495         footer.push($closeButton);
1496
1497         return footer;
1498       }
1499     },
1500     footer : function() {
1501       var footer = [];
1502
1503       var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
1504       var $installButton = one.lib.dashlet.button.button(installButton);
1505       footer.push($installButton);
1506
1507       var addButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.add, "btn-primary", "");
1508       var $addButton = one.lib.dashlet.button.button(addButton);
1509       footer.push($addButton);
1510
1511       var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
1512       var $closeButton = one.lib.dashlet.button.button(closeButton);
1513       footer.push($closeButton);
1514
1515       return footer;
1516     },
1517     footerEdit : function() {
1518       var footer = [];
1519
1520       var editButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.edit, "btn-success", "");
1521       var $editButton = one.lib.dashlet.button.button(editButton);
1522       footer.push($editButton);
1523
1524       var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
1525       var $closeButton = one.lib.dashlet.button.button(closeButton);
1526       footer.push($closeButton);
1527
1528       return footer;
1529     },
1530     removeMultiple: {
1531       dialog: function(flows) {
1532         var h3 = 'Remove Flow Entry';
1533         var flowList = [];
1534         for (var i = 0; i < flows.length; i++) {
1535           flowList.push(flows[i]["name"]);
1536         }
1537         var footer = one.f.flows.modal.removeMultiple.footer();
1538         var $body = one.f.flows.modal.removeMultiple.body(flowList);
1539         var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $body, footer);
1540
1541         // bind close button
1542         $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
1543           $modal.modal('hide');
1544         });
1545
1546         // bind remove rule button
1547         $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(this, function(e) {
1548           var resource = {};
1549           resource['body'] = JSON.stringify(flows);
1550
1551           $.post(one.f.address.root+one.f.address.flows.deleteFlows, resource, function(response) {
1552             $modal.modal('hide');
1553             if(response == "Success") {
1554               one.lib.alert("Flow Entry(s) successfully removed");
1555             } else {
1556               one.lib.alert(response);
1557             }
1558             one.main.dashlet.right.bottom.empty();
1559             one.f.detail.dashlet(one.main.dashlet.right.bottom);
1560             one.main.dashlet.left.top.empty();
1561             one.f.flows.dashlet(one.main.dashlet.left.top);
1562           });
1563         });
1564         $modal.modal();
1565       },
1566       footer : function() {
1567         var footer = [];
1568         var remove = one.lib.dashlet.button.single('Remove Flow Entry',one.f.flows.id.modal.dialog.remove, 'btn-danger', '');
1569         var $remove = one.lib.dashlet.button.button(remove);
1570         footer.push($remove);
1571
1572         var cancel = one.lib.dashlet.button.single('Cancel', one.f.flows.id.modal.dialog.close, '', '');
1573         var $cancel = one.lib.dashlet.button.button(cancel);
1574         footer.push($cancel);
1575
1576         return footer;
1577       },
1578       body : function (flows) {
1579         var $p = $(document.createElement('p'));
1580         var p = 'Remove the following Flow Entry(s)?';
1581         //creata a BS label for each rule and append to list
1582         $(flows).each(function(){
1583           var $span = $(document.createElement('span'));
1584           $span.append(this);
1585           p += '<br/>' + $span[0].outerHTML;
1586         });
1587         $p.append(p);
1588         return $p;
1589       }
1590     }
1591   },
1592   ajax : {
1593     dashlet : function(callback) {
1594       $.getJSON(one.f.address.root+one.f.address.flows.main, function(data) {
1595         one.f.flows.registry['flows'] = data.flows;
1596         one.f.flows.registry['privilege'] = data.privilege;
1597         one.f.flows.modal.ajax.nodes(function(){/*Empty function. Do nothing. */})
1598
1599         callback(data);
1600       });
1601     }
1602   },
1603   data : {
1604     flowsDataGrid: function(data) {
1605       var source = new StaticDataSource({
1606         columns: [
1607       {
1608         property: 'selector',
1609       label: "<input type='checkbox' id='"+one.f.flows.id.dashlet.datagrid.selectAllFlows+"'/>",
1610       sortable: false
1611       },
1612       {
1613         property: 'name',
1614       label: 'Flow Name',
1615       sortable: true
1616       },
1617       {
1618         property: 'node',
1619       label: 'Node',
1620       sortable: true
1621       }
1622       ],
1623       data: data.flows,
1624       formatter: function(items) {
1625         $.each(items, function(index, item) {
1626           var $checkbox = document.createElement("input");
1627           $checkbox.setAttribute("type", "checkbox");
1628           $checkbox.setAttribute("name", item.name);
1629           $checkbox.setAttribute("node", item.nodeId);
1630           $checkbox.setAttribute('class','flowEntry')
1631           item.selector = $checkbox.outerHTML;
1632         item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
1633           ' data-flowstatus=' + item["flow"]["status"] + 
1634           ' data-nodeId=' + item["nodeId"] + '>' + item["name"] + '</span>';
1635         });
1636
1637       },
1638       delay: 0
1639       });
1640       return source;
1641     },
1642     dashlet : function(data) {
1643       var body = [];
1644       $(data).each(function(index, value) {
1645         var tr = {};
1646         var entry = [];
1647
1648
1649         entry.push(value['name']);
1650         entry.push(value['node']);
1651         if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
1652         tr['type'] = ['success'];
1653         else if (value['flow']['installInHw'] == 'false' && value['flow']['status'] == 'Success')
1654         tr['type'] = ['warning'];
1655         else 
1656         tr['type'] = ['warning'];
1657       tr['entry'] = entry;
1658       tr['id'] = value['nodeId'];
1659
1660       body.push(tr);
1661       });
1662       return body;
1663     }
1664   },
1665   body : {
1666     dashlet : function(body, callback) {
1667       var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed', 'table-cursor'];
1668       var $table = one.lib.dashlet.table.table(attributes);
1669
1670       var headers = ['Flow Name', 'Node'];
1671
1672       var $thead = one.lib.dashlet.table.header(headers);
1673       $table.append($thead);
1674
1675       var $tbody = one.lib.dashlet.table.body(body);
1676       $table.append($tbody);
1677       return $table;
1678     }
1679   }
1680 }
1681
1682 /** INIT **/
1683 // populate nav tabs
1684 $(one.f.menu.left.top).each(function(index, value) {
1685   var $nav = $(".nav", "#left-top");
1686   one.main.page.dashlet($nav, value);
1687 });
1688
1689 $(one.f.menu.left.bottom).each(function(index, value) {
1690   var $nav = $(".nav", "#left-bottom");
1691   one.main.page.dashlet($nav, value);
1692 });
1693
1694 $(one.f.menu.right.bottom).each(function(index, value) {
1695   var $nav = $(".nav", "#right-bottom");
1696   one.main.page.dashlet($nav, value);
1697 });
1698
1699 one.f.populate = function($dashlet, header) {
1700   var $h4 = one.lib.dashlet.header(header);
1701   $dashlet.append($h4);
1702 };
1703
1704 // bind dashlet nav
1705 $('.dash .nav a', '#main').click(function() {
1706   // de/activation
1707   var $li = $(this).parent();
1708   var $ul = $li.parent();
1709   one.lib.nav.unfocus($ul);
1710   $li.addClass('active');
1711   // clear respective dashlet
1712   var $dashlet = $ul.parent().find('.dashlet');
1713   one.lib.dashlet.empty($dashlet);
1714   // callback based on menu
1715   var id = $(this).attr('id');
1716   var menu = one.f.dashlet;
1717   switch (id) {
1718     case menu.flows.id:
1719       one.f.flows.dashlet($dashlet);
1720       break;
1721     case menu.nodes.id:
1722       one.f.nodes.dashlet($dashlet);
1723       break;
1724     case menu.detail.id:
1725       one.f.detail.dashlet($dashlet);
1726       break;
1727   };
1728 });
1729
1730 // activate first tab on each dashlet
1731 $('.dash .nav').each(function(index, value) {
1732   $($(value).find('li')[0]).find('a').click();
1733 });