// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.
//
// Returns a singleton instance of an InitialNetworkPresenter
//
define(['hp/core/EventDispatcher',
        'fs/services/settings/NetworkSetupService',
        'fs/services/status/StatusService',
        'fs/services/settings/CertificateService',
        'fs/services/settings/SettingsService',
        'hp/core/Localizer',
        'hp/lib/date'],
function(EventDispatcher, networkSetupService, statusService, certificateService, settingsService, localizer) { "use strict";

    var NetworkSetupPresenter = (function() {

        // Total timeout / length of progress bar under other circumstances.  The longest time we've seen in testing was about
        // 22 seconds.
        var NORMAL_DELAY = 60000; // msec

        // How long to wait, after a getTaskStatus request times out, before trying again.
        var TASK_RESULT_DELAY = 3000; // msec

        // How long to wait, after a checkReachable request times out, before trying again.
        var REACHABLE_DELAY = 1500; // msec

        // How long to wait, after achieving contact with the new hostname, before giving up on achieving contact with the old
        // hostname.  Should be large enough for a couple of attempts at the old hostname.
        //var REACHABLE_OFFSET = 3000; // msec

        // Should we do a reload window after 10s timeout to deal with the dynamic certificates
        var shouldReload = false;
        var manualToDhcp = false;

        var MAX_TRY=11;
        var httpSuccess = false;
        var maxNoOfNICsDisplayed = 8,
            maxNoOfNICsSupported = 8,
            MULTI_NIC_DISABLED_KEY = 'multiNICDisabled',
            MAX_NO_OF_NICS_DISPLAYED_KEY = 'maxNoOfNICsDisplayed',
            MAX_NO_OF_NICS_SUPPORTED_DISABLED_KEY = 'maxNoOfNICsSupported',
            ALIAS_SUPPORTED_DISABLED_KEY = 'ipaliasHostname',
            aliasSupportedOld = null,
            aliasSupportedFlag = false,
            multiNICDisabled = false,
            singleNICEnabled  = false;
            
        /**
         * @constructor Singleton class containing presentation
         *              logic for the initial network settings page
         * @type {InitialNetworkPresenter}
         */
        function NetworkSetupPresenter() {

            this.STATIC = "STATIC";
            this.UNCONFIGURE = "UNCONFIGURE";
            this.DHCP = "DHCP";

            this.MANUAL_TO_DHCP_ERROR = "MANUAL_TO_DHCP";
            this.REACHABLE_ERROR = "REACHABLE_ERROR";

            var REACHABLE_ERROR = "REACHABLE_ERROR";
            var STATIC = "STATIC";
            var UNCONFIGURE = "UNCONFIGURE";
            var DHCP = "DHCP";

            var dispatcher = new EventDispatcher();

            // The network configuration, as retrieved from the server.
            var originalConfig;

            // Total amount of time to wait for node to be accessible.
            var setConfigTimeout;

            // Timestamp when setNetworkConfiguration was started.
            var setConfigStartTime;

            // Flag indicating that we are currently polling the server for reachability.
            var checkingReachable;

            // Timers on reachable hosts.  This is an object keyed by hostname (with '' for the current/old host).
            var hostReachableTimers = {};

            // Flag whether we should be trying to talk to the pre-change hostname.
            var originalHostAllowed;

            // Flag whether we should redirect the browser when the network configuration finishes.
            var shouldRedirect;


            // Hostname we want to be connected to when we're done.
            var newHostname;

            // URI for the setNetworkConfiguration asynchronous task.
            var taskURI;

            // Forward function references.
            var checkTaskResult;
            var handleTaskStatus;

            // For unit testing, allow a stub of the timers created and cleared.
            var timerHost = window;

            var retryCount = 0;

            /**
             * Stop the interval timers pinging the hosts for when they become reachable.
             */
            function clearTimers() {
                for (var host in hostReachableTimers) {
                    if (hostReachableTimers[host]) {
                        timerHost.clearTimeout(hostReachableTimers[host]);
                        hostReachableTimers[host] = null;
                    }
                }
            }
            
            /**
             * Report a failure of the configuration change to the view.
             *
             * @param {Object} errorInfo Error information
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             */
            function onSetConfigFailed(errorInfo, handlers) {
                handlers.error(errorInfo);

            }

            /**
             * Handler for when a host becomes reachable.
             *
             * @param {string} host Hostname of the host that became reachable, '' for current.
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             * @param {boolean} ssl whether the controller-state was reached using https
             * @param {boolean} certErrorFlag last checkReachable call resulted in certificate error
             * @param {Object} the count of the checkReachable call which succeeded or the last try count
             */
            function onReachable(host, ssl,handlers, certErrorFlag, retryCount) {
                if (!host) {
                    // Old host is reachable again; it must have been a transient outage due to network reconfiguration.
                    // Go back to polling on the task status.


                  // incase of old host but  need a certificate to to be generated , redirect to the old host
                  //again so that the client side certificate is generated
                  // !ssl means the controler-state.json was pinged using http
                  // redirect if http was successful or if the https error came multiple times (assuming a new certificate is created)
                  if(!ssl || certErrorFlag){
                      checkingReachable = false;
                      clearTimers();
                        var data = {
                                state : null,
                                computedPercentComplete : null,
                                host : host,
                                rechableDelay : retryCount*REACHABLE_DELAY,//this much time we waited for the checkReachable to succeed.  
                                certError : certErrorFlag
                            };
                     handlers.success(data);
                     return;

                  }
                    clearTimers();
                    checkTaskResult(host, handlers);
                } else {
                    // We got to the new node.
                    checkingReachable = false;
                    clearTimers();

                    // Let's see if we can get task status from the new host.  It's unlikely but worth trying.
                    networkSetupService.getTaskStatus(host, taskURI, {
                        success: function(status) {
                            // Yes, so poll on the task status as needed.
                            handleTaskStatus(host, status, handlers);
                        },
                        error: function(errorInfo) {
                            // Can't get to the task status.  This is probably because of the self-signed certificate at the new
                            // address.  We'll call it good.

                               var data = {
                                       state : null,
                                       computedPercentComplete : null,
                                       host : host,
                                       rechableDelay : retryCount*REACHABLE_DELAY
                                   };
                            handlers.success(data);
                        }
                    });
                }
            }
            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration uses DHCP.
             */
            function isDhcpIPv4Used(data) {
                return data.ipv4Type == DHCP ;
            }
            
             /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration uses DHCP.
             */
           function isDhcpIPv6Used (data) {
                return  data.ipv6Type == DHCP;
            }
           /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration uses IPv6.
             */
            function isIpv6Used (data) {
                return data.ipv6Type != UNCONFIGURE;
            }

            function onSetConfigTimeout(handlers) {
               checkingReachable = false; // stop all reachability testing; we've given up.
                // clear all timers to prevent spawning new threads
                // add specific error code if the appliance becomes unreachable
               clearTimers();
               onSetConfigFailed({
                   errorCode : REACHABLE_ERROR,
                   message: localizer.getString('fs.settings.network.error.set.timeout.msg'),
                   resolution: localizer.getString('fs.settings.network.error.set.timeout.res')
               }, handlers);
            }



            /**
             * Check whether the server is reachable, on either the old or the new address.
             *
             * @param {string} ssl flag to check if https is needed .
             * @param {string} host Hostname of the server to check, '' for current.
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             */
            function checkReachable(host,ssl, handlers) {
                hostReachableTimers[host] = null;
                networkSetupService.checkReachable(host,ssl, {
                    success: function() {

                      onReachable(host,ssl,handlers, false, retryCount);
                      httpSuccess = !ssl;
                    },
                    error: function(errorInfo) {
                        // If we've already flagged that the host is reachable by some other means,
                      //we can ignore this error.
                        // This flag is also cleared when the overall operation times out.

                        if (!checkingReachable) {
                            return;
                        }

                        // reduce the MAX_TRY  incase http is reachable
                        if(httpSuccess){
                          MAX_TRY = MAX_TRY-2;
                        }

                        retryCount++;
                        //alternate between https and http
                        if(retryCount < MAX_TRY){
                          if(retryCount%2){
                            hostReachableTimers[host] = timerHost.setTimeout(function() {
                               checkReachable(host,false, handlers); // attempt with http
                            }, REACHABLE_DELAY);

                            }else{
                               hostReachableTimers[host] = timerHost.setTimeout(function() {
                                 checkReachable(host,true, handlers); // attempt with https
                                 }, REACHABLE_DELAY);
                            }
                           
                          }
                         httpSuccess = false;
                        if (retryCount == MAX_TRY){
                            //if the error status is timeout on the last retry, assume the appliance(new IP) is unreachable and show error.
                            if(errorInfo.statusText === 'timeout' && errorInfo.status === 0){
                                onSetConfigTimeout(handlers);
                                return;
                            }
                            // otherwise assume that the appliance is reachable and https is not going through due to certificate error,
                            // proceed with redirection
                            onReachable(host,ssl, handlers, true, retryCount);
                            return;
                        }

                    }
                });
            }


            /**
             * Wait until the server is reachable, on either the old or the new hostname.
             *
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             */
            function waitForReachable(handlers) {
                checkingReachable = true;

                 if (shouldRedirect) {

                    hostReachableTimers[newHostname] = timerHost.setTimeout(function() {
                        checkReachable(newHostname,true, handlers);
                    }, REACHABLE_DELAY);
                    return;
                }

                if (originalHostAllowed) {
                    hostReachableTimers[''] = timerHost.setTimeout(function() {
                            checkReachable('',true, handlers);
                    }, REACHABLE_DELAY);
                }



            }

            /**
             * Handle the task status returned from the asynchronous setNetworkConfiguration call.Incase of TaskT
             * there are only 3 states 'Running', 'Completed' and 'Error'.So the Default has been pointed to Error
             *
             * @param {string} host Hostname from which task status was requested, '' for current.
             * @param {TaskResource} status Task resource with status.
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             */
            handleTaskStatus = function(host, status, handlers) {

                var taskData = {
                        state : status.taskStatus,
                        computedPercentComplete : status.computedPercentComplete,
                        host : host
                    };
                switch (status.taskState) {
                case 'Error':
                       if (status.taskStatus === "pre-validation" &&
                               ((status.taskErrors !== null ||  status.taskErrors != undefined )
                                   && status.taskErrors.length > 0  )) {
                                   onSetConfigFailed(status.taskErrors, handlers);
                          }
                       else if(status.taskStatus === "fts-in-progress"){
                           onSetConfigFailed({
                               message: localizer.getString('fs.settings.network.error.set.ftsinprogress.msg')
                           }, handlers);
                       }
                       else {
                           // Incase if task errors or task status is not present displaying a generic error
                           onSetConfigFailed({
                               message: localizer.getString('fs.settings.network.error.set.unknown.msg')
                           }, handlers);
                       }


                       break;

                case 'Completed':
                    // Job is finished successfully.  Since we were able to get task status from our old address, there's no
                    // need to redirect except in the case where there was a hostname change and we need to force page reload
                    if (status.taskStatus === 'post-validation'){
                         handlers.success(taskData);
                         }else{
                             taskData = {
                                  state : null,
                                  computedPercentComplete : status.computedPercentComplete,
                                  host : host
                              };
                             handlers.success(taskData);
                         }


                    break;

                default:
                    // Job is still running, we'll poll again after an interval.
                    timerHost.setTimeout(function() {
                        checkTaskResult(host, handlers);
                    }, TASK_RESULT_DELAY);

                    break;
                }
            };

            /**
             * Method called periodically to check the results of the running setNetworkConfiguration asynchronous task.
             *
             * @param {string} host Hostname of the host to request task status from, '' for current.
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             */
            checkTaskResult = function(host, handlers) {
                checkingReachable = false;
                networkSetupService.getTaskStatus(host, taskURI, {
                    success: function(status) {
                    handleTaskStatus(host, status, handlers);
                    },
                     error: function(errorInfo) {
                            // the problem may be caused by a newly generated certificate that a user can only accept in a browser
                            // try to continue even if not redirect

                              // if redirect is true and hostname is changed we ping the controller-state for getting
                            if (shouldRedirect) {
                                originalHostAllowed = false;
                                clearTimers();
                               waitForReachable(handlers);

                            } else {
                                // ignore the error for Beta
                                originalHostAllowed = true;
                                clearTimers();
                                waitForReachable(handlers);
                           }
                  }
                });

            };


            /**
             * The appliance setNetworkConfiguration call succeeded, which means the asynchronous process of changing the network
             * configuration (and possibly adding a node) has begun.  Periodically monitor it.
             *
             * @param {Object} result Result of the setNetworkConfiguration call.
             * @param {Object} handlers Handlers for the setNetworkConfiguration results.
             */
            function onSetConfigSuccess(result,data,responseHeader, handlers) {
            
                taskURI = responseHeader.getResponseHeader('Location');
            
                handlers.running(setConfigTimeout);
                checkTaskResult('', handlers);
            }

            /**
             * This function updates the ntp servers field
             * ntpData contains ntp servers list which is retrieved from the appliance.
             * @param ntpData
             */
            function updateNTPservers(ntpData){
                dispatcher.fire("ntpServersChange",ntpData);
            }

            /**
             * Figure out whether we should redirect the browser when the change is complete.
             *
             * @param {Object} networkObject Network configuration object
             * @returns {String} address to which we should redirect (or current address if no redirect wanted)
             */

            function redirectWanted(networkObject) {
                var addrs;
                manualToDhcp = false;
                if (networkObject.confOneNode) {
                    addrs = networkObject.app1Ipv4Addr;
                }
               var current = statusService.getState().usingAddr;
                // handle DHCP case

               // minimize switching between IP and hostname on redirect as it does not work in IE
               // when checking reachability
               // try to stay on the current windonw.control.host as long as possible

               // DHCP ->DHCP
                if (isDhcpIPv4Used(networkObject) && isDhcpIPv4Used(originalConfig))
                {

                    if (networkObject.hostname == originalConfig.hostname) {
                        return timerHost.location.host;
                    } else  {
                        return current;
                    }
                }
               // manual to DHCP -> redirect to hostname

                if (isDhcpIPv4Used(networkObject) && !isDhcpIPv4Used(originalConfig))  {
                    manualToDhcp = true;
                    return networkObject.hostname;
                }

                if (current == addrs ) {
                    return timerHost.location.host;
                } else {
                    return addrs;
                }
            }
            /**
             * This function updates the locale field
             * localeData contains locale info which is retrieved from the appliance.
             * @param localeData
             */
            function updateLocale(localeData){
                dispatcher.fire("localeChange",localeData);
            }

            /**
             * This function gets the locale info from the service layer and updates the locale field.
             */
            this.getLocale = function () {
                networkSetupService.getLocale({
                    success: updateLocale,
                    error: function(error) {}
                });
            };
            /**
            *
            * This function parses the date and time in Non UTC format .
            * @param data
            */
           this.parseDateTime = function(data)
           {
               /*
               * Currently date.js supports only UTC format and need is to display the
               * appliance date time in the same format it was saved .As date.js cannot
               * be used we borrowed the same logic from parseISOString .Here we parse
               * the incoming date format (yyy-MM-dd:HH:mm:ss.sss) and convert it to
               * required display format for date time.
               * Going forward it can be reconsidered putting this in date.js script
               */
               var ms = (data.length > 20) ? parseFloat(data.slice(19,23)) * 1000 : 0;
               return new Date(parseInt(data.slice(0,4), 10),
                   parseInt(data.slice(5,7), 10) - 1,
                   parseInt(data.slice(8,10), 10),
                   parseInt(data.slice(11,13), 10),
                   parseInt(data.slice(14,16), 10),
                   parseInt(data.slice(17,19), 10),
                   ms);
           };

            /**
             * This function get the date and time info from the service layer and updates the dateTime field.
             * @param data
             */
            this.getDateTime = function (handlers) {
                networkSetupService.getDateTime({
                    success : function (data) {
                        dispatcher.fire("dateAndTimeChange",data.dateTime);
                    },
                    error: function(error) {}

                });
            };

            /**
             * This function retrieves all the available list of locale's from the appliance.
             * @param handlers
             */
            this.getLocales = function(handlers)
            {
                networkSetupService.getLocales({
                    success: function(locales) {
                        handlers.success(locales);
                    },
                    error: handlers.error
                });
            };

            this.getProductConfig = function(handlers)
            {
                networkSetupService.getProductConfig({
                    success: function(productConfig) {
                        handlers.success(productConfig);
                    },
                    error: handlers.error
                });
            };

            this.setSetting = function(settingObj, handlers)
            {
                // Set settings from DB settings
                settingsService.setSetting(settingObj, {
                    success: function() {
                    },
                 error: handlers.error
                });

            };

            this.getSetting = function(name, handlers)
            {
               // Retrieve setting from DB settings
                settingsService.getSetting(name, {
                    success: function(setting) {
                        handlers.success(setting);
                    }//,
                    //error: handlers.error
                });

            };

            /**
             * This function gets the ntp servers list from the service layer and updates the ntp servers field.
             */
            this.getNTPservers = function () {
                networkSetupService.getNTPservers({
                    success: updateNTPservers,
                    error: function(error) {}
                });
            };

            /**
             * Set the desired network configuration.
             *
             * @param {Object} networkObject Network configuration object
             * @param {{success:function(redirectHost):void, error:function(ErrorInfo):void}} handlers
             *     Handlers for success and error return.  If the parameter to the success handler is set, it names the hostname
             *     or IP address to which the browser should be redirected.
             * @return {int} number of seconds that the UI should show in the progress bar
             */
            this.postNetwork = function(eth0NetworkObject,editedeth0NetworkObj,networkObjectList ,timeDto,localeDto ,serverCertificateDTO, handlers) {


                //1. get eth0 details for redirection

                originalConfig = eth0NetworkObject;
                var networkObject = editedeth0NetworkObj;

                // Figure out our new hostname.
                if(networkObject != null){

                    newHostname = redirectWanted(networkObject);

                    shouldRedirect = (((networkObject.hostname != originalConfig.hostname) ||
                        (newHostname != timerHost.location.host) ) &&
                         timerHost.location.protocol == 'https:');
                    // in addition to the redirect  we want to be more defensive for going DHCp to MANUAL and vice verse
                    shouldReload = shouldRedirect;
                }
                setConfigTimeout = NORMAL_DELAY;

                setConfigStartTime = Date.now();

                // Start the actual configuration change.
                networkSetupService.postNetwork(networkObjectList ,timeDto,localeDto,serverCertificateDTO, {

                    success: function(result,data,responseHeader) {
                        onSetConfigSuccess(result,data,responseHeader ,handlers);
                    },
                    error: function(errorInfo) {
                        onSetConfigFailed(errorInfo, handlers);
                    }
                });
            };


            /**
             * Retrieve the current network configuration.
             *
             * @param {{success:function(NetworkObject):void, error:function(ErrorInfo):void}} handlers
             *     Handlers for success and error return
             */
            this.getNetworkConfiguration = function(handlers) {
                networkSetupService.getNetworkConfiguration({
                    success: function(networkObject) {
                        originalConfig = networkObject;
                        handlers.success(originalConfig);
                    },
                    error: handlers.error
                });
            };

            /**
             * Retrieve the current network configuration.
             *
             * @param {{success:function(NetworkObject):void, error:function(ErrorInfo):void}} handlers
             *     Handlers for success and error return
             */
            this.getSelectedNetworkConfiguration = function(macAddress, handlers) {
                networkSetupService.getSelectedNetworkConfiguration(macAddress, {
                    success: function(networkObject) {
                        handlers.success(networkObject);
                    },
                    error: handlers.error
                });
            };


            /**
             * Retrieve the nics that are configured.
             *
             * @param {{success:function(NetworkObject):void, error:function(ErrorInfo):void}} handlers
             *     Handlers for success and error return
             */
            this.getConfiguredNICs = function(handlers) {
                networkSetupService.getConfiguredNICs({
                    success: function(multiNicDTO) {
                        handlers.success(multiNicDTO);
                    },
                    error: handlers.error
                });
            };

            /**
             * Retrieve the nics that are not configured.
             *
             * @param {{success:function(NetworkObject):void, error:function(ErrorInfo):void}} handlers
             *     Handlers for success and error return
             */
            this.getUnconfiguredNICs = function(handlers) {

                networkSetupService.getUnconfiguredNICs({
                    success: function(networkObjectList) {
                        handlers.success(networkObjectList);
                    },
                    error: handlers.error
                });
            };

            /**
             * Retrive the NIC Object of the server by Passing the Mac Address.
             *
             * @param {{success:function(NetworkObject):void, error:function(ErrorInfo):void}} handlers
             *     Handlers for success and error return
             */
            this.getConfiguredNIC = function(mac,handlers) {
                networkSetupService.getConfiguredNIC(mac,{
                    success: function(networkObject) {
                        handlers.success(networkObject);
                    },
                    error: handlers.error
                });
            };

            /**
             * Return whether the UI should show two nodes (vs. one).
             *
             * @param {Object} networkObject Network data from the server.
             * @param {function(boolean):void} callback Function called with the resulting two-node flag.
             */
            this.showTwoNode = function(callback) {
                if (!originalConfig.confOneNode) {
                    callback(true);
                } else if (originalConfig.twoNodeData) {
                    networkSetupService.validatePeerNode({
                        success: function() {
                            callback(true);
                        },
                        error: function(errorInfo) {
                            callback(false, errorInfo.message);
                        }
                    });
                } else {
                    callback(false);
                }
            };

            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether a fully qualified domain name is required in this network configuration.
             */
            this.fqdnRequired = function(data) {
                return data.ipv4NameServers[0] || data.ipv4NameServers[1];
            };

            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether IPv4 addresses are needed in this network configuration.
             */
            this.ipv4DataRequired = function(data) {
                return data.ipv4Type == STATIC;
            };

            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether IPv6 addresses are needed in this network configuration.
             */
            this.ipv6DataRequired = function(data) {
                return data.ipv6Type == STATIC;
            };

            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether IPv6 is in use in this network configuration.
             */
            this.ipv6Used = function(data) {
                return isIpv6Used(data);
            };

            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration needs to accommodate IPv6 DNS server addresses.
             */
            this.ipv6DNS = function(data) {
                return this.ipv6Used(data) || data.ipv6NameServers[0].indexOf(':') >= 0 || data.ipv6NameServers[1].indexOf(':') >= 0;
            };

            /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration uses DHCP.
             */
            this.dhcpUsed = function(data) {
                 return data.ipv4Type == this.DHCP || data.ipv6Type == this.DHCP;
            };
             /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration uses DHCP.
             */
            this.dhcpIPv4Used = function(data) {
                return isDhcpIPv4Used(data);
            };

             /**
             * @param {Object} data Network data from the view.
             * @return {boolean} Whether this network configuration uses DHCP.
             */
            this.dhcpIPv6Used = function(data) {
                return isDhcpIPv6Used(data);
            };
             /**
             * @return {boolean} Whether IPv6 is disabled
             */
            this.iPv6Disabled = function(data) {
                return  networkSetupService.getIPv6Disabled();
            };

            this.trapForwardingDisabled = function(data) {
                return  networkSetupService.getTrapForwardingDisabled();
            };

            this.setTrapForwardingDisabled = function(value){
                networkSetupService.setTrapForwardingDisabled(value);
            };

            /**
             * @return {boolean} Whether the second IP is used (Altair)
             */
            this.isSecondIPUsed = function() {
              return ("ipv4_2" in originalConfig.addrs.node1);
            };
            /**
             * Retrieve the certificate information
             *
             * @param {Object} handlers The success and error handler methods.
             */
            this.getCertificate = function(handlers) {
                certificateService.getCertificate({
                    success: handlers.success,
                    error: handlers.error
                });
            };

            /**
             * @param {String} priDns from the view.
             * @param {String} altDns from the view.
             * @return {boolean} Whether at least one DNS name server is specified in the view.
             */
            this.dnsServerSpecified = function(priDns, altDns) {
                if (priDns != null && priDns != '') {
                    return true;
                }
                if (altDns != null && altDns != '') {
                    return true;
                }
                return false;
            };

            /**
             * @param {String} hostname from the view.
             * @param {String} priDns from the view.
             * @param {String} altDns from the view.
             * @return {String} domain if the fully qualified hostname is specified, otherwise null.
             */
            this.getDomainName = function(hostname, priDns, altDns) {
                if (hostname == null || !this.dnsServerSpecified(priDns, altDns)) {
                     return null;
                }
                var i = hostname.indexOf('.');
                if ( i == -1) {
                    return null;
                } else {
                    return (hostname.substring (i+1, hostname.length));
                }
            };
            this.shouldReloadWindow = function() {
                return shouldReload;
            };

            this.shouldRedirect = function() {
                return shouldRedirect;
            };
           /**
             * Add a listener for a specified event.
             *
             * @public
             * @param {string} eventName The name of the event.
             * @param {function(...)} callback
             */
            this.on = function(eventName, callback) {
                dispatcher.on(eventName, callback);
            };

            /**
             * Remove a listener for the specified event.
             *
             * @public
             * @param {string} eventName The name of the event.
             * @param {function(...)} callback
             */
            this.off = function(eventName, callback) {
                dispatcher.off(eventName, callback);
            };
            /**
             * @private For unit testing only...
             */
            this._setTimerHost = function(th) {
                timerHost = th;
            };


            /**
             * @private For unit testing only...
             */
            this._setReachableHost = function(arg0,arg1,arg2) {
                checkReachable(arg0, arg1, arg2);
            }
            /**
            *
            * This function validates NTP field for valid entry based on regex matching.
            * @param value NTP field value to be validated
            */
            this.validateNTPField = function(value){
                var valid = (/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*([a-zA-Z]{1,63}|example|invalid|localhost|localdomain)$/).test(value)||//fqdn
                (/^(?:[a-zA-Z0-9][a-zA-Z0-9_\-]*?)$/.test(value))||//hostname
                (/^(([01]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\.){3}([01]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])$/.test(value))||//ipv4
                (/^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?$/.test(value))||//ipv6
                value==='';
                return valid;
            };
            
            /**
             * Parses product config file and gets the product config variables.
             * @param pageReadyHandlers
             */
            // TODO in atlas2.1 this method will be used for get list of 
            // configured and unconfigured nics.
            // TODO for caching product config variables in UI.
            this.setNICDisplay = function (pageReadyHandlers) {
            
            var nicDisplay;
            var nics = [];
            networkSetupService.getProductConfig({
                    success: function(productConfig) {
                        if (productConfig.members != null)	{
                        $.each(productConfig.members, function (i, data) {
                            if(data.name == MULTI_NIC_DISABLED_KEY && data.value == 'true')
                            {
                                multiNICDisabled = true;
                            }
                            if(data.name == MAX_NO_OF_NICS_DISPLAYED_KEY && data.value <=  maxNoOfNICsDisplayed)
                            {
                                maxNoOfNICsDisplayed = data.value;
                            }
                            if(data.name == MAX_NO_OF_NICS_SUPPORTED_DISABLED_KEY && data.value <= maxNoOfNICsSupported)
                            {
                                maxNoOfNICsSupported = data.value;
                            }
                            if(data.name == ALIAS_SUPPORTED_DISABLED_KEY)
                            {
                                aliasSupportedOld = data.value;
                                if(aliasSupportedOld != null){
                                    aliasSupportedFlag = true;
                                }
                            }
                            
                        });
                        } 
                        
                        
                        networkSetupService.getConfiguredNICs({
                                success: function(multiNicDTO) {
                                    nics = $.merge( nics, multiNicDTO.applianceNetworks );
                                    
                                    networkSetupService.getUnconfiguredNICs({
                                        success: function(networkObjectUnconfList) {
                                            nics = $.merge( nics, networkObjectUnconfList );

                                            nics = nics.sort(function(a, b) {
                                                var deviceA = a.device.toLowerCase(); 
                                                var deviceB = b.device.toLowerCase();
                                                if (deviceA < deviceB){
                                                    return -1
                                                }
                                                if (deviceA > deviceB){
                                                    return 1
                                                }
                                                        
                                                return 0 //default return value (no sorting)                                                

                                            });
                                            nicDisplay = (  maxNoOfNICsDisplayed < maxNoOfNICsSupported)? maxNoOfNICsDisplayed:maxNoOfNICsSupported;
                                            if(multiNICDisabled){
                                                singleNICEnabled = true;
                                            }else{
                                                singleNICEnabled = false;
                                            }
                                            if(nics.length > 1){
                                                singleNICEnabled = false;
                                            }else{
                                                singleNICEnabled = true;
                                            }
                                            
                                            if (nicDisplay == 1){
                                                singleNICEnabled = true;
                                            }
                                                
                                            pageReadyHandlers.success(nics,singleNICEnabled,aliasSupportedFlag,nicDisplay);
                                        },
                                        error: function(){
                                            pageReadyHandlers.success(nics,singleNICEnabled,aliasSupportedFlag,nicDisplay);
                                        }
                                    });
                                },
                                error: function(){
                                    pageReadyHandlers.success(nics,singleNICEnabled,aliasSupportedFlag,nicDisplay);
                                }
                            });
                    },
                    error: function(){
                        pageReadyHandlers.success(nics,singleNICEnabled,aliasSupportedFlag,nicDisplay);
                    }
                });
            };

        }

        return new NetworkSetupPresenter();

    }());

    return NetworkSetupPresenter;

});
