// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
(function(cloudStack, $) {
  var ingressEgressDataMap = function(elem) {
    var elemData = {
      id: elem.ruleid,
      protocol: elem.protocol,
      startport: elem.startport,
      endport: elem.endport,
      cidr: elem.cidr ? elem.cidr : ''.concat(elem.account, ' - ', elem.securitygroupname)
    };
    if (elemData.startport == 0 && elemData.endport) {
      elemData.startport = '0';
    } else if (elem.icmptype && elem.icmpcode) {
      elemData.startport = elem.icmptype;
      elemData.endport = elem.icmpcode;
    }
    return elemData;
  };
  var instanceSecondaryIPSubselect = function(args) {
    var instance = args.context.instances[0];
    var network = args.context.networks[0];
    var nic = $.grep(instance.nic, function(nic) {
      return nic.networkid == network.id;
    })[0];
    // Get NIC IPs
    $.ajax({
      url: createURL('listNics'),
      data: {
        virtualmachineid: instance.id,
        nicId: nic.id
      },
      success: function(json) {
        var nic = json.listnics.nic[0];
        var ips = nic.secondaryip ? nic.secondaryip : [];
        var ipSelection = [];
        // Add primary IP as default
        ipSelection.push({ id: -1, description: nic.ipaddress + ' (Primary)' });
        // Add secondary IPs
        $(ips).map(function(index, ip) {
          ipSelection.push({
            id: ip.ipaddress,
            description: ip.ipaddress
          });
        }); 
        args.response.success({
          data: ipSelection
        });
      }
    })
  };
  
  var ipChangeNotice = function() {
    cloudStack.dialog.confirm({
      message: 'message.ip.address.changed',
      action: function() {
        $('#browser .container').cloudBrowser('selectPanel', {
          panel: $('#browser .panel:last').prev(),
          complete: function() {
            $(window).trigger('cloudStack.fullRefresh');
          }
        });
      }
    });
  };
  var zoneObjs = [];
  var actionFilters = {
    ipAddress: function(args) {
      var allowedActions = args.context.actions;
      var disallowedActions = [];
      var item = args.context.item;
      var status = item.state;
      if (status == 'Destroyed' ||
          status == 'Releasing' ||
          status == 'Released' ||
          status == 'Creating' ||
          status == 'Allocating' ||
          item.account == 'system' ||
          item.issystem == true ) {
            return [];
          }
      if(item.networkOfferingConserveMode == false) {
        /*
         (1) If IP is SourceNat, no StaticNat/VPN/PortForwarding/LoadBalancer can be enabled/added.
         */
        if (item.issourcenat == true){
          disallowedActions.push('enableStaticNAT');
          disallowedActions.push('enableVPN');
        }
        /*
         (2) If IP is non-SourceNat, show StaticNat/VPN/PortForwarding/LoadBalancer at first.
         1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer.
         2. Once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer.
         3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer.
         4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding.
         */
        else { //item.issourcenat == false
          if (item.isstaticnat) { //1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer.
            disallowedActions.push('enableVPN');
          }
          if (item.vpnenabled) { //2. Once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer.
            disallowedActions.push('enableStaticNAT');
          }
          //3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer.
          $.ajax({
            url: createURL('listPortForwardingRules'),
            data: {
              ipaddressid: item.id,
              listAll: true
            },
            dataType: 'json',
            async: false,
            success: function(json) {
              var rules = json.listportforwardingrulesresponse.portforwardingrule;
              if(rules != null && rules.length > 0) {
                disallowedActions.push('enableVPN');
                disallowedActions.push('enableStaticNAT');
              }
            }
          });
          //4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding.
          $.ajax({
            url: createURL('listLoadBalancerRules'),
            data: {
              publicipid: item.id,
              listAll: true
            },
            dataType: 'json',
            async: false,
            success: function(json) {
              var rules = json.listloadbalancerrulesresponse.loadbalancerrule;
              if(rules != null && rules.length > 0) {
                disallowedActions.push('enableVPN');
                disallowedActions.push('enableStaticNAT');
              }
            }
          });
        }
      }
			if(item.networkOfferingConserveMode == false) {			 
				/*
				(1) If IP is SourceNat, no StaticNat/VPN/PortForwarding/LoadBalancer can be enabled/added. 
				*/
	      if (item.issourcenat == true){
					disallowedActions.push('enableStaticNAT');
					disallowedActions.push('enableVPN');
				}			
				
				/*
				(2) If IP is non-SourceNat, show StaticNat/VPN/PortForwarding/LoadBalancer at first.
				1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer.
				2. Once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer.
				3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer.
				4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding.
				*/
				else { //item.issourcenat == false				   
					if (item.isstaticnat) { //1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer.
					  disallowedActions.push('enableVPN');
					}
					if (item.vpnenabled) { //2. Once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer.
					  disallowedActions.push('enableStaticNAT');
					}
								 
					//3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer.
					$.ajax({
						url: createURL('listPortForwardingRules'),
						data: {
							ipaddressid: item.id,
							listAll: true
						},
						dataType: 'json',
						async: false,
						success: function(json) {							
							var rules = json.listportforwardingrulesresponse.portforwardingrule;
							if(rules != null && rules.length > 0) {
							  disallowedActions.push('enableVPN');
								disallowedActions.push('enableStaticNAT'); 
							}
						}
					});	
										
					//4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding.
					$.ajax({
						url: createURL('listLoadBalancerRules'),
						data: {
							publicipid: item.id,
							listAll: true
						},
						dataType: 'json',
						async: false,
						success: function(json) {
							var rules = json.listloadbalancerrulesresponse.loadbalancerrule;
							if(rules != null && rules.length > 0) {
							  disallowedActions.push('enableVPN');
								disallowedActions.push('enableStaticNAT'); 
							}
						}
					});		
				}			  				
			}			
			
      if (item.isstaticnat) {
        disallowedActions.push('enableStaticNAT');
      } else {
        disallowedActions.push('disableStaticNAT');
      }
			if(item.networkOfferingHavingVpnService == true) {      
        if (item.vpnenabled) {
          disallowedActions.push('enableVPN');
        } else {
          disallowedActions.push('disableVPN');
        }
      } else { //item.networkOfferingHavingVpnService == false
        disallowedActions.push('disableVPN');
        disallowedActions.push('enableVPN');
      }
      if (item.issourcenat){
        disallowedActions.push('enableStaticNAT');
        disallowedActions.push('disableStaticNAT');
        disallowedActions.push('remove');
      }
      allowedActions = $.grep(allowedActions, function(item) {
        return $.inArray(item, disallowedActions) == -1;
      });
      return allowedActions;
    },
    securityGroups: function(args) {
      var allowedActions = [];
      var isSecurityGroupOwner = isAdmin() || isDomainAdmin() ||
            args.context.item.account == args.context.users[0].account;
      if (isSecurityGroupOwner &&
          args.context.item.state != 'Destroyed' &&
          args.context.item.name != 'default') {
        allowedActions.push('remove');
      }
      return allowedActions;
    }
  };
	var networkOfferingObjs = [];
        var checkVpc=0; 	
  cloudStack.sections.network = {
    title: 'label.network',
    id: 'network',
    sectionSelect: {
      preFilter: function(args) {
        var havingSecurityGroupNetwork = false;
        var havingBasicZones = false;
        var havingAdvancedZones = true;
        // Get zone types
        $.ajax({
          url: createURL('listZones'),
          async: false,
          success: function(json) {
            var zones = json.listzonesresponse.zone ?
                  json.listzonesresponse.zone : [];
            var basicZones = $.grep(zones, function(zone) {
              return zone.networktype == 'Basic';
            });
            var advancedZones = $.grep(zones, function(zone) {
              return zone.networktype == 'Advanced';
            });
            
            havingBasicZones = basicZones.length ? true : false;
            havingAdvancedZones = advancedZones.length ? true : false;    
      }
        });
        
        $.ajax({
          url: createURL('listNetworks', { ignoreProject: true }),
          data: {
            supportedServices: 'SecurityGroup',
            listAll: true,
						details: 'min'
          },
          async: false,
          success: function(data) {
            if (data.listnetworksresponse.network != null && data.listnetworksresponse.network.length > 0) {
              havingSecurityGroupNetwork = true;
            }
          }
        });
        var sectionsToShow = ['networks'];
        if (havingAdvancedZones) {
          sectionsToShow.push('vpc');
          sectionsToShow.push('vpnCustomerGateway');
        }
        
        if(havingSecurityGroupNetwork == true)
          sectionsToShow.push('securityGroups');
        return sectionsToShow;
      },
      label: 'label.select-view'
    },
    sections: {
      networks: {
        id: 'networks',
        type: 'select',
        title: 'label.guest.networks',
        listView: {
          actions: {
            add: {
              label: 'label.add.guest.network',
              preFilter: function(args) {
                var advSgDisabledZones;
								$.ajax({
									url: createURL('listZones'),
									async: false,
									success: function(json) {									 
										advSgDisabledZones = $.grep(json.listzonesresponse.zone, function(zone) {
											return (zone.networktype == 'Advanced' && zone.securitygroupsenabled	!= true); //Isolated networks can only be created in Advanced SG-disabled zone (but not in Basic zone nor Advanced SG-enabled zone)
										});										
									}
								});								
								return (advSgDisabledZones != null && advSgDisabledZones.length > 0);							
              },
              createForm: {
                title: 'label.add.guest.network',
                desc: 'message.add.guest.network',
                fields: {
                  name: { label: 'label.name', validation: { required: true }, docID: 'helpGuestNetworkName' },
                  displayText: { label: 'label.display.text', validation: { required: true }, docID: 'helpGuestNetworkDisplayText'},
                  zoneId: {
                    label: 'label.zone',
                    validation: { required: true },
                    docID: 'helpGuestNetworkZone',
                    select: function(args) {
                      $.ajax({
                        url: createURL('listZones'),
                        success: function(json) {
                          var zones = $.grep(json.listzonesresponse.zone, function(zone) {
                            return (zone.networktype == 'Advanced' && zone.securitygroupsenabled	!= true); //Isolated networks can only be created in Advanced SG-disabled zone (but not in Basic zone nor Advanced SG-enabled zone)
                          });
                          args.response.success({
                            data: $.map(zones, function(zone) {
                              return {
                                id: zone.id,
                                description: zone.name
                              };
                            })
                          });
                        }
                      });
                    }
                  },
                  networkOfferingId: {
                    label: 'label.network.offering',
                    validation: { required: true },
                    dependsOn: 'zoneId',
                    docID: 'helpGuestNetworkNetworkOffering',
                    select: function(args) {
                      $.ajax({
                        url: createURL('listVPCs'),
                        data: {
                          listAll: true
                        },
                        success: function(json) {
                          var items = json.listvpcsresponse.vpc;
                          var baseUrl = 'listNetworkOfferings&zoneid=' + args.zoneId;
                          var listUrl;
                          if(items != null && items.length > 0) 
                            listUrl = baseUrl;
                          else
                            listUrl = baseUrl + '&forVpc=false';
                          $.ajax({
                            url: createURL(listUrl),
                            data: {
                              guestiptype: 'Isolated',
                              supportedServices: 'SourceNat',
                              specifyvlan: false,
                              state: 'Enabled'
                            },
                            success: function(json) {
                              networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering;
                              args.response.success({
                                data: $.map(networkOfferingObjs, function(zone) {
                                  return {
                                    id: zone.id,
                                    description: zone.name
                                  };
                                })
                              });
                            }
                          });                            
                        }
                      });
                    }
                  },
                  vpcid: {
                    label: 'label.vpc',
                    dependsOn: 'networkOfferingId',
                    select: function(args) {
                      var networkOfferingObj;
                      var $form = args.$select.closest('form');
                      $(networkOfferingObjs).each(function(key, value) {
                        if(value.id == args.networkOfferingId) {
                          networkOfferingObj = value;
                          return false; //break each loop
                        }
                      });
                      if(networkOfferingObj.forvpc == true) {
                        args.$select.closest('.form-item').css('display', 'inline-block');
                        $.ajax({
                          url: createURL('listVPCs'),
                          data: {
                            listAll: true,
														details: 'min'
                          },
                          success: function(json) {
                            var items = json.listvpcsresponse.vpc;
                            var data;
                            if(items != null && items.length > 0) {
                              data = $.map(items, function(item) {
                                return {
                                  id: item.id,
                                  description: item.name
                                }
                              });
                            }
                            args.response.success({ data: data });
                          }
                        });
                        $form.find('.form-item[rel=networkDomain]').hide();
                      }
                      else {
                        args.$select.closest('.form-item').hide();
                        $form.find('.form-item[rel=networkDomain]').show();
                        args.response.success({ data: null });
                      }
                    }
                  },
                  guestGateway: { label: 'label.guest.gateway', docID: 'helpGuestNetworkGateway' },
                  guestNetmask: { label: 'label.guest.netmask', docID: 'helpGuestNetworkNetmask' },
                  networkDomain: { label: 'label.network.domain' }
                }
              },
              action: function(args) {
                var dataObj = {
                  zoneId: args.data.zoneId,
                  name: args.data.name,
                  displayText: args.data.displayText,
                  networkOfferingId: args.data.networkOfferingId
                };		
		
                if(args.data.guestGateway != null && args.data.guestGateway.length > 0) {                  
                  $.extend(dataObj, {
                    gateway: args.data.guestGateway
                  });
                }								
                if(args.data.guestNetmask != null && args.data.guestNetmask.length > 0) {                  
                  $.extend(dataObj, {
                    netmask: args.data.guestNetmask
                  });									
                }								
                if(args.$form.find('.form-item[rel=vpcid]').css("display") != "none") {                 
                  $.extend(dataObj, {
                    vpcid: args.data.vpcid
                  });
                }
                if(args.data.networkDomain != null && args.data.networkDomain.length > 0 && args.$form.find('.form-item[rel=vpcid]').css("display") == "none") {
                  $.extend(dataObj, {
                    networkDomain: args.data.networkDomain
                  });                
                }
															
                $.ajax({
                  url: createURL('createNetwork'),
									data: dataObj,
                  success: function(json) {
                    args.response.success({
                      data: json.createnetworkresponse.network
                    });
                  },
                  error: function(json) {
                    args.response.error(parseXMLHttpResponse(json));
                  }
                });
              },
              messages: {
                notification: function() { return 'label.add.guest.network'; }
              }
            }
          },
          id: 'networks',
          fields: {
            name: { label: 'label.name' },
            account: { label: 'label.account' },            
            type: { label: 'label.type' },            
            cidr: { label: 'label.cidr' }           
          },
          
					advSearchFields: {					 
						zoneid: { 
						  label: 'Zone',							
              select: function(args) {							  					
								$.ajax({
									url: createURL('listZones'),
									data: {
									  listAll: true
									},
									success: function(json) {									  
										var zones = json.listzonesresponse.zone;
										args.response.success({
											data: $.map(zones, function(zone) {
												return {
													id: zone.id,
													description: zone.name
												};
											})
										});
									}
								});
							}						
						},	
            						
						domainid: {					
							label: 'Domain',					
							select: function(args) {
								if(isAdmin() || isDomainAdmin()) {
									$.ajax({
										url: createURL('listDomains'),
										data: { 
											listAll: true,
											details: 'min'
										},
										success: function(json) {
											var array1 = [{id: '', description: ''}];
											var domains = json.listdomainsresponse.domain;
											if(domains != null && domains.length > 0) {
												for(var i = 0; i < domains.length; i++) {
													array1.push({id: domains[i].id, description: domains[i].path});
												}
											}
											args.response.success({
												data: array1
											});
										}
									});
								}
								else {
									args.response.success({
										data: null
									});
								}
							},
							isHidden: function(args) {
								if(isAdmin() || isDomainAdmin())
									return false;
								else
									return true;
							}
						},		
						
						account: { 
							label: 'Account',
							isHidden: function(args) {
								if(isAdmin() || isDomainAdmin())
									return false;
								else
									return true;
							}			
						},						
						tagKey: { label: 'Tag Key' },
						tagValue: { label: 'Tag Value' }						
					},
					
					dataProvider: function(args) {
            var data = {};
						listViewDataProvider(args, data);		
						
            $.ajax({
              url: createURL('listNetworks'),
              data: data,			
              async: false,
              success: function(data) {
                args.response.success({
                  data: data.listnetworksresponse.network
                });
              },
              error: function(data) {
                args.response.error(parseXMLHttpResponse(data));
              }
            });
          },
          detailView: {
            name: 'Guest network details',
            viewAll: {
              path: 'network.ipAddresses',
              label: 'label.menu.ipaddresses',
              preFilter: function(args) {
                if (args.context.networks[0].state == 'Destroyed')
                  return false;
                return true;
              }
            },
            actions: {
              edit: {
                label: 'label.edit',
                messages: {
                  notification: function(args) {
                    return 'label.edit.network.details';
                  }
                },
                action: function(args) {
								  var data = {
									  id: args.context.networks[0].id,		
									  name: args.data.name,
										displaytext: args.data.displaytext
									};
								  
                  //args.data.networkdomain is null when networkdomain field is hidden
                  if(args.data.networkdomain != null && args.data.networkdomain != args.context.networks[0].networkdomain) {
									  $.extend(data, {
										  networkdomain: args.data.networkdomain
										});
									} 
                  
                  var oldcidr;
                  $.ajax({
                    url: createURL("listNetworks&id=" + args.context.networks[0].id ),
                    dataType: "json",
                    async: false,
                    success: function(json) {
                      oldcidr = json.listnetworksresponse.network[0].cidr;
                      
                    }
                  });
                  if(args.data.cidr !="" && args.data.cidr != oldcidr ){
                    $.extend(data, {
                      guestvmcidr: args.data.cidr
                    });
                  }
                  //args.data.networkofferingid is null when networkofferingid field is hidden
                  if(args.data.networkofferingid != null && args.data.networkofferingid != args.context.networks[0].networkofferingid) {
									  $.extend(data, {
										  networkofferingid: args.data.networkofferingid
										});
                    if(args.context.networks[0].type == "Isolated") { //Isolated network
                      cloudStack.dialog.confirm({
                        message: 'Do you want to keep the current guest network CIDR unchanged?',
                        action: function() { //"Yes"	button is clicked                          
													$.extend(data, {
													  changecidr: false
													});
													
                          $.ajax({
                            url: createURL('updateNetwork'),
                            data: data,
                            success: function(json) {
                              var jid = json.updatenetworkresponse.jobid;
                              args.response.success(
                                {_custom:
                                 {jobId: jid,
                                  getUpdatedItem: function(json) {
                                    var item = json.queryasyncjobresultresponse.jobresult.network;
                                    return {data: item};
                                  }
                                 }
                                }
                              );
                            }
                          });
                        },
                        cancelAction: function() { //"Cancel" button is clicked                         
													$.extend(data, {
													  changecidr: true
													});
													
                          $.ajax({
                            url: createURL('updateNetwork'),
                            data: data,
                            success: function(json) {
                              var jid = json.updatenetworkresponse.jobid;
                              args.response.success(
                                {_custom:
                                 {jobId: jid,
                                  getUpdatedItem: function(json) {
                                    var item = json.queryasyncjobresultresponse.jobresult.network;
                                    return {data: item};
                                  }
                                 }
                                }
                              );
                            }
                          });
                        }
                      });
                      return;
                    }
                  }
                  $.ajax({
                    url: createURL('updateNetwork'),
                    data: data,
                    success: function(json) {
                      var jid = json.updatenetworkresponse.jobid;
                      args.response.success(
                        {_custom:
                         {jobId: jid,
                          getUpdatedItem: function(json) {
                            var item = json.queryasyncjobresultresponse.jobresult.network;
                            return {data: item};
                          }
                         }
                        }
                      );
                    }
                  });
                },
                notification: {
                  poll: pollAsyncJobResult
                }
              },
              'restart': {
                label: 'label.restart.network',
                createForm: {
                  title: 'label.restart.network',
                  desc: 'message.restart.network',
                  preFilter: function(args) {									  
										var zoneObj;
										$.ajax({
										  url: createURL("listZones&id=" + args.context.networks[0].zoneid),
											dataType: "json",
											async: false,
											success: function(json){											  
											  zoneObj = json.listzonesresponse.zone[0];												
											}
										});
                                        args.$form.find('.form-item[rel=cleanup]').find('input').attr('checked', 'checked'); //checked
                                        args.$form.find('.form-item[rel=cleanup]').css('display', 'inline-block'); //shown
									},
									fields: {
                    cleanup: {
                      label: 'label.clean.up',
                      isBoolean: true
                    }
                  }
                },
                messages: {
                  notification: function(args) {
                    return 'label.restart.network';
                  }
                },
                action: function(args) {
                  var array1 = [];
                  array1.push("&cleanup=" + (args.data.cleanup == "on"));
                  $.ajax({
                    url: createURL("restartNetwork&id=" + args.context.networks[0].id + array1.join("")),
                    dataType: "json",
                    async: true,
                    success: function(json) {
                      var jid = json.restartnetworkresponse.jobid;
                      args.response.success(
                        {_custom:
                         {jobId: jid,
                          getUpdatedItem: function(json) {
                            return json.queryasyncjobresultresponse.jobresult.network;
                          }
                         }
                        }
                      );
                    }
                  });
                },
                notification: {
                  poll: pollAsyncJobResult
                }
              },
              remove: {
                label: 'label.action.delete.network',
                messages: {
                  confirm: function(args) {
                    return 'message.action.delete.network';
                  },
                  notification: function(args) {
                    return 'label.action.delete.network';
                  }
                },
                action: function(args) {
                  $.ajax({
                    url: createURL("deleteNetwork&id=" + args.context.networks[0].id),
                    dataType: "json",
                    async: true,
                    success: function(json) {
                      var jid = json.deletenetworkresponse.jobid;
                      args.response.success(
                        {_custom:
                         {jobId: jid
                         }
                        }
                      );
                    }
                  });
                },
                notification: {
                  poll: pollAsyncJobResult
                }
              }
            },
            tabFilter: function(args) {
              var networkOfferingHavingELB = false;
              var hasNetworkACL = false;
              var hasSRXFirewall = false;
              var isVPC = false;
              var isAdvancedSGZone = false;
              var hiddenTabs = [];
              // Get network offering data
              $.ajax({
                url: createURL("listNetworkOfferings&id=" + args.context.networks[0].networkofferingid),
                dataType: "json",
                async: false,
                success: function(json) {
                  var networkoffering = json.listnetworkofferingsresponse.networkoffering[0];
                  if (networkoffering.forvpc) {
                    isVPC = true;
                  }
                  $(networkoffering.service).each(function(){
                    var thisService = this;
                    if (thisService.name == 'NetworkACL') {
                      hasNetworkACL = true;
                    } else if (thisService.name == "Lb") {
                      $(thisService.capability).each(function(){
                        if (this.name == "ElasticLb" && this.value == "true") {
                          networkOfferingHavingELB = true;
                        }
                      });
                    }
                    if (thisService.name == 'Firewall') {
                      $(thisService.provider).each(function() {
                        if (this.name == 'JuniperSRX') {
                          hasSRXFirewall = true;
                          return false;
                        }
                        return true;
                      });
                    }
                  });
                }
              });
              // Get zone data
              $.ajax({
                url: createURL('listZones'),
                data: {
                  id: args.context.networks[0].zoneid
                },
                async: false,
                success: function(json) {
                  var zone = json.listzonesresponse.zone[0];
                  isAdvancedSGZone = zone.securitygroupsenabled;
                }
              });
              if (!networkOfferingHavingELB) {
                hiddenTabs.push("addloadBalancer");
              }
              if (isVPC || isAdvancedSGZone || hasSRXFirewall) {
                hiddenTabs.push('egressRules');
               }
              
              return hiddenTabs;
            },
            isMaximized: true,
            tabs: {
              details: {
                title: 'label.details',
                preFilter: function(args) {
                  var hiddenFields = [];
                  var zone;
                  $.ajax({
                    url: createURL('listZones'),
                    data: {
                      id: args.context.networks[0].zoneid
                    },
                    async: false,
                    success: function(json) {
                      zone = json.listzonesresponse.zone[0];
                    }
                  });
                  if(zone.networktype == "Basic") {
                    hiddenFields.push("account");
                    hiddenFields.push("gateway");
                    hiddenFields.push("vlan");
                    hiddenFields.push("cidr");
                    //hiddenFields.push("netmask");
                  }
                  if(args.context.networks[0].type == "Isolated") {
                    hiddenFields.push("networkofferingdisplaytext");
                    hiddenFields.push("networkdomaintext");
                    hiddenFields.push("gateway");
                    hiddenFields.push("networkofferingname");
                    //hiddenFields.push("netmask");
                  }
                  else { //selectedGuestNetworkObj.type == "Shared"
                    hiddenFields.push("networkofferingid");
                    hiddenFields.push("networkdomain");
                  }
									
									if(!isAdmin()) {
									  hiddenFields.push("vlan");
									}
									
                  return hiddenFields;
                },						
																
                fields: [
                  {
                    name: {
                      label: 'label.name',
                      isEditable: true
                    }
                  },
                  {
                    id: { label: 'label.id' },
                    zonename: { label: 'label.zone' },
                    displaytext: {
                      label: 'label.description',
                      isEditable: true
                    },
                    type: {
                      label: 'label.type'
                    },
                    state: {
                      label: 'label.state'
                    },
                    ispersistent:{
                      label:'Persistent ',
                      converter:cloudStack.converters.toBooleanText
                     },
                    restartrequired: {
                      label: 'label.restart.required',
                      converter: function(booleanValue) {
                        if(booleanValue == true)
                          return "Yes";
                        else if(booleanValue == false)
                          return "No";
                      }
                    },
                    vlan: { label: 'label.vlan.id' },               
                    networkofferingid: {
                      label: 'label.network.offering',
                      isEditable: true,
                      select: function(args){
											  if (args.context.networks[0].type == 'Shared') { //Shared network is not allowed to upgrade to a different network offering
												  args.response.success({ data: [] });
                          return;
												}
											
                        if (args.context.networks[0].state == 'Destroyed') {
                          args.response.success({ data: [] });
                          return;
                        }
                        var items = [];
                        $.ajax({
                          url: createURL("listNetworkOfferings&networkid=" + args.context.networks[0].id),
                          dataType: "json",
                          async: false,
                          success: function(json) {
                            var networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering;
                            $(networkOfferingObjs).each(function() {
                              items.push({id: this.id, description: this.displaytext});
                            });
                          }
                        });
                        $.ajax({
                          url: createURL("listNetworkOfferings&id=" + args.context.networks[0].networkofferingid),  //include currently selected network offeirng to dropdown
                          dataType: "json",
                          async: false,
                          success: function(json) {
                            var networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering;
                            $(networkOfferingObjs).each(function() {
                              items.push({id: this.id, description: this.displaytext});
                            });
                          }
                        });
                        args.response.success({data: items});
                      }
                    },
                    gateway: { label: 'label.gateway' },
                    //netmask: { label: 'label.netmask' },
                    cidr: { label: 'label.cidr', isEditable:true },
                    networkcidr:{label:'Network CIDR'},
                    reservediprange:{label:'Reserved IP Range'},
                    networkdomaintext: {
                      label: 'label.network.domain.text'
                    },
                    networkdomain: {
                      label: 'label.network.domain',
                      isEditable: true
                    },
                    domain: { label: 'label.domain' },
                    account: { label: 'label.account' },
                    vpcid: {
                      label: 'label.vpc.id',
                      converter: function(args) {
                        if(args != null)
												  return args;
												else
												  return 'N/A';
                      }											
										}
                  }
                ],
                tags: cloudStack.api.tags({ resourceType: 'Network', contextId: 'networks' }),
                dataProvider: function(args) {
                  $.ajax({
                    url: createURL("listNetworks&id=" + args.context.networks[0].id + "&listAll=true"), //pass "&listAll=true" to "listNetworks&id=xxxxxxxx" for now before API gets fixed.
                    data: { listAll: true },
										dataType: "json",
										async: true,
										success: function(json) {								  
											var jsonObj = json.listnetworksresponse.network[0];  
                      addExtraPropertiesToGuestNetworkObject(jsonObj);												
											args.response.success(
												{
													actionFilter: cloudStack.actionFilter.guestNetwork,
													data: jsonObj
												}
											);		
										}
									});			
                }
              }
            }
          }
        }
      },
      secondaryNicIps: {
        title: 'label.menu.ipaddresses',
        listView: {
          id: 'secondaryNicIps',
          label: 'label.ips',
          fields: {
            virtualmachinedisplayname: { label: 'label.vm.name' },
            ipaddress: {
              label: 'label.ips',
              converter: function(text, item) {
                if (item.issourcenat) {
                  return text + ' [' + _l('label.source.nat') + ']';
                }
                return text;
              }
            }
          },
          actions: {
            add: {
              label: 'label.acquire.new.ip',
              addRow: 'true',
              messages: {
                confirm: function(args) {
                  return 'message.acquire.new.ip';
                },
                notification: function(args) {
                  return 'label.acquire.new.ip';
                }
              },
              action: function(args) {
                var dataObj = {};
                $.ajax({
                  url: createURL('addIpToNic'),
                  data: {
                    nicId: args.context.nics[0].id
                  },
                  success: function(json) {
                    args.response.success({
                      _custom: {
                        getUpdatedItem: function(data) {
                          return $.extend(
                            data.queryasyncjobresultresponse.jobresult.nicsecondaryip,
                            {
                              zoneid: args.context.instances[0].zoneid,
                              virtualmachinedisplayname: args.context.instances[0].displayname
                            }
                          );
                        },
                        jobId: json.addiptovmnicresponse.jobid
                      }
                    });
                  }
                });
              },
              notification: {
                poll: pollAsyncJobResult
              }
            }
          },
          dataProvider: function(args) {
            var data = {};
            $.ajax({
              url: createURL('listNics'),
              data: {
                nicId: args.context.nics[0].id,
                virtualmachineid: args.context.instances[0].id
              },
              success: function(json) {
                var ips = json.listnics.nic ? json.listnics.nic[0].secondaryip : [];
                args.response.success({
                  data: $(ips).map(function(index, ip) {
                    return $.extend(ip, {
                      zoneid: args.context.instances[0].zoneid,
                      virtualmachinedisplayname: args.context.instances[0].displayname
                    });
                  })
                });
              }
            });
          },
          // Detail view
          detailView: {
            name: 'Secondary IP address detail',
            actions: {
              remove: {
                label: 'label.action.release.ip',
                action: function(args) {
                  $.ajax({
                    url: createURL('removeIpFromNic'),
                    data: {
                      id: args.context.secondaryNicIps[0].id
                    },
                    success: function(json) {
                      args.response.success({
                        _custom: { jobId: json.removeipfromnicresponse.jobid }
                      });
                    }
                  });
                },
                messages: {
                  confirm: function(args) {
                    return 'message.action.release.ip';
                  },
                  notification: function(args) {
                    return 'label.action.release.ip';
                  }
                },
                notification: { poll: pollAsyncJobResult }
              }
            },
            tabs: {
              details: {
                title: 'label.details',
                fields: [
                  {
                    ipaddress: { label: 'label.ip' }
                  },
                  {
                    id: { label: 'label.id' },
                    virtualmachinedisplayname: { label: 'label.vm.name' },
                    zonename: { label: 'label.zone.name' }
                  }
                ],
                dataProvider: function(args) {
                  $.ajax({
                    url: createURL('listNics'),
                    data: {
                      nicId: args.context.nics[0].id,
                      virtualmachineid: args.context.instances[0].id
                    },
                    success: function(json) {
                      var ips = json.listnics.nic[0].secondaryip
                      args.response.success({
                        data: $.grep($(ips).map(function(index, ip) {
                          return $.extend(ip, {
                            zonename: args.context.instances[0].zonename,
                            virtualmachinedisplayname: args.context.instances[0].displayname
                          });
                        }), function(ip) {
                          return ip.ipaddress == args.context.secondaryNicIps[0].ipaddress;
                        })[0]
                      });
                    }
                  });
                }
              }
            }
          }
        }
      },
      ipAddresses: {
        type: 'select',
        title: 'label.menu.ipaddresses',
        listView: {
          id: 'ipAddresses',
          label: 'label.ips',
          fields: {
            ipaddress: {
              label: 'label.ips',
              converter: function(text, item) {
                if (item.issourcenat) {
                  return text + ' [' + _l('label.source.nat') + ']';
                }
                return text;
              }
            },
            zonename: { label: 'label.zone' },            
            virtualmachinedisplayname: { label: 'label.vm.name' },
            state: {
              converter: function(str) {
                // For localization
                return str;
              },
              label: 'label.state', indicator: { 'Allocated': 'on', 'Released': 'off' }
            }
          },
          actions: {
            add: {
              label: 'label.acquire.new.ip',
              addRow: 'true',
              preFilter: function(args) {                
								var zoneObj;
 								var dataObj = {};
                
                if ('vpc' in args.context) { //from VPC section
                  $.extend(dataObj, {
                    id: args.context.vpc[0].zoneid
                  });
                } else if ('networks' in args.context) { //from Guest Network section
                  $.extend(dataObj, {
                    id: args.context.networks[0].zoneid
                  });
                }
								$.ajax({
								  url: createURL('listZones'),
									data: dataObj,
								  //	  id: args.context.networks[0].zoneid
								  //	},
									async: false,
									success: function(json) {									  
										zoneObj = json.listzonesresponse.zone[0];										
									}
								});
                if (zoneObj.networktype == 'Advanced' && zoneObj.securitygroupsenabled) {
                  return false;
                }
																							
								if (zoneObj.networktype == 'Basic') {
								  var havingEIP = false, havingELB = false;
								  $.ajax({
									  url: createURL('listNetworkOfferings'),
										data: {
										  id: args.context.networks[0].networkofferingid
										},
										async: false,
										success: function(json) {									  
											$(json.listnetworkofferingsresponse.networkoffering[0].service).each(function(){											 
												var thisService = this;														
												if (thisService.name == "StaticNat") {
													$(thisService.capability).each(function(){
														if (this.name == "ElasticIp" && this.value == "true") {
															havingEIP = true;
															return false; //break $.each() loop
														}
													});
												} else if (thisService.name == "Lb") {
													$(thisService.capability).each(function(){
														if (this.name == "ElasticLb" && this.value == "true") {
															havingELB = true;
															return false; //break $.each() loop
														}
													});
												}
											});			
										}
									});									                	               
									if(havingEIP != true || havingELB != true) { //not EIP-ELB 
										return false;  //acquire new IP is not allowed in non-EIP-ELB basic zone 
									}			
								}
																
								//*** from Guest Network section ***
								if('networks' in args.context) { 
                  if(args.context.networks[0].vpcid == null){ //Guest Network section > non-VPC network, show Acquire IP button
                    return true;
                  } 
									else { //Guest Network section > VPC network, hide Acquire IP button
                    return false;
                  }
                } 								
								//*** from VPC section ***
								else { //'vpc' in args.context
                  return true; //VPC section, show Acquire IP button
                }
              },
              messages: {
                confirm: function(args) {
                  if(args.context.vpc)
                    return 'message.acquire.new.ip.vpc';
                   else
                     return 'message.acquire.new.ip';
                },
                notification: function(args) {
                  return 'label.acquire.new.ip';
                }
              },	
              action: function(args) {                
								var dataObj = {};											
								if('vpc' in args.context) { //from VPC section
								  $.extend(dataObj, {
									  vpcid: args.context.vpc[0].id
									});
								}
								else if('networks' in args.context) { //from Guest Network section
								  $.extend(dataObj, {
									  networkid: args.context.networks[0].id
									});									
									
									if(args.context.networks[0].type == "Shared" && !args.context.projects) {
										$.extend(dataObj, {
											domainid: g_domainid,
											account: g_account
										});
									}									
								}
                $.ajax({
                  url: createURL('associateIpAddress'),
                  data: dataObj,
                  success: function(data) {
                    args.response.success({
                      _custom: {
                        jobId: data.associateipaddressresponse.jobid,
                        getUpdatedItem: function(data) {
                          var newIP = data.queryasyncjobresultresponse.jobresult.ipaddress;
                          return $.extend(newIP, {
                            state: 'Allocated'
                          });
                        },
                        getActionFilter: function() {
                          return actionFilters.ipAddress;
                        }
                      }
                    });
                  },
                  error: function(json) {
                    args.response.error(parseXMLHttpResponse(json));
                  }
                });
              },
              notification: {
                poll: pollAsyncJobResult
              }
            }
          },
          dataProvider: function(args) {
            var data = {};
						listViewDataProvider(args, data);
            if (g_supportELB == "guest") // IPs are allocated on guest network
              $.extend(data, {
                forvirtualnetwork: false,
                forloadbalancing: true
              });
            else if(g_supportELB == "public") // IPs are allocated on public network
              $.extend(data, {
                forvirtualnetwork: true,
                forloadbalancing: true
              });
            if (args.context.networks) {
              $.extend(data, { associatedNetworkId: args.context.networks[0].id });
            }						
            
            if("vpc" in args.context) {
              $.extend(data, {
                vpcid: args.context.vpc[0].id
              });
            }
            $.ajax({
              url: createURL('listPublicIpAddresses'),
              data: data,
              dataType: "json",
              async: true,
              success: function(json) {
                var items = json.listpublicipaddressesresponse.publicipaddress;
                $(items).each(function() {
                  getExtaPropertiesForIpObj(this, args);
                });
                args.response.success({
                  actionFilter: actionFilters.ipAddress,
                  data: items
                });
              },
              error: function(data) {
                args.response.error(parseXMLHttpResponse(data));
              }
            });
          },
          // Detail view
          detailView: {
            name: 'IP address detail',
            tabFilter: function(args) {
              var item = args.context.ipAddresses[0];
              // Get VPN data
              $.ajax({
                url: createURL('listRemoteAccessVpns'),
                data: {
                  listAll: true,
                  publicipid: item.id
                },
                dataType: 'json',
                async: false,
                success: function(vpnResponse) {
                  var isVPNEnabled = vpnResponse.listremoteaccessvpnsresponse.count;
                  if (isVPNEnabled) {
                    item.vpnenabled = true;
                    item.remoteaccessvpn = vpnResponse.listremoteaccessvpnsresponse.remoteaccessvpn[0];
                  };
                },
                error: function(data) {
                  args.response.error(parseXMLHttpResponse(data));
                }
              });
              var disabledTabs = [];
              var ipAddress = args.context.ipAddresses[0];
              var disableVpn = false, disableIpRules = false;
              if (!ipAddress.vpnenabled) {
                disableVpn = true;
              }
              
              if (ipAddress.issystem == true) {
                disableVpn = true;
                
                if (ipAddress.isstaticnat == true || ipAddress.virtualmachineid != null) {
                  disableIpRules = true;
                }
              }
              if (ipAddress.vpcid && ipAddress.issourcenat) {
                disableIpRules = true;
              }
              if (disableVpn) disabledTabs.push('vpn');
              if (disableIpRules) disabledTabs.push('ipRules');
              
              return disabledTabs;
            },
            actions: {
              enableVPN: {
                label: 'label.enable.vpn',
                action: function(args) {
                  $.ajax({
                    url: createURL('createRemoteAccessVpn'),
                    data: {
                      publicipid: args.context.ipAddresses[0].id,
                      domainid: args.context.ipAddresses[0].domainid,
                      account: args.context.ipAddresses[0].account
                    },
                    dataType: 'json',
                    async: true,
                    success: function(data) {
                      args.response.success({
                        _custom: {
                          getUpdatedItem: function(json) {
                            return {
                              vpn: json.queryasyncjobresultresponse.jobresult.remoteaccessvpn,
                              vpnenabled: true
                            };
                          },
                          getActionFilter: function() {
                            return actionFilters.ipAddress;
                          },
                          jobId: data.createremoteaccessvpnresponse.jobid
                        }
                      });
                    },
                    error: function(data) {
                      args.response.error(parseXMLHttpResponse(data));
                    }
                  });
                },
                messages: {
                  confirm: function(args) {
                    return 'message.enable.vpn';
                  },
                  notification: function(args) {
                    return 'label.enable.vpn';
                  },
                  complete: function(args) {
                    return _l('message.enabled.vpn') + ' ' + args.vpn.publicip + '.' + '
'
                      + _l('message.enabled.vpn.ip.sec') + '
'
                      + args.vpn.presharedkey;
                  }
                },
                notification: {
                  poll: pollAsyncJobResult
                }
              },
              disableVPN: {
                label: 'label.disable.vpn',
                action: function(args) {
                  $.ajax({
                    url: createURL('deleteRemoteAccessVpn'),
                    data: {
                      publicipid: args.context.ipAddresses[0].id,
                      domainid: args.context.ipAddresses[0].domainid
                    },
                    dataType: 'json',
                    async: true,
                    success: function(data) {
                      args.response.success({
                        _custom: {
                          getUpdatedItem: function(data) {
                            return {
                              vpnenabled: false
                            };
                          },
                          getActionFilter: function() { return actionFilters.ipAddress; },
                          jobId: data.deleteremoteaccessvpnresponse.jobid
                        }
                      });
                    },
                    error: function(data) {
                      args.response.error(parseXMLHttpResponse(data));
                    }
                  });
                },
                messages: {
                  confirm: function(args) {
                    return 'message.disable.vpn';
                  },
                  notification: function(args) {
                    return 'label.disable.vpn';
                  }
                },
                notification: {
                  poll: pollAsyncJobResult
                }
              },
              enableStaticNAT: {
                label: 'label.action.enable.static.NAT',
                action: {
                  noAdd: true,
                  custom: cloudStack.uiCustom.enableStaticNAT({
                    tierSelect: function(args) {
                      if ('vpc' in args.context) { //from VPC section
                        args.$tierSelect.show(); //show tier dropdown
                        $.ajax({ //populate tier dropdown
                          url: createURL("listNetworks"),
                          async: false,
                          data: {
                            vpcid: args.context.vpc[0].id,
                            //listAll: true,  //do not pass listAll to listNetworks under VPC
														domainid: args.context.vpc[0].domainid,
						                account: args.context.vpc[0].account,
                            supportedservices: 'StaticNat'
                          },
                          success: function(json) {
                            var networks = json.listnetworksresponse.network;
                            var items = [{ id: -1, description: 'Please select a tier' }];
                            $(networks).each(function(){
                              items.push({id: this.id, description: this.displaytext});
                            });
                            args.response.success({ data: items });
                          }
                        });
                      }
                      else { //from Guest Network section
                        args.$tierSelect.hide();
                      }
                      args.$tierSelect.change(function() {
                        args.$tierSelect.closest('.list-view').listView('refresh');
                      });
                      args.$tierSelect.closest('.list-view').listView('refresh');
                    },
                    listView: $.extend(true, {}, cloudStack.sections.instances, {
                      listView: {
                        filters: false,
                        subselect: {
                          label: 'label.use.vm.ip',
                          dataProvider: instanceSecondaryIPSubselect
                        },
                        dataProvider: function(args) {
                          var data = {
                            page: args.page,
                            pageSize: pageSize,                            
                            listAll: true
                          };
                          
                          var $tierSelect = $(".ui-dialog-content").find('.tier-select select');
                          
                          // if $tierSelect is not initialized, return; tierSelect() will refresh listView and come back here later 
                          if($tierSelect.size() == 0){
                            args.response.success({ data: null });
                            return;             
                          }
                          if('vpc' in args.context) {
                            if($tierSelect.size() && $tierSelect.val() != '-1' ){ 
                              data.networkid = $tierSelect.val();
                            }                          
                            $.extend(data, {
                              vpcid: args.context.vpc[0].id
                            });
                          }
                          else if('networks' in args.context) {
                            $.extend(data, {
                              networkid: args.context.networks[0].id
                            });
                          }
													
                          if (!args.context.projects) {
                            $.extend(data, {
                              account: args.context.ipAddresses[0].account,
                              domainid: args.context.ipAddresses[0].domainid
                            });
                          }
                          $.ajax({
                            url: createURL('listVirtualMachines'),
                            data: data,
                            dataType: 'json',
                            async: true,
                            success: function(data) {
                              args.response.success({
                                data: $.grep(
                                  data.listvirtualmachinesresponse.virtualmachine ?
                                    data.listvirtualmachinesresponse.virtualmachine : [],
                                  function(instance) {
                                    return $.inArray(instance.state, [
                                      'Destroyed','Expunging'
                                    ]) == -1;
                                  }
                                )
                              });
                            },
                            error: function(data) {
                              args.response.error(parseXMLHttpResponse(data));
                            }
                          });
                        }
                      }
                    }),
                    action: function(args) {										  
											var data = {
												ipaddressid: args.context.ipAddresses[0].id,
												virtualmachineid: args.context.instances[0].id
											};
                      if (args._subselect && args._subselect != -1) {
                        data.vmguestip = args._subselect;
                      }
											
											if('vpc' in args.context) {
											  if(args.tierID == '-1') {
												  args.response.error('Tier is required');
												  return;
												}											
											  $.extend(data, {
												  networkid: args.tierID
												});
											}
										
                      $.ajax({
                        url: createURL('enableStaticNat'),
                        data: data,
                        dataType: 'json',
                        async: true,
                        success: function(data) {
                          args.response.success({});
                        },
                        error: function(data) {
                          args.response.error(parseXMLHttpResponse(data));
                        }
                      });
                    }
                  })
                },
                messages: {
                  notification: function(args) {
                    return 'label.action.enable.static.NAT';
                  }
                },
                notification: {
                  poll: function(args) {
                    args.complete({
                      data: {
                        isstaticnat: true
                      }
                    });
                    if (args._custom.$detailView.is(':visible')) {
                      ipChangeNotice();
                    }
                  }
                }
              },
              disableStaticNAT: {
                label: 'label.action.disable.static.NAT',
                action: function(args) {
                  $.ajax({
                    url: createURL('disableStaticNat'),
                    data: {
                      ipaddressid: args.context.ipAddresses[0].id
                    },
                    dataType: 'json',
                    async: true,
                    success: function(data) {
                      args.response.success({
                        _custom: {
                          jobId: data.disablestaticnatresponse.jobid,
                          getUpdatedItem: function() {
                            return {
                              isstaticnat: false,
                              virtualmachinedisplayname: ""
                            };
                          },
                          getActionFilter: function() {
                            return function(args) {
                              return ['enableStaticNAT'];
                            };
                          },
                          onComplete: function(args, _custom) {
                            if (_custom.$detailView.is(':visible')) {
                              ipChangeNotice();
                            }
                          }
                        }
                      });
                    },
                    error: function(data) {
                      args.response.error(parseXMLHttpResponse(data));
                    }
                  });
                },
                messages: {
                  confirm: function(args) {
                    return 'message.action.disable.static.NAT';
                  },
                  notification: function(args) {
                    return 'label.action.disable.static.NAT';
                  }
                },
                notification: {
                  poll: pollAsyncJobResult
                }
              },
              remove: {
                label: 'label.action.release.ip',
                action: function(args) {
                  $.ajax({
                    url: createURL('disassociateIpAddress'),
                    data: {
                      id: args.context.ipAddresses[0].id
                    },
                    dataType: 'json',
                    async: true,
                    success: function(data) {
                      args.response.success({
                        _custom: {
                          jobId: data.disassociateipaddressresponse.jobid,
                          getActionFilter: function() {
                            return function(args) {
                              var allowedActions = ['enableStaticNAT'];
                              return allowedActions;
                            };
                          },
                          getUpdatedItem: function(args) {
                            return {
                              state: 'Released'
                            };
                          },
                          onComplete: function() {
                            $(window).trigger('cloudStack.fullRefresh');
                          }
                        }
                      });
                    },
                    error: function(data) {
                      args.response.error(parseXMLHttpResponse(data));
                    }
                  });
                },
                messages: {
                  confirm: function(args) {
                    return 'message.action.release.ip';
                  },
                  notification: function(args) {
                    return 'label.action.release.ip';
                  }
                },
                notification: { poll: pollAsyncJobResult }
              }
            },
            tabs: {
              details: {
                title: 'label.details',
                preFilter: function(args) {
                  var hiddenFields = [];
                  var zoneObj;
                  $.ajax({
                    url: createURL("listZones&id=" + args.context.ipAddresses[0].zoneid),
                    dataType: "json",
                    async: false,
                    success: function(json) {
                      zoneObj = json.listzonesresponse.zone[0];
                    }
                  });
                  if(zoneObj.networktype == "Advanced") {
                    hiddenFields.push("issystem");
                    hiddenFields.push("purpose");
                  }
									
									if(!isAdmin()) {                   
                    hiddenFields.push("vlanname");
                  }									
                  return hiddenFields;
                },
                fields: [
                  {
                    ipaddress: { label: 'label.ip' }
                  },
                  {
                    id: { label: 'label.id' },    
                    associatednetworkid: { label: 'label.associated.network.id' },
										networkname: { label: 'label.associated.network' },
                    state: { label: 'label.state' },
										networkid: { label: 'label.network.id' },
                    issourcenat: { label: 'label.source.nat', converter: cloudStack.converters.toBooleanText },
                    isstaticnat: { label: 'label.static.nat', converter: cloudStack.converters.toBooleanText },
                    issystem: { label: 'label.is.system', converter: cloudStack.converters.toBooleanText }, //(basic zone only)
                    purpose: { label: 'label.purpose' }, //(basic zone only) When an IP is system-generated, the purpose it serves can be Lb or static nat.
                    virtualmachinedisplayname: { label: 'label.vm.name' },
                    domain: { label: 'label.domain' },
                    account: { label: 'label.account' },
                    zonename: { label: 'label.zone' },
                    vlanname: { label: 'label.vlan' }
                  }
                ],
                tags: cloudStack.api.tags({ resourceType: 'PublicIpAddress', contextId: 'ipAddresses' }),
                dataProvider: function(args) {
                  var items = args.context.ipAddresses;
                  $.ajax({
                    url: createURL('listPublicIpAddresses'),
                    data: {
                      id: args.context.ipAddresses[0].id
                    },
                    dataType: "json",
                    async: true,
                    success: function(json) {
                      var ipObj = json.listpublicipaddressesresponse.publicipaddress[0];
                      getExtaPropertiesForIpObj(ipObj, args);
                      var network = $.grep(
                        args.context.vpc ?
                          args.context.vpc[0].network : args.context.networks,
                        function(network) {
                          return network.id = ipObj.associatednetworkid;
                        })[0];
                      args.response.success({
                        actionFilter: actionFilters.ipAddress,
                        data: $.extend(ipObj, {
                          networkname: network ? network.name : ''
                        })
                      });
                    },
                    error: function(data) {
                      args.response.error(parseXMLHttpResponse(data));
                    }
                  });
                }
              },
              ipRules: { //Configuration tab
                title: 'label.configuration',
                custom: cloudStack.ipRules({
                  preFilter: function(args) {							
                    var disallowedActions = [];
                    if (args.context.ipAddresses[0].isstaticnat)
                      disallowedActions.push("nonStaticNATChart");  //tell ipRules widget to show staticNAT chart instead of non-staticNAT chart.
                    var havingFirewallService = false;
                    var havingPortForwardingService = false;
                    var havingLbService = false;
										var havingVpnService = false;		
										
                    if('networks' in args.context && args.context.networks[0].vpcid == null) { //a non-VPC network from Guest Network section
                      $.ajax({
                        url: createURL('listNetworkOfferings'),
                        data: {
												  listAll: true,
													id: args.context.networks[0].networkofferingid
												},
                        async: false,
                        success: function(json) {
                          var networkoffering = json.listnetworkofferingsresponse.networkoffering[0];
                          $(networkoffering.service).each(function(){
                            var thisService = this;
                            if(thisService.name == "Firewall")
                              havingFirewallService = true;
                            if(thisService.name == "PortForwarding")
                              havingPortForwardingService = true;
                            if(thisService.name == "Lb")
                              havingLbService = true;
                            if(thisService.name == "Vpn")
                              havingVpnService = true;
                          });
                        }
                      });
                    }
                    else { //a VPC network from Guest Network section or from VPC section
                      // Firewall is not supported in IP from VPC section
                      // (because ACL has already supported in tier from VPC section)
                      havingFirewallService = false;
                      disallowedActions.push("firewall");
                      havingVpnService = false; //VPN is not supported in IP from VPC section
                      if(args.context.ipAddresses[0].associatednetworkid == null) { //IP is not associated with any tier yet
                        havingPortForwardingService = true;
                        havingLbService = true;
                      }
                      else { //IP is associated with a tier
                        $.ajax({
                          url: createURL('listNetworks'),
													data: {
													  listAll: true,
														id: args.context.ipAddresses[0].associatednetworkid
													},
                          async: false,
                          success: function(json) {
                            var networkObj = json.listnetworksresponse.network[0];
                            $.ajax({
                              url: createURL("listNetworkOfferings&id=" + networkObj.networkofferingid),
                              async: false,
                              success: function(json) {
                                var networkoffering = json.listnetworkofferingsresponse.networkoffering[0];
                                $(networkoffering.service).each(function(){
                                  var thisService = this;
                                  if(thisService.name == "PortForwarding")
                                    havingPortForwardingService = true;
                                  if(thisService.name == "Lb")
                                    havingLbService = true;
                                });
                              }
                            });
                          }
                        });
                      }
                    }
                    if(args.context.ipAddresses[0].networkOfferingConserveMode == false) {
                      /*
                       (1) If IP is SourceNat, no StaticNat/VPN/PortForwarding/LoadBalancer can be enabled/added.
                       */
                      if (args.context.ipAddresses[0].issourcenat){
                        if(havingFirewallService == false) { //firewall is not supported in IP from VPC section (because ACL has already supported in tier from VPC section)
                          disallowedActions.push("firewall");
                        }
                        disallowedActions.push("portForwarding");
                        disallowedActions.push("loadBalancing");
                      }
                      /*
                       (2) If IP is non-SourceNat, show StaticNat/VPN/PortForwarding/LoadBalancer at first.
                       1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer.
                       2. If VPN service is supported (i.e. IP comes from Guest Network section, not from VPC section), once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer.
                       3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer.
                       4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding.
                       */
                      else { //args.context.ipAddresses[0].issourcenat == false
                        if(havingFirewallService == false)
                          disallowedActions.push("firewall");
                        if(havingPortForwardingService == false)
                          disallowedActions.push("portForwarding");
                        if(havingLbService == false)
                          disallowedActions.push("loadBalancing");
                        if (args.context.ipAddresses[0].isstaticnat) { //1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer.
                          disallowedActions.push("portForwarding");
                          disallowedActions.push("loadBalancing");
                        }
                        if (havingVpnService && args.context.ipAddresses[0].vpnenabled) { //2. If VPN service is supported (i.e. IP comes from Guest Network section, not from VPC section), once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer.
                          disallowedActions.push("portForwarding");
                          disallowedActions.push("loadBalancing");
                        }
                        //3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer.
                        $.ajax({
                          url: createURL('listPortForwardingRules'),
                          data: {
                            ipaddressid: args.context.ipAddresses[0].id,
                            listAll: true
                          },
                          dataType: 'json',
                          async: false,
                          success: function(json) {
                            // Get instance
                            var rules = json.listportforwardingrulesresponse.portforwardingrule;
                            if(rules != null && rules.length > 0) {
                              disallowedActions.push("loadBalancing");
                            }
                          }
                        });
                        //4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding.
                        $.ajax({
                          url: createURL('listLoadBalancerRules'),
                          data: {
                            publicipid: args.context.ipAddresses[0].id,
                            listAll: true
                          },
                          dataType: 'json',
                          async: false,
                          success: function(json) {
                            var rules = json.listloadbalancerrulesresponse.loadbalancerrule;
                            if(rules != null && rules.length > 0) {
                              disallowedActions.push("portForwarding");
                            }
                          }
                        });
                      }
                    }
                    return disallowedActions;
                  },
                  // Firewall rules
                  firewall: {
                    noSelect: true,
                    fields: {
                      'cidrlist': { edit: true, label: 'label.cidr.list' },
                      'protocol': {
                        label: 'label.protocol',
                        select: function(args) {
                          args.$select.change(function() {
                            var $inputs = args.$form.find('input');
                            var $icmpFields = $inputs.filter(function() {
                              var name = $(this).attr('name');
                              return $.inArray(name, [
                                'icmptype',
                                'icmpcode'
                              ]) > -1;
                            });
                            var $otherFields = $inputs.filter(function() {
                              var name = $(this).attr('name');
                              return name != 'icmptype' && name != 'icmpcode' && name != 'cidrlist';
                            });
                            if ($(this).val() == 'icmp') {
                              $icmpFields.show();
                              $icmpFields.attr('disabled', false);
                              $otherFields.attr('disabled', 'disabled');
                              $otherFields.hide();
                              $otherFields.parent().find('label.error').hide();
                            } else {
                              $otherFields.show();
                              $otherFields.parent().find('label.error').hide();
                              $otherFields.attr('disabled', false);
                              $icmpFields.attr('disabled', 'disabled');
                              $icmpFields.hide();
                              $icmpFields.parent().find('label.error').hide();
                            }
                          });
                          args.response.success({
                            data: [
                              { name: 'tcp', description: 'TCP' },
                              { name: 'udp', description: 'UDP' },
                              { name: 'icmp', description: 'ICMP' }
                            ]
                          });
                        }
                      },
                      'startport': { edit: true, label: 'label.start.port',isOptional: true },
                      'endport': { edit: true, label: 'label.end.port',isOptional: true },
                      'icmptype': { edit: true, label: 'ICMP.type', isDisabled: true },
                      'icmpcode': { edit: true, label: 'ICMP.code', isDisabled: true },
                      'add-rule': {
                        label: 'label.add.rule',
                        addButton: true
                      }
                    },
                    tags: cloudStack.api.tags({ resourceType: 'FirewallRule', contextId: 'multiRule' }),
                    add: {
                      label: 'label.add',
                      action: function(args) {
                        $.ajax({
                          url: createURL('createFirewallRule'),
                          data: $.extend(args.data, {
                            ipaddressid: args.context.ipAddresses[0].id
                          }),
                          dataType: 'json',
                          success: function(data) {
                            args.response.success({
                              _custom: {
                                jobId: data.createfirewallruleresponse.jobid
                              },
                              notification: {
                                label: 'label.add.firewall',
                                poll: pollAsyncJobResult
                              }
                            });
                          },
                          error: function(data) {
                            args.response.error(parseXMLHttpResponse(data));
                          }
                        });
                      }
                    },
                    actions: {
                      destroy: {
                        label: 'label.action.delete.firewall',
                        action: function(args) {
                          $.ajax({
                            url: createURL('deleteFirewallRule'),
                            data: {
                              id: args.context.multiRule[0].id
                            },
                            dataType: 'json',
                            async: true,
                            success: function(data) {
                              var jobID = data.deletefirewallruleresponse.jobid;
                              args.response.success({
                                _custom: {
                                  jobId: jobID
                                },
                                notification: {
                                  label: 'label.action.delete.firewall',
                                  poll: pollAsyncJobResult
                                }
                              });
                            },
                            error: function(data) {
                              args.response.error(parseXMLHttpResponse(data));
                            }
                          });
                        }
                      }
                    },
                    dataProvider: function(args) {
                      $.ajax({
                        url: createURL('listFirewallRules'),
                        data: {
                          listAll: true,
                          ipaddressid: args.context.ipAddresses[0].id
                        },
                        dataType: 'json',
                        async: true,
                        success: function(data) {
                          args.response.success({
                            data: data.listfirewallrulesresponse.firewallrule
                          });
                        },
                        error: function(data) {
                          args.response.error(parseXMLHttpResponse(data));
                        }
                      });
                    }
                  },
                  staticNATDataProvider: function(args) {
                    $.ajax({
                      url: createURL('listPublicIpAddresses'),
                      data: {
                        id: args.context.ipAddresses[0].id,
												listAll: true
                      },
                      dataType: 'json',
                      async: true,
                      success: function(data) {											
                        var ipObj = data.listpublicipaddressesresponse.publicipaddress[0];
                        getExtaPropertiesForIpObj(ipObj, args);
												
                        args.response.success({
                          data: ipObj
                        });
                      },
                      error: function(data) {
                        args.response.error(parseXMLHttpResponse(data));
                      }
                    });
                  },
                  vmDataProvider: function(args) {
                    $.ajax({
                      url: createURL('listVirtualMachines'),
                      data: {
                        id: args.context.ipAddresses[0].virtualmachineid,
                        listAll: true
                      },
                      dataType: 'json',
                      async: true,
                      success: function(data) {
                        args.response.success({
                          data: data.listvirtualmachinesresponse.virtualmachine[0]
                        });
                      },
                      error: function(data) {
                        args.response.error(parseXMLHttpResponse(data));
                      }
                    });
                  },
                  vmDetails: cloudStack.sections.instances.listView.detailView,
                  //"NAT Port Range" multiEdit screen for StaticNAT is obsolete in cloudstack 3.0 because createIpForwardingRule/deleteIpForwardingRule/listIpForwardingRules API are obsolete in cloudstack 3.0.
                  //cloudstack 3.0 is using createFirewallRule/listFirewallRules/deleteFirewallRule API for both staticNAT and non-staticNAT .
                  /*
                   staticNAT: {
                   noSelect: true,
                   fields: {
                   'protocol': {
                   label: 'label.protocol',
                   select: function(args) {
                   args.response.success({
                   data: [
                   { name: 'tcp', description: 'TCP' },
                   { name: 'udp', description: 'UDP' }
                   ]
                   });
                   }
                   },
                   'startport': { edit: true, label: 'label.start.port' },
                   'endport': { edit: true, label: 'label.end.port' },
                   'add-rule': {
                   label: 'label.add.rule',
                   addButton: true
                   }
                   },
                   add: {
                   label: 'label.add',
                   action: function(args) {
                   $.ajax({
                   url: createURL('createIpForwardingRule'),
                   data: $.extend(args.data, {
                   ipaddressid: args.context.ipAddresses[0].id
                   }),
                   dataType: 'json',
                   success: function(data) {
                   args.response.success({
                   _custom: {
                   jobId: data.createipforwardingruleresponse.jobid
                   },
                   notification: {
                   label: 'label.add.static.nat.rule',
                   poll: pollAsyncJobResult
                   }
                   });
                   },
                   error: function(data) {
                   args.response.error(parseXMLHttpResponse(data));
                   }
                   });
                   }
                   },
                   actions: {
                   destroy: {
                   label: 'label.remove.rule',
                   action: function(args) {
                   $.ajax({
                   url: createURL('deleteIpForwardingRule'),
                   data: {
                   id: args.context.multiRule[0].id
                   },
                   dataType: 'json',
                   async: true,
                   success: function(data) {
                   var jobID = data.deleteipforwardingruleresponse.jobid;
                   args.response.success({
                   _custom: {
                   jobId: jobID
                   },
                   notification: {
                   label: 'label.remove.static.nat.rule',
                   poll: pollAsyncJobResult
                   }
                   });
                   },
                   error: function(data) {
                   args.response.error(parseXMLHttpResponse(data));
                   }
                   });
                   }
                   }
                   },
                   dataProvider: function(args) {
                   setTimeout(function() {
                   $.ajax({
                   url: createURL('listIpForwardingRules'),
                   data: {
                   listAll: true,
                   ipaddressid: args.context.ipAddresses[0].id
                   },
                   dataType: 'json',
                   async: true,
                   success: function(data) {
                   args.response.success({
                   data: data.listipforwardingrulesresponse.ipforwardingrule
                   });
                   },
                   error: function(data) {
                   args.response.error(parseXMLHttpResponse(data));
                   }
                   });
                   }, 100);
                   }
                   },
                   */
                  // Load balancing rules
                  loadBalancing: {
                    listView: $.extend(true, {}, cloudStack.sections.instances, {
                      listView: {
                        fields: {
                          name: { label: 'label.name' },
                          displayname: { label: 'label.display.name' },
                          zonename: { label: 'label.zone.name' },
                          state: {
                            label: 'label.state',
                            indicator: {
                              'Running': 'on',
                              'Stopped': 'off',
                              'Destroyed': 'off',
                              'Error': 'off'
                            }
                          }
                        },
                        filters: false,
                        dataProvider: function(args) {
                          var itemData = $.isArray(args.context.multiRule) && args.context.multiRule[0]['_itemData'] ?
                            args.context.multiRule[0]['_itemData'] : [];
																											                    
													var networkid;
													if('vpc' in args.context) 
													  networkid = args.context.multiData.tier;													
													else 
													  networkid = args.context.ipAddresses[0].associatednetworkid;			
													
                          var data = {
                            page: args.page,
                            pageSize: pageSize,
                            networkid: networkid,
                            listAll: true
                          };
                          if (!args.context.projects) {
                            $.extend(data, {
                              account: args.context.ipAddresses[0].account,
                              domainid: args.context.ipAddresses[0].domainid
                            });
                          }
                          $.ajax({
                            url: createURL('listVirtualMachines'),
                            data: data,
                            dataType: 'json',
                            async: true,
                            success: function(data) {
                              var vmData = $.grep(
                                data.listvirtualmachinesresponse.virtualmachine ?
                                  data.listvirtualmachinesresponse.virtualmachine : [],
                                function(instance) {
                                 //Hiding the autoScale VMs
                                 var nonAutoScale =0;
                                 if(instance.displayname == null)
                                    nonAutoScale = 1
                                 else {
                                 if(instance.displayname.match(/AutoScale-LB-/) == null)
                                       nonAutoScale = 1;
                                 else {
                                     if( instance.displayname.match(/AutoScale-LB-/).length)          
                                        nonAutoScale =0;
                                   }   
                                  }         
                                  var isActiveState = $.inArray(instance.state, ['Destroyed','Expunging']) == -1;
                                  var notExisting = !$.grep(itemData, function(item) {
                                    return item.id == instance.id;
                                  }).length;
                                  return nonAutoScale && isActiveState && notExisting;
                                }
                              );
                              args.response.success({
                                data: vmData
                              });
                            },
                            error: function(data) {
                              args.response.error(parseXMLHttpResponse(data));
                            }
                          });
                        }
                      }
                    }),
                    headerFields: {
                      tier: {
                        label: 'label.tier',
                        select: function(args) {
                          if('vpc' in args.context) {
                            var data = {
														  //listAll: true,  //do not pass listAll to listNetworks under VPC
															supportedservices: 'Lb'
														};
														if(args.context.ipAddresses[0].associatednetworkid == null) {
														  $.extend(data, {
															  vpcid: args.context.vpc[0].id,
																domainid: args.context.vpc[0].domainid,
						                    account: args.context.vpc[0].account
															});
														}
														else {
														  $.extend(data, {
															  id: args.context.ipAddresses[0].associatednetworkid
															});
														}			
													
														$.ajax({
															url: createURL("listNetworks"),															
															data: data,															
															success: function(json) {					  
																var networks = json.listnetworksresponse.network;	
																var items = [];
																$(networks).each(function(){																  
																	items.push({id: this.id, description: this.displaytext});
																});
																args.response.success({ data: items });																
															}
														});	 
													}																								
                        }
                      }
                    },
                    multipleAdd: true,
                    fieldPreFilter: function(args) {                        
											var hiddenFields = [];		
											if('vpc' in args.context) { //from VPC section
											  hiddenFields.push('autoScale'); //autoScale is not supported in VPC
											}		
                      else { //from Guest Network section 											  
                        $.ajax({
												  url: createURL('listNetworkOfferings'),
													data: {
													  id: args.context.networks[0].networkofferingid
													},
													async: false,
													success: function(json) {													  
														var serviceArray = json.listnetworkofferingsresponse.networkoffering[0].service;
														var lbProviderArrayIncludesNetscaler = false;
														for(var i = 0; i < serviceArray.length; i++) {
														  if(serviceArray[i].name == "Lb") {
															  var providerArray = serviceArray[i].provider;
																for(var k = 0; k < providerArray.length; k++) {
																  if(providerArray[k].name == "Netscaler") {
																	  lbProviderArrayIncludesNetscaler = true;
																		break;
																	}
																}																					
															  break;
															}															
														}														
														if(lbProviderArrayIncludesNetscaler == false) {
														  hiddenFields.push('autoScale'); //autoScale is not supported in a network that is not using Netscaler provider for LB service (CS-16459)
														}		
													}
												});											  
                      }											
                      return hiddenFields; // Returns fields to be hidden
                    },
                    fields: {
                      'name': { edit: true, label: 'label.name', isEditable: true },
                      'publicport': { edit: true, label: 'label.public.port' },
                      'privateport': { edit: true, label: 'label.private.port' },
                      'algorithm': {
                        label: 'label.algorithm',
                        isEditable: true,
                        select: function(args) {
                          args.response.success({
                            data: [
                              { id: 'roundrobin', name: 'roundrobin', description: _l('label.round.robin') },
                              { id: 'leastconn', name: 'leastconn', description: _l('label.least.connections') },
                              { id: 'source', name: 'source', description: _l('label.source') }
                            ]
                          });
                        }
                      },
                      'sticky': {
                        label: 'label.stickiness',
                        custom: {
                          buttonLabel: 'label.configure',
                          action: cloudStack.lbStickyPolicy.dialog()
                        }
                      },
                      'autoScale': {
                        label: 'AutoScale',
                        custom: {
                          requireValidation: true,
                          buttonLabel: 'label.configure',
                          action: cloudStack.uiCustom.autoscaler(cloudStack.autoscaler)
                        }
                      },
                      'add-vm': {
                        label: 'label.add.vms',
                        addButton: true
                      }
                    },
                    tags: cloudStack.api.tags({ resourceType: 'LoadBalancer', contextId: 'multiRule' }),
                    add: {
                      label: 'label.add.vms',
                      action: function(args) {  											  
												var networkid;												
											  if('vpc' in args.context) { //from VPC section
												  if(args.data.tier == null) {													  
														args.response.error('Tier is required');
													  return;
													}												
												  networkid = args.data.tier;		
												}
												else if('networks' in args.context) {	//from Guest Network section										  
													networkid = args.context.networks[0].id;													
												}											
                        var data = {
                          algorithm: args.data.algorithm,
                          name: args.data.name,
                          privateport: args.data.privateport,
                          publicport: args.data.publicport,
													openfirewall: false,	
                          networkid: networkid,													
													publicipid: args.context.ipAddresses[0].id
                        };
											
                        var stickyData = $.extend(true, {}, args.data.sticky);                     
                        $.ajax({
                          url: createURL('createLoadBalancerRule'),
                          data: data,
                          dataType: 'json',
                          async: true,
                          success: function(data) {
                            var itemData = args.itemData;
                            var jobID = data.createloadbalancerruleresponse.jobid;
                            var lbID = data.createloadbalancerruleresponse.id;
                            $.ajax({
                              url: createURL('assignToLoadBalancerRule'),
                              data: {
                                id: data.createloadbalancerruleresponse.id,
                                virtualmachineids: $.map(itemData, function(elem) {
                                  return elem.id;
                                }).join(',')
                              },
                              dataType: 'json',
                              async: true,
                              success: function(data) {
                                var jobID = data.assigntoloadbalancerruleresponse.jobid;
                                var lbStickyCreated = false;
                                args.response.success({
                                  _custom: {
                                    jobId: jobID
                                  },
                                  notification: {
                                    label: 'label.add.load.balancer',
                                    poll: function(args) {
                                      var complete = args.complete;
                                      var error = args.error;
                                      pollAsyncJobResult({
                                        _custom: { jobId: jobID },
                                        complete: function(args) {
                                          if (lbStickyCreated) return;
                                          lbStickyCreated = true;
                                          // Create stickiness policy
                                          if (stickyData &&
                                              stickyData.methodname &&
                                              stickyData.methodname != 'None') {
                                            cloudStack.lbStickyPolicy.actions.add(lbID,
                                                                                  stickyData,
                                                                                  complete, error);
                                          } else {
                                            complete();
                                          }
                                        },
                                        error: error
                                      });
                                    }
                                  }
                                });
                              },
                              error: function(data) {
                                args.response.error(parseXMLHttpResponse(data));
                              }
                            });
                          },
                          error: function(data) {
                            args.response.error(parseXMLHttpResponse(data));
                          }
                        });
                      }
                    },
                    actions: {
                      edit: {
                        label: 'label.edit',
                        action: function(args) {
                          $.ajax({
                            url: createURL('updateLoadBalancerRule'),
                            data: $.extend(args.data, {
                              id: args.context.multiRule[0].id
                            }),
                            success: function(json) {
                              args.response.success({
                                _custom: { jobId: json.updateloadbalancerruleresponse.jobid },
                                notification: {
                                  label: 'label.edit.lb.rule',
                                  poll: pollAsyncJobResult
                                }
                              });
                            }
                          });
                        }
                      },
                      destroy:  {
                        label: 'label.action.delete.load.balancer',
                        action: function(args) {
                          $.ajax({
                            url: createURL('deleteLoadBalancerRule'),
                            data: {
                              id: args.context.multiRule[0].id
                            },
                            dataType: 'json',
                            async: true,
                            success: function(data) {
                              var jobID = data.deleteloadbalancerruleresponse.jobid;
                              args.response.success({
                                _custom: {
                                  jobId: jobID
                                },
                                notification: {
                                  label: 'label.action.delete.load.balancer',
                                  poll: pollAsyncJobResult
                                }
                              });
                            },
                            error: function(data) {
                              args.response.error(parseXMLHttpResponse(data));
                            }
                          });
                        }
                      }
                    },
                    itemActions: {
                      add: {
                        label: 'label.add.vms.to.lb',
                        action: function(args) {
                          $.ajax({
                            url: createURL('assignToLoadBalancerRule'),
                            data: {
                              id: args.multiRule.id,
                              virtualmachineids: $.map(args.data, function(elem) {
                                return elem.id;
                              }).join(',')
                            },
                            success: function(json) {
                              args.response.success({
                                notification: {
                                  _custom: {
                                    jobId: json.assigntoloadbalancerruleresponse.jobid
                                  },
                                  desc: 'label.add.vms.to.lb',
                                  poll: pollAsyncJobResult
                                }
                              });
                            },
                            error: function(json) {
                              args.response.error();
                              cloudStack.dialog.notice({ message: parseXMLHttpResponse(json) });
                            }
                          });
                        }
                      },
                      destroy: {
                        label: 'label.remove.vm.from.lb',
                        action: function(args) {
                          $.ajax({
                            url: createURL('removeFromLoadBalancerRule'),
                            data: {
                              id: args.multiRule.id,
                              virtualmachineids: args.item.id
                            },
                            success: function(json) {
                              args.response.success({
                                notification: {
                                  _custom: {
                                    jobId: json.removefromloadbalancerruleresponse.jobid
                                  },
                                  desc: 'label.remove.vm.from.lb',
                                  poll: pollAsyncJobResult
                                }
                              });
                            },
                            error: function(json) {
                              args.response.error();
                              cloudStack.dialog.notice({ message: parseXMLHttpResponse(json) });
                            }
                          });
                        }
                      }
                    },
                    dataProvider: function(args) {
                      var $multi = args.$multi;
                      $.ajax({
                        url: createURL('listLoadBalancerRules'),
                        data: {
                          publicipid: args.context.ipAddresses[0].id,
                          listAll: true
                        },
                        dataType: 'json',
                        async: true,
                        success: function(data) {
                          var loadBalancerData = data.listloadbalancerrulesresponse.loadbalancerrule;
                          var loadVMTotal = loadBalancerData ? loadBalancerData.length : 0;
                          var loadVMCurrent = 0;
                          $(loadBalancerData).each(function() {
                            loadVMCurrent++;
                            var item = this;
                            var stickyData = {};
                            var lbInstances = [];
                            // Passing _hideFields array will disable specified fields for this row
                            //item._hideFields = ['autoScale'];
                            
														$.ajax({
															url: createURL('listAutoScaleVmGroups'),
															data: {
																listAll: true,
																lbruleid: item.id
															},	
                              async: false,															
															success: function(json) {			
                                if(json.listautoscalevmgroupsresponse.autoscalevmgroup != null && json.listautoscalevmgroupsresponse.autoscalevmgroup.length > 0) { //from 'autoScale' button
																  item._hideFields = ['add-vm'];
																}
																else { //from 'add-vm' button
																  item._hideFields = ['autoScale'];
																} 
															}
														});
																												
														// Get sticky data
                            $.ajax({
                              url: createURL('listLBStickinessPolicies'),
                              async: false,
                              data: {
                                listAll: true,
                                lbruleid: item.id
                              },
                              success: function(json) {
                                var stickyPolicy = json.listlbstickinesspoliciesresponse.stickinesspolicies ?
                                      json.listlbstickinesspoliciesresponse.stickinesspolicies[0].stickinesspolicy : null;
                                if (stickyPolicy && stickyPolicy.length) {
                                  stickyPolicy = stickyPolicy[0];
                                  if (!stickyPolicy.methodname) stickyPolicy.methodname = 'None';
                                  stickyData = {
                                    _buttonLabel: stickyPolicy.methodname,
                                    methodname: stickyPolicy.methodname,
                                    stickyName: stickyPolicy.name,
                                    id: stickyPolicy.id,
                                    lbRuleID: item.id
                                  };
                                  $.extend(stickyData, stickyPolicy.params);
                                } else {
                                  stickyData = {
                                    lbRuleID: item.id
                                  };
                                }
                              },
                              error: function(json) {
                                cloudStack.dialog.notice({ message: parseXMLHttpResponse(json) });
                              }
                            });
                            // Get instances
                            $.ajax({
                              url: createURL('listLoadBalancerRuleInstances'),
                              dataType: 'json',
                              async: false,
                              data: {
                                listAll: true,
                                id: item.id
                              },
                              success: function(data) {
                                lbInstances = data.listloadbalancerruleinstancesresponse.loadbalancerruleinstance ?
                                  data.listloadbalancerruleinstancesresponse.loadbalancerruleinstance : [];
																																																	
                                $(lbInstances).each(function() {																  																
																	if(this.displayname.indexOf('AutoScale-LB-') > -1) //autoscale VM is not allowed to be deleted manually. So, hide destroy button
                                    this._hideActions = ['destroy'];	                                  																	
																});                                				
                              },
                              error: function(data) {
                                args.response.error(parseXMLHttpResponse(data));
                              }
                            });
                            $.extend(item, {
                              _itemName: 'displayname',
                              _itemData: lbInstances,
                              _maxLength: {
                                name: 7
                              },
                              sticky: stickyData,
                              autoScale: {
                                lbRuleID: item.id
                              }
                            });
                          });
                          args.response.success({
                            data: loadBalancerData
                          });
                        }
                      });
                      // Check if tiers are present; hide/show header drop-down (begin) ***   
                      //dataProvider() is called when a LB rule is added in multiEdit. However, adding a LB rule might change parent object (IP Address object). So, we have to force to refresh args.context.ipAddresses[0] here
										  $.ajax({
												url: createURL('listPublicIpAddresses'),
												data: {                      
													id: args.context.ipAddresses[0].id,
													listAll: true
												},
												success: function(json) {		                         											
													var ipObj = json.listpublicipaddressesresponse.publicipaddress[0];	
													getExtaPropertiesForIpObj(ipObj, args);
												
													args.context.ipAddresses.shift(); //remove the first element in args.context.ipAddresses										
													args.context.ipAddresses.push(ipObj);
																							
													var $headerFields = $multi.find('.header-fields');	                       												
													if ('vpc' in args.context) {
														if(args.context.ipAddresses[0].associatednetworkid == null) {
															$headerFields.show();
														}
														else {
															$headerFields.hide();
														}
													} 
													else if('networks' in args.context){
														$headerFields.hide();
													}																								
												}
											});											
                      // Check if tiers are present; hide/show header drop-down (end) ***   											
                    }
                  },
                  // Port forwarding rules
                  portForwarding: {
                    headerFields: {
                      tier: {
                        label: 'label.tier',
                        select: function(args) {
													if('vpc' in args.context) {		
                            var data = {
														  //listAll: true,  //do not pass listAll to listNetworks under VPC
															supportedservices: 'PortForwarding'
														};
														if(args.context.ipAddresses[0].associatednetworkid == null) {
														  $.extend(data, {
															  vpcid: args.context.vpc[0].id,
																domainid: args.context.vpc[0].domainid,
						                    account: args.context.vpc[0].account
															});
														}
														else {
														  $.extend(data, {
															  id: args.context.ipAddresses[0].associatednetworkid
															});
														}													
														$.ajax({
															url: createURL("listNetworks"),															
															data: data,															
															success: function(json) {					  
																var networks = json.listnetworksresponse.network;	
																var items = [];
																$(networks).each(function(){																  
																	items.push({id: this.id, description: this.displaytext});
																});
																args.response.success({ data: items });																
															}
														});	 
													}	
                        }
                      }
                    },
                    listView: $.extend(true, {}, cloudStack.sections.instances, {
                      listView: {
                        filters: false,
                        subselect: {
                          label: 'label.use.vm.ip',
                          dataProvider: instanceSecondaryIPSubselect
                        },
                        dataProvider: function(args) {
                          var networkid;
													if('vpc' in args.context) 
													  networkid = args.context.multiData.tier;													
													else 
													  networkid = args.context.ipAddresses[0].associatednetworkid;													
													
													var data = {
                            page: args.page,
                            pageSize: pageSize,
                            listAll: true,
                            networkid: networkid
                          };
                          if (!args.context.projects) {
                            $.extend(data, {
                              account: args.context.ipAddresses[0].account,
                              domainid: args.context.ipAddresses[0].domainid
                            });
                          }
                          $.ajax({
                            url: createURL('listVirtualMachines'),
                            data: data,
                            dataType: 'json',
                            async: true,
                            success: function(data) {
                              args.response.success({
                                data: $.grep(
                                  data.listvirtualmachinesresponse.virtualmachine ?
                                    data.listvirtualmachinesresponse.virtualmachine : [],
                                  function(instance) {
                                    return $.inArray(instance.state, [
                                      'Destroyed','Expunging'
                                    ]) == -1;
                                  }
                                )
                              });
                            },
                            error: function(data) {
                              args.response.error(parseXMLHttpResponse(data));
                            }
                          });
                        }
                      }
                    }),
                    fields: {
                      //'private-ports': {
                      privateport: {
                        edit: true,
                        label: 'label.private.port',
                        //range: ['privateport', 'privateendport']  //Bug 13427 - Don't allow port forwarding ranges in the CreatePortForwardingRule API
												range: ['privateport', 'privateendport']    //Bug 16344 (restore port range back) (http://bugs.cloudstack.org/browse/CS-16344)
                      },
                      //'public-ports': {
                      publicport: {
                        edit: true,
                        label: 'label.public.port',
                        //range: ['publicport', 'publicendport']  //Bug 13427 - Don't allow port forwarding ranges in the CreatePortForwardingRule API
												range: ['publicport', 'publicendport']    //Bug 16344 (restore port range back) (http://bugs.cloudstack.org/browse/CS-16344)
                      },
                      'protocol': {
                        label: 'label.protocol',
                        select: function(args) {
                          args.response.success({
                            data: [
                              { name: 'tcp', description: 'TCP' },
                              { name: 'udp', description: 'UDP' }
                            ]
                          });
                        }
                      },
                      'add-vm': {
                        label: 'label.add.vm',
                        addButton: true
                      }
                    },
                    tags: cloudStack.api.tags({ resourceType: 'PortForwardingRule', contextId: 'multiRule' }),
                    add: {
                      label: 'label.add.vm',
                      action: function(args) {
                        var data = {
                          ipaddressid: args.context.ipAddresses[0].id,
                          privateport: args.data.privateport,
													privateendport: args.data.privateendport,
                          publicport: args.data.publicport,
													publicendport: args.data.publicendport,
                          protocol: args.data.protocol,
                          virtualmachineid: args.itemData[0].id,
                          openfirewall: false
                        };
                        if (args.itemData[0]._subselect && args.itemData[0]._subselect != -1) {
                          data.vmguestip = args.itemData[0]._subselect;
                        }
                        if('vpc' in args.context) { //from VPC section
                          if(args.data.tier == null) {
                            args.response.error('Tier is required');
                            return;
                          }
                          $.extend(data, {
                            networkid: args.data.tier
                          });
                        }                        
												else {  //from Guest Network section
												  $.extend(data, {
                            networkid: args.context.networks[0].id
                          });	
												}
											
                        $.ajax({
                          url: createURL('createPortForwardingRule'),
                          data: data,                        
                          success: function(data) {
                            args.response.success({
                              _custom: {
                                jobId: data.createportforwardingruleresponse.jobid
                              },
                              notification: {
                                label: 'label.add.port.forwarding.rule',
                                poll: pollAsyncJobResult
                              }
                            });
                          },
                          error: function(data) {
                            args.response.error(parseXMLHttpResponse(data));
                          }
                        });
                      }
                    },
                    actions: {
                      destroy: {
                        label: 'label.remove.pf',
                        action: function(args) {
                          $.ajax({
                            url: createURL('deletePortForwardingRule'),
                            data: {
                              id: args.context.multiRule[0].id
                            },
                            dataType: 'json',
                            async: true,
                            success: function(data) {
                              var jobID = data.deleteportforwardingruleresponse.jobid;
                              args.response.success({
                                _custom: {
                                  jobId: jobID
                                },
                                notification: {
                                  label: 'label.remove.pf',
                                  poll: pollAsyncJobResult
                                }
                              });
                            },
                            error: function(data) {
                              args.response.error(parseXMLHttpResponse(data));
                            }
                          });
                        }
                      }
                    },
                    dataProvider: function(args) {
                      var $multi = args.$multi;
                      $.ajax({
                        url: createURL('listPortForwardingRules'),
                        data: {
                          ipaddressid: args.context.ipAddresses[0].id,
                          listAll: true
                        },
                        dataType: 'json',
                        async: true,
                        success: function(data) {
                          // Get instance
                          var portForwardingData = data
                                .listportforwardingrulesresponse.portforwardingrule;
                          var loadTotal = portForwardingData ? portForwardingData.length : 0;
                          var loadCurrent = 0;
                          $(portForwardingData).each(function() {
                            var item = this;
                            item._itemName = '_displayName';
                            $.ajax({
                              url: createURL('listVirtualMachines'),
                              dataType: 'json',
                              async: true,
                              data: {
                                listAll: true,
                                id: item.virtualmachineid
                              },
                              success: function(data) {
                                loadCurrent++;
                                $.extend(item, {
                                  _itemData: $.map(data.listvirtualmachinesresponse.virtualmachine, function(vm) {
                                    return $.extend(vm, {
                                      _displayName: vm.id == vm.displayname ?
                                        (vm.instancename ? vm.instancename : vm.name)
                                      : vm.displayname
                                    });
                                  }),
                                  _context: {
                                    instances: data.listvirtualmachinesresponse.virtualmachine
                                  }
                                });
                                if (loadCurrent == loadTotal) {
                                  args.response.success({
                                    data: portForwardingData
                                  });
                                }
                              }
                            });
                          });
                 							
													// Check if tiers are present; hide/show header drop-down (begin) ***   
													//dataProvider() is called when a PF rule is added in multiEdit. However, adding a LB rule might change parent object (IP Address object). So, we have to force to refresh args.context.ipAddresses[0] here
													$.ajax({
														url: createURL('listPublicIpAddresses'),
														data: {                      
															id: args.context.ipAddresses[0].id,
															listAll: true
														},
														success: function(json) {												  
															var ipObj = json.listpublicipaddressesresponse.publicipaddress[0];														 
											        getExtaPropertiesForIpObj(ipObj, args);													 
													
															args.context.ipAddresses.shift(); //remove the first element in args.context.ipAddresses										
															args.context.ipAddresses.push(ipObj);
																									
															var $headerFields = $multi.find('.header-fields');													
															if ('vpc' in args.context) {
																if(args.context.ipAddresses[0].associatednetworkid == null) {
																	$headerFields.show();
																}
																else {
																	$headerFields.hide();
																}
															} 
															else if('networks' in args.context){
																$headerFields.hide();
															}																								
														}
													});											
													// Check if tiers are present; hide/show header drop-down (end) ***   	
                        },
                        error: function(data) {
                          args.response.error(parseXMLHttpResponse(data));
                        }
                      });
                    }
                  }
                })
              },
              vpn: {
                title: 'VPN',
                custom: function(args) {
                  var ipAddress = args.context.ipAddresses[0].ipaddress;
                  var psk = "";
                  if(args.context.ipAddresses[0].remoteaccessvpn != null)
                    psk = args.context.ipAddresses[0].remoteaccessvpn.presharedkey;
                  return $('