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