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