// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.
/**
 * @type {AlertsPresenter}
 */
define(['fs/services/alerts/AlertsService',
    'hp/services/IndexService',
    'hp/core/Localizer',
    'hp/model/Session',
    'hp/core/Router',
    'hp/core/UrlFragment',
    'hp/services/IndexFilter',
    'hp/core/EventDispatcher',
    'hp/core/HashManager',
    'jquery',
     'lib/jquery.dateFormat'],
function(alertsService, indexService, Localizer, session,
    router, urlFragment, IndexFilter, EventDispatcher, hashManager) {"use strict";

    var AlertsPresenter = ( function() {
        var DEFAULT_STATES = ['active','locked'];
        var DEFAULT_COUNT = 25;

        /**
         * @constructor
         */
        function AlertsPresenter(resource, globalView) {

            var dispatcher = new EventDispatcher();
            var initialized = false;

            // variables used to fix duplicate request bug
            var lastAssignedUri = null;
            var lastAssignedUser = null;
            var lastStateChangeUri = null;
            var lastStateChangeVal = null;

            // variables used to determine if the filter changed
            var oldFilter = null;

            function onResetStopCount() {
                dispatcher.fire('resetStopCount');
            }

            // private
            // called when the alerts results changes
            function onIndexResultsChange(indexResults) {
               dispatcher.fire("indexResultsChange", indexResults);
            }


            // private
            // compares 2 arrays to see if they are the same
            function areSame(arr1, arr2) {
                return ($(arr1).not(arr2).length === 0 &&
                    $(arr2).not(arr1).length === 0);
            }

            function areFilterTermsSame(newTerms) {
                if(!oldFilter) {
                    return false;
                }

                return areSame(newTerms, oldFilter.terms ? oldFilter.terms : []);
            }

            // This function is created for breaking original areFilterPropertiesSame
            // function into two functions to fix sonar issue - Cyclomatic complexity.
            function areStateSeverityLifecycleSame(newProps, oldProps)
            {
                if(newProps.lifecycle !== oldProps.lifecycle) {
                    return false;
                }

                if(!areSame(newProps.severity, oldProps.severity)) {
                    return false;
                }

                if(!areSame(newProps.state, oldProps.state)) {
                    return false;
                }

                return true;
            }

            function areFilterPropertiesSame(newProps) {
                var oldProps;

                if(!oldFilter) {
                    return false;
                }

                oldProps = oldFilter.properties ? oldFilter.properties : {};

                if(!areStateSeverityLifecycleSame(newProps, oldProps))
                {
                    return false;
                }

                if(newProps.time !== oldProps.time) {
                    return false;
                }

                if(newProps.fromDate !== oldProps.fromDate) {
                    return false;
                }

                if(newProps.toDate !== oldProps.toDate) {
                    return false;
                }

                if(newProps.user !== oldProps.user) {
                    return false;
                }

                if(newProps.resourceUri !== oldProps.resourceUri) {
                    return false;
                }

                return true;
            }

            function isFilterSame(newFilter) {
                var newProps = newFilter.data.properties ? newFilter.data.properties : [],
                    newTerms = newFilter.data.terms ? newFilter.data.terms : [];

                return areFilterPropertiesSame(newProps) && areFilterTermsSame(newTerms);
            }

            // private
            // called when the selection changes
            function onSelectionChange(selection) {
                dispatcher.fire("selectionChange", selection);
            }

            // private
            // retrieves the list of alerts matching the selected filters
            function getIndexResults(handlers) {
                resource.getIndexResults(handlers);
            }

            // private
            // called when the filter value changes
            function onFilterChange(filter) {
                dispatcher.fire("filterChange", filter);
            }

            // public
            // used for retrieving the date from a month ago
            this.getDateOneMonthAgo = function() {
                var lastMonthToday = new Date();
                lastMonthToday.setMonth(lastMonthToday.getMonth() - 1);
                lastMonthToday.setDate(lastMonthToday.getDate() - 1);
                return lastMonthToday;
            };

            // private
            // retrieves the data for a given alert
            function getAlertDataImpl(uri) {
                return resource.getIndexResultForUri(uri);
            }

            // private
            // called when the filter changes
            function changeFilter(newFilter, context) {
                if (newFilter.data.properties && !isFilterSame(newFilter)) {
                    oldFilter = $.extend(true, {}, newFilter.data);
                    newFilter.data.count = DEFAULT_COUNT;
                    newFilter.data.defaultCount = DEFAULT_COUNT;
                    if (globalView) {
                        var location = newFilter.updateLocation(hashManager.getHash());
                        router.go(location, "alerts filter change");
                    } else if (resource.setIndexFilter(newFilter)) {
                        resource.getIndexResults();
                    }
                }
            }

            // private
            // sets the default filters
            function setDefaultFilters() {
                oldFilter = null;

                var newFilter = new IndexFilter(resource.getIndexFilter());
                newFilter.setUserQuery("");
                newFilter.data.terms = []; // have to do this since setUserQuery won't for ""
                newFilter.unsetProperty('state');
                newFilter.unsetProperty('user');
                newFilter.unsetProperty('severity');
                newFilter.unsetProperty('category');
                newFilter.unsetProperty('time');
                newFilter.unsetProperty('fromDate');
                newFilter.unsetProperty('toDate');
                newFilter.setProperty('state', DEFAULT_STATES);

                changeFilter(newFilter, "alerts default filter change");
            }

            // public
            // utility method used for converting the time format
            function convertISOStringToUTCTime(isoDateString) {
                var dateString = isoDateString.replace(/\D/g, " ");
                var dtparts = dateString.split(" ");
                dtparts[1]--;
                return Date.UTC(dtparts[0],dtparts[1],dtparts[2],dtparts[3],dtparts[4],dtparts[5]);
            }

            // public
            // sorts an array by date
            this.dateSort = function(a, b) {
                var aTime = convertISOStringToUTCTime(a.created);
                var bTime = convertISOStringToUTCTime(b.created);
                return aTime < bTime ? -1 : (aTime > bTime) ? 1 : 0;
            };

            // private
            // retrieves the current user logged in
            this.getCurrentUser = function() {
                return session.getUser();
            };

            /**
             * @public
             */
            this.init = function() {
                setDefaultFilters();
                resource.on("indexResultsChange", onIndexResultsChange);
                resource.on("selectionChange", onSelectionChange);
                resource.on("filterChange", onFilterChange);
                resource.on("resetStopCount", onResetStopCount);
            };

            this.pause = function () {
                initialized = false;
                lastAssignedUri = null;
                lastAssignedUser = null;
                oldFilter = null;
            };

            this.resume = function () {
            };

            // public
            // called to retrieve the state filter
            this.getStateFilter = function () {
                var filter = new IndexFilter(resource.getIndexFilter());
                var severity = null;
                var states = null;
                var user = null;
                var lifecycle = null;
                var result = [];

                if (filter) {
                    severity = filter.getProperty('severity');
                    states = filter.getProperty('state');
                    user = filter.getProperty('user');
                    lifecycle = filter.getProperty('lifecycle');
                }

                if (severity) {
                    result = result.concat(severity);
                }
                if (states) {
                    result = result.concat(states);
                }
                if (user) {
                    result.push('mine');
                }
                if(lifecycle) {
                    result.push('lifecycle');
                }
                return result;
            };

            // public
            // called to retrieve the localized list of filters to be displayed to the user
            this.getStateFilterSummary = function() {
                var values = this.getStateFilter();
                var localizedValues = [];
                $.each(values, function(index, result) {
                    localizedValues.push(Localizer.getString('fs.alerts.filter.' + result));
                });
                var result = localizedValues.join(', ');
                if (result.length === 0) {
                    result = Localizer.getString('fs.alerts.filter.all_alerts');
                }
                return result;
            };

            // public
            // called when the date filter changes
            this.setDateRange = function(fromValue, toValue) {
                var newFilter = new IndexFilter(resource.getIndexFilter());
                newFilter.setProperty('fromDate', fromValue);
                newFilter.setProperty('toDate', toValue);

                changeFilter(newFilter, "alerts filter change");
            };

            // public
            // sets the date filter
            this.setDateFilter = function(value) {
                if (value && value.length !== 0) {
                    var newFilter = new IndexFilter(resource.getIndexFilter());
                    if (value === 'all') {
                        newFilter.unsetProperty('time');
                    } else {
                        if (value === 'specificDateRange') {
                            newFilter.setProperty('fromDate', $.format.date(this.getDateOneMonthAgo().toString(), "M/dd/yyyy"));
                            newFilter.setProperty('toDate', $.format.date(new Date().toString(), "M/dd/yyyy"));
                        } else {
                            newFilter.unsetProperty('fromDate');
                            newFilter.unsetProperty('toDate');
                        }
                        newFilter.setProperty('time', value);
                    }

                    changeFilter(newFilter, "alerts filter change");
                }
            };

            // public
            // selects all uris
            this.selectAll = function(uris) {
                resource.setSelectedUris(uris);
            };

            // public
            // retrieves alerts information based on the uri provided
            this.getAlertData = function(uri) {
                return resource.getIndexResultForUri(uri);
            };

            // public
            // gets the from the AlertResource's severity
            // used for displaying the status icon
            this.getStatus = function(severity) {
                var status;
                if (severity) {
                    switch(severity) {
                        case "OK":
                            status = "ok";
                            break;
                        case "Unknown":
                            status =  "unknown";
                            break;
                        case "Disabled":
                            status =  "disabled";
                            break;
                        case "Warning":
                            status =  "warning";
                            break;
                        case "Critical":
                            status = "error";
                            break;
                    }
                }
                return status;
            };

            // public
            this.setResourceUri = function(uri) {
                var filter = new IndexFilter(resource.getIndexFilter());
                if(uri) {
                    filter.setProperty('resourceUri', "resourceUri='" + uri +"'");
                } else {
                    filter.unsetProperty('resourceUri');
                }

                if(!initialized) {
                    filter.unsetProperty('user');
                    filter.unsetProperty('severity');
                    filter.unsetProperty('lifecycle');
                    filter.unsetProperty('fromDate');
                    filter.unsetProperty('toDate');
                    filter.setProperty('state', DEFAULT_STATES);
                    filter.unsetProperty('time');
                    initialized = true;
                }
                changeFilter(filter);
            };

            // public
            // returns the currently selected alerts to the caller
            this.getSelection = function() {
                return resource.getSelection();
            };

            // public
            // used to assign a user to a specified alert
            this.assignUserToAlertByUri = function(uri, user, handlers) {
                // check if the alert is already assigned to this user
                if(getAlertDataImpl(uri).assignedToUser === user) {
                    handlers.success(null);
                } else if(uri !== lastAssignedUri || user !== lastAssignedUser) {
                    lastAssignedUser = user;
                    lastAssignedUri = uri;
                    alertsService.assignUserToAlertByUri(uri, user, handlers);
                }
            };

            // public
            // used to clear/dismiss a specific alert
            this.setAlertState = function(uri, state, handlers) {
                // check if the alert already has this state
                var alertImpl = getAlertDataImpl(uri);
                if(alertImpl && alertImpl.alertState === state) {
                    handlers.success(null);
                } else if(uri !== lastStateChangeUri || lastStateChangeVal !== state){
                    lastStateChangeUri = uri;
                    lastStateChangeVal = state;
                    alertsService.setAlertState(uri, state, handlers);
                }
            };

            // public
            // used to deleted specific alert/AlertChangeLog
            this.deleteResourceByUri = function(uri, handlers) {
               alertsService.deleteResourceByUri(uri, handlers);
            };

            // public
            // returns array of all users or just the current user
            // if the user is unauthorized to make this call
            this.getAllUsers = function(handlers)
            {
                var canRetrieveUsers = session.canViewCategory('users');
                var myHandlers = {
                    success: function(data){
                        var users = {};
                        if (data && data.members && data.members.length !== 0) {
                            $.each(data.members, function(index, user){
                                users[user.userName] = user.userName;
                            });
                        }
                        else {
                            users[session.getUser()] = session.getUser();
                        }
                        handlers.success(users);
                    },
                    error: handlers.error
                };
                // check to see if the user is authorized to get all users
                if(canRetrieveUsers) {
                    alertsService.getAllUsers(myHandlers);
                } else {
                    myHandlers.success(null);
                }

             };

            // public
            // used to add an alert note
            this.addAlertNote = function(uri, note, handlers) {
                alertsService.addAlertNote(uri, note, handlers);
            };

            // public
            // retrieves an event based on the uri passed in
            this.getEvent = function(eventUri, handlers) {
                alertsService.getEventByUri(eventUri, handlers);
            };

            // public
            // retrieves the a resource based on it's uri
            this.getIndexForResource = function(resourceUri, handlers) {
                if (resourceUri) {
                    indexService.getIndexForResource(resourceUri, handlers);
                }
            };

            this.getAlertData = getAlertDataImpl;
            this.setDefaultFilters = setDefaultFilters;
            this.getIndexResults = getIndexResults;

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

            this.off = function(eventName, callback) {
                dispatcher.off(eventName, callback);
            };
        }

        return AlertsPresenter;
    }());

    return AlertsPresenter;
});
