// 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) {
    /**
     * Serialize form data as object
     */
    var getData = function($wizard, options) {
        if (!options) options = {};
        var $forms = $wizard.find('form').filter(function() {
            return !options.all ? !$(this).closest('.multi-edit').size() : true;
        });
        var $physicalNetworkItems = $wizard.find(
            '.steps .setup-physical-network .select-container.multi'
        ).filter(':not(.disabled)');
        var $publicTrafficItems = $wizard.find(
            '.steps .setup-public-traffic .data-body .data-item');
        var $storageTrafficItems = $wizard.find(
            '.steps .setup-storage-traffic .data-body .data-item');
        var groupedForms = {};
        if ($physicalNetworkItems.find('li.traffic-type-draggable.storage').size()) {
            $wizard.find('li.conditional.storage-traffic').show();
        } else {
            $wizard.find('li.conditional.storage-traffic').hide();
        }
        if (options.all) {
            return cloudStack.serializeForm($forms, {
                escapeSlashes: true
            });
        }
        // Group form fields together, by form ID
        $forms.each(function() {
            var $form = $(this);
            var id = $form.attr('rel');
            if (!id) return true;
            groupedForms[id] = cloudStack.serializeForm($form, {
                escapeSlashes: true
            });
            return true;
        });
        // Get physical network data
        groupedForms.physicalNetworks = $.map(
            $physicalNetworkItems,
            function(network) {
                var $network = $(network);
                var $guestForm = $wizard.find('form[guest-network-id=' + $network.index() + ']');
                var trafficTypeConfiguration = {};
                $network.find('.traffic-type-draggable').each(function() {
                    var $trafficType = $(this);
                    var trafficTypeID = $trafficType.attr('traffic-type-id');
                    trafficTypeConfiguration[trafficTypeID] = $trafficType.data('traffic-type-data');
                });
                return {
                    id: $network.index(),
                    name: $network.find('.field.name input[type=text]').val(),
                    isolationMethod: $network.find('.field.name select').val(),
                    // Traffic type list
                    trafficTypes: $.map(
                        $network.find('.traffic-type-draggable'),
                        function(trafficType) {
                            var $trafficType = $(trafficType);
                            return $trafficType.attr('traffic-type-id');
                        }
                    ),
                    // Traffic type configuration data
                    trafficTypeConfiguration: trafficTypeConfiguration,
                    guestConfiguration: $guestForm.size() ? cloudStack.serializeForm($guestForm) : null
                };
            }
        );
        // Get public traffic data (multi-edit)
        groupedForms.publicTraffic = $.map(
            $publicTrafficItems,
            function(publicTrafficItem) {
                var $publicTrafficItem = $(publicTrafficItem);
                var publicTrafficData = {};
                var fields = [
                    'gateway',
                    'netmask',
                    'vlanid',
                    'startip',
                    'endip'
                ];
                $(fields).each(function() {
                    publicTrafficData[this] =
                        $publicTrafficItem.find('td.' + this + ' span').html();
                });
                return publicTrafficData;
            }
        );
        // Get storage traffic data (multi-edit)
        groupedForms.storageTraffic = $.map(
            $storageTrafficItems,
            function(storageTrafficItem) {
                var $storageTrafficItem = $(storageTrafficItem);
                var storageTrafficData = {};
                var fields = [
                    'gateway',
                    'netmask',
                    'vlan',
                    'startip',
                    'endip'
                ];
                $(fields).each(function() {
                    storageTrafficData[this] =
                        $storageTrafficItem.find('td.' + this + ' span').html();
                });
                return storageTrafficData;
            }
        );
        // Hack to fix forward slash JS error
        $.each(groupedForms, function(key1, value1) {
            $.each(value1, function(key2, value2) {
                if (typeof value2 == 'string') {
                    groupedForms[key1][key2] = value2.replace(/__forwardSlash__/g, '\/');
                }
            });
        });
        // Include zone network type
        if (groupedForms.zone) {
            groupedForms.zone.networkType = $forms.find('input[name=network-model]:checked').val();
            // Include zone isolation mode, supported for Advanced zones only
            if (groupedForms.zone.networkType == 'Advanced') {
                groupedForms.zone.sgEnabled = $forms.find('input[name=zone-advanced-sg-enabled]')
                    .is(':checked') ? true : false;
            }
        }
        return groupedForms;
    };
    /**
     * Handles validation for custom UI components
     */
    var customValidation = {
        networkRanges: function($form) {
            if ($form.closest('.multi-edit').find('.data-item').size()) {
                return true;
            }
            cloudStack.dialog.notice({
                message: _l('message.please.add.at.lease.one.traffic.range')
            });
            return false;
        },
        physicalNetworks: function($form) {
            var $enabledPhysicalNetworks = $form.filter(':not(.disabled)').filter(function() {
                return $(this).find('.traffic-type-draggable').size();
            });
            var $trafficTypes = $enabledPhysicalNetworks.find('.traffic-type-draggable');
            var $configuredTrafficTypes = $trafficTypes.filter(function() {
                var $trafficType = $(this);
                return ($trafficType.data('traffic-type-data') != null);
            });
            if ($enabledPhysicalNetworks.size() > 1 &&
                $configuredTrafficTypes.size() != $trafficTypes.size()) {
                cloudStack.dialog.notice({
                    message: _l('message.configure.all.traffic.types')
                });
                return false;
            }
            return true;
        }
    };
    /**
     * Determine if UI components in step should be custom-validated
     * (i.e., not a standard form)
     */
    var checkCustomValidation = function($step) {
        var $multiEditForm = $step.find('.multi-edit form');
        var $physicalNetworks = $step.find('.select-container.multi');
        var isCustomValidated;
        if ($multiEditForm.size()) {
            isCustomValidated = customValidation.networkRanges($multiEditForm);
        } else if ($physicalNetworks.size()) {
            isCustomValidated = customValidation.physicalNetworks($physicalNetworks);
        } else {
            isCustomValidated = true;
        }
        return isCustomValidated;
    };
    var isAdvancedNetwork = function($wizard) {
        return getData($wizard, {
            all: true
        })['network-model'] == 'Advanced';
    };
    /**
     * Setup physical network wizard UI
     */
    var physicalNetwork = {
        init: function($wizard) {
            var $existingPhysicalNetworks = physicalNetwork.getNetworks($wizard);
            // Initialize physical networks
            if (!$existingPhysicalNetworks.size()) {
                physicalNetwork.add($wizard);
            } else if (!isAdvancedNetwork($wizard)) {
                $existingPhysicalNetworks.filter(':first').siblings().each(function() {
                    physicalNetwork.remove($(this));
                });
            }
            physicalNetwork.updateNetworks(physicalNetwork.getNetworks($wizard));
            $wizard.find('.traffic-types-drag-area ul li').removeClass('required disabled clone');
            // Setup clone traffic types
            $(physicalNetwork.cloneTrafficTypes($wizard)).each(function() {
                var trafficTypeID = this;
                $wizard.find('.traffic-types-drag-area ul li').filter(function() {
                    return $(this).hasClass(trafficTypeID);
                }).addClass('clone');
            });
            // Setup required traffic types
            $(physicalNetwork.requiredTrafficTypes($wizard)).each(function() {
                var trafficTypeID = this;
                var $firstPhysicalNetwork = physicalNetwork.getNetworks($wizard).filter(':first');
                // First physical network gets required traffic types
                physicalNetwork.assignTrafficType(trafficTypeID, $firstPhysicalNetwork);
                $wizard.find('.traffic-types-drag-area ul li').filter(function() {
                    return $(this).hasClass(trafficTypeID);
                }).addClass('required');
            });
            // Setup disabled traffic types
            $(physicalNetwork.disabledTrafficTypes($wizard)).each(function() {
                var trafficTypeID = this;
                var $trafficType = physicalNetwork.getTrafficType(this, $wizard);
                physicalNetwork.unassignTrafficType($trafficType);
                $wizard.find('.traffic-types-drag-area ul li').filter(function() {
                    return $(this).hasClass(trafficTypeID);
                }).addClass('disabled');
            });
        },
        /**
         * Traffic type edit dialog
         */
        editTrafficTypeDialog: function($trafficType) {
            var trafficData = $trafficType.data('traffic-type-data') ?
                $trafficType.data('traffic-type-data') : {};
            var hypervisor = getData($trafficType.closest('.zone-wizard')).zone.hypervisor;
            var zoneType = getData($trafficType.closest('.zone-wizard')).zone.networkType;
            var fields;
            
            if (hypervisor == 'VMware') {
            	fields = {
            		vSwitchName: {
	                    label: 'label.vswitch.name' ,
	                    defaultValue: trafficData.vSwitchName
	                },
	                vlanId: { 
	                        label: 'label.vlan.id',
	                	defaultValue: trafficData.vlanId
	                }	                
	            };  
            	
            	if(zoneType == 'Advanced') {
	            	if($trafficType.hasClass('guest') || $trafficType.hasClass('public')) {            		
	            		if(trafficData.vSwitchType == null) {
	            			 var useDvs = false;
	                         $.ajax({
	                             url: createURL('listConfigurations'),
	                             data: {
	                                 name: 'vmware.use.dvswitch'
	                             },
	                             async: false,
	                             success: function(json) {
	                                 if (json.listconfigurationsresponse.configuration[0].value == 'true') {
	                                     useDvs = true;
	                                 }
	                             }
	                         });    
	                         if (useDvs == true) { 
	                        	 var useNexusDvs = false;                                            
	                             $.ajax({
	                                 url: createURL('listConfigurations'),
	                                 data: {
	                                     name: 'vmware.use.nexus.vswitch'
	                                 },
	                                 async: false,
	                                 success: function(json) {
	                                     if (json.listconfigurationsresponse.configuration[0].value == 'true') {
	                                         useNexusDvs = true;
	                                     }
	                                 }
	                             });
	                             if (useNexusDvs == true) {
	                            	 trafficData.vSwitchType = 'nexusdvs';
	                            	 fields.vSwitchName.defaultValue = 'epp0';
	                             } else {
	                            	 trafficData.vSwitchType = 'vmwaredvs';
	                            	 fields.vSwitchName.defaultValue = 'dvSwitch0';
	                             }   
	                         } else { //useDvs == false
	                        	 trafficData.vSwitchType = 'vmwaresvs';
	                        	 fields.vSwitchName.defaultValue = 'vSwitch0';
	                         }                         
	            		}
	            		
	            		$.extend(fields, {
	            		    vSwitchType: {
	                                label: 'label.vSwitch.type',
	            		        select: function (args) {            		        	
	            		            args.response.success({
	            		                data: [{
	            		                    id: 'nexusdvs',
	            		                    description: 'Cisco Nexus 1000v Distributed Virtual Switch'
	            		                }, {
	            		                    id: 'vmwaresvs',
	            		                    description: 'VMware vNetwork Standard Virtual Switch'
	            		                }, {
	            		                    id: 'vmwaredvs',
	            		                    description: 'VMware vNetwork Distributed Virtual Switch'
	            		                }]
	            		            });
	            		        },
	    		                defaultValue: trafficData.vSwitchType
	            		    }
	            		});   
	            	}  
            	}
            } else {    
	            fields = {
	                label: {
	                    label: hypervisor + ' ' + _l('label.traffic.label'),
	                    defaultValue: trafficData.label
	                }
	            };
            }
            cloudStack.dialog.createForm({
                form: {
                    title: _l('label.edit.traffic.type'),
                    desc: _l('message.edit.traffic.type'),
                    fields: fields
                },
                after: function(args) {               
                    $trafficType.data('traffic-type-data', args.data);
                }
            });
        },
        /**
         * Get required traffic type IDs for proper validation
         */
        requiredTrafficTypes: function($wizard) {
            return cloudStack.zoneWizard.requiredTrafficTypes({
                data: getData($wizard)
            });
        },
        /**
         * Get required traffic type IDs for proper validation
         */
        disabledTrafficTypes: function($wizard) {
            return cloudStack.zoneWizard.disabledTrafficTypes({
                data: getData($wizard)
            });
        },
        /**
         * Get clone-type traffic type IDs for proper validation
         */
        cloneTrafficTypes: function($wizard) {
            return cloudStack.zoneWizard.cloneTrafficTypes({
                data: getData($wizard)
            });
        },
        /**
         * Physical network step: Renumber network form items
         */
        renumberFormItems: function($container) {
            var $items = $container.find('.select-container.multi');
            $items.each(function() {
                var $item = $(this);
                var $networkName = $item.find('.field.name input[type=text]');
                var $networkId = $item.find('input[name=id]');
                var $networkTypes = $item.find('.field.network-types input');
                var index = $item.index();
                $networkId.val(index);
                $networkName.attr('name', 'physicalNetworks[' + index + ']' + '.name');
                $networkTypes.val(index);
            });
        },
        /**
         * Get main physical network wizard step container
         *
         * @param $elem Any elem within the container
         */
        getMainContainer: function($elem) {
            return $elem.closest('.steps .setup-physical-network');
        },
        /**
         * Returns traffic elem
         *
         * @param trafficTypeID ID of desired traffic type
         */
        getTrafficType: function(trafficTypeID, $container) {
            var $trafficType = $container.find('li.traffic-type-draggable').filter(function() {
                return $(this).attr('traffic-type-id') == trafficTypeID;
            });
            if (physicalNetwork.isTrafficTypeClone($trafficType) && !$container.closest('.select-container.multi').size()) {
                // Get traffic type from original container
                return $trafficType.filter(function() {
                    return $(this).closest(
                        physicalNetwork.getOriginalTrafficContainer($trafficType)
                    ).size();
                });
            }
            return $trafficType;
        },
        /**
         * Get original drag container for traffic type elem
         *
         * @param $trafficType Traffic type elem
         */
        getOriginalTrafficContainer: function($trafficType) {
            var $dragContainer = physicalNetwork.getMainContainer($trafficType)
                .find('.traffic-types-drag-area ul > li')
                .filter(function() {
                    return $(this).hasClass($trafficType.attr('traffic-type-id'));
                })
                .find('ul');
            return $dragContainer;
        },
        /**
         * Get all physical networks
         *
         * @param $container Physical network step - main container
         */
        getNetworks: function($container) {
            return $container.find('.select-container.multi');
        },
        /**
         * Determine if traffic type is a 'cloned' type
         *
         * @param $trafficType
         */
        isTrafficTypeClone: function($trafficType) {
            return physicalNetwork.getOriginalTrafficContainer($trafficType).parent().hasClass('clone');
        },
        /**
         * Assigns traffic type to specified physical network
         *
         * @param trafficTypeID ID of desired traffic type
         * @param $physicalNetwork Physical network elem
         */
        assignTrafficType: function(trafficTypeID, $physicalNetwork, data) {
            var $container = physicalNetwork.getMainContainer($physicalNetwork);
            var $trafficType = physicalNetwork.getTrafficType(trafficTypeID, $container);
            var $dropArea = $physicalNetwork.find('.drop-container ul');
            if ($physicalNetwork.find('.traffic-type-draggable[traffic-type-id=' + trafficTypeID + ']').size()) return false;
            if (physicalNetwork.isTrafficTypeClone($trafficType)) {
                if (!physicalNetwork.getTrafficType(trafficTypeID, $physicalNetwork).size()) {
                    $trafficType = $trafficType.clone()
                        .removeClass('disabled')
                        .appendTo($dropArea)
                        .draggable(physicalNetwork.draggableOptions($physicalNetwork.closest('.zone-wizard')));
                } else {
                    return false;
                }
            } else {
                $trafficType.appendTo($dropArea);
            }
            if (data) {
                $trafficType.data('traffic-type-data', data);
            }
            physicalNetwork.updateNetworks($.merge($physicalNetwork, $physicalNetwork.siblings()));
            return $trafficType;
        },
        /**
         * Assigns traffic type to original drag container
         *
         * @param trafficTypeID ID of desired traffic type
         * @param $container Physical network wizard step container
         * @param $physicalNetwork (optional) Specific physical network to remove from -- only for clones
         */
        unassignTrafficType: function($trafficType) {
            var $wizard = $trafficType.closest('.zone-wizard');
            var $originalContainer = physicalNetwork.getOriginalTrafficContainer($trafficType);
            var $physicalNetworks = physicalNetwork.getNetworks($wizard);
            var trafficTypeID = $trafficType.attr('traffic-type-id');
            if (!physicalNetwork.isTrafficTypeClone($trafficType) &&
                $.inArray(trafficTypeID, physicalNetwork.requiredTrafficTypes($wizard)) == -1) {
                $trafficType.appendTo($originalContainer);
            } else {
                physicalNetwork.assignTrafficType(
                    trafficTypeID,
                    $physicalNetworks.filter(':first')
                );
                if (physicalNetwork.isTrafficTypeClone($trafficType) &&
                    $physicalNetworks.find('.traffic-type-draggable[traffic-type-id=' + trafficTypeID + ']').size() > 1) {
                    $trafficType.remove();
                }
            }
            return $trafficType;
        },
        /**
         * Returns true if new physical network item needs to be added
         */
        needsNewNetwork: function($containers) {
            // Basic zones do not have multiple physical networks
            if (!isAdvancedNetwork($containers.closest('.zone-wizard')))
                return false;
            var $emptyContainers = $containers.filter(function() {
                return !$(this).find('li').size();
            });
            return !$emptyContainers.size() ? $containers.size() : false;
        },
        /**
         * Cleanup physical network containers
         */
        updateNetworks: function($containers) {
            var $mainContainer = physicalNetwork.getMainContainer($containers);
            var $allPhysicalNetworks = physicalNetwork.getNetworks($mainContainer);
            var containerTotal = isAdvancedNetwork($containers.closest('.zone-wizard')) ?
                2 : 1;
            $allPhysicalNetworks.each(function() {
                var $ul = $(this).find('.drop-container ul');
                if (!$(this).find('li').size()) {
                    $(this).addClass('disabled');
                    $ul.fadeOut();
                } else {
                    $(this).removeClass('disabled');
                    $ul.show();
                }
            });
            $containers.each(function() {
                var $currentContainer = $(this);
                if (!$currentContainer.find('li').size() &&
                    $containers.size() > containerTotal) {
                    $currentContainer.remove();
                }
            });
            $containers = $containers.closest('.setup-physical-network')
                .find('.select-container.multi');
            if (physicalNetwork.needsNewNetwork($containers)) {
                physicalNetwork.add($mainContainer.parent());
            }
            $containers.filter(':first').find('.remove.physical-network').remove();
            return $containers;
        },
        /**
         * Default options for initializing traffic type draggables
         */
        draggableOptions: function($wizard) {
            return {
                appendTo: $wizard,
                helper: 'clone',
                // Events
                start: function(event, ui) {
                    $(this).addClass('disabled');
                },
                stop: function(event, ui) {
                    $(this).removeClass('disabled');
                },
                cancel: '.edit-traffic-type'
            };
        },
        /**
         * Physical network step: Generate new network element
         */
        add: function($wizard) {
            var $container = $wizard.find('.setup-physical-network .content.input-area form');
            var $physicalNetworkItem = $('
').addClass('select-container multi');
            var $deleteButton = $('
').addClass('button remove physical-network')
                .attr({
                    title: 'Remove this physical network'
                })
                .append('
').addClass('icon').html(' ');
            var $icon = $('').addClass('physical-network-icon');
            var $nameField = $('
').addClass('field name').append(
                $('
').addClass('name').append(
                    $('