// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.

define(['fs/services/alerts/AlertsService',
    'fs/model/activity/ActivityResource',
    'hp/core/EventDispatcher',
    'hp/model/Session',
    'hp/core/NotificationFormatter',
    'hp/core/Localizer',
    'hp/model/DevelopmentSettings'],
function(service, resource, EventDispatcher, session, notificationFormatter,
    localizer, settings) {"use strict";

    var ActivityAlertPresenter = ( function() {

        /**
         * @constructor
         * @type {ActivityPresenter}
         */
        function ActivityAlertPresenter() {

            var dispatcher = new EventDispatcher();
            var expandedAlerts = {}; // alert uri -> true
            var expandedAlertCount = 0;
            var expandedEvents = {}; // event uri -> true
            var expandedEventCount = 0;
            var alertToEventUris = {}; // map alert uri to its eventUri
            var timer = null;
            var pendingReplies = 0;

            var batchHandlers = {
                success: function () {
                    pendingReplies -= 1;
                    if (0 === pendingReplies) {
                        // refresh in case our filter needs it
                        resource.getIndexResults();
                    }
                },
                error: function () {
                    pendingReplies -= 1;
                    if (0 === pendingReplies) {
                        // refresh in case our filter needs it
                        resource.getIndexResults();
                    }
                }
            };

            function compareNotes(a, b) {
                return ((a.created > b.created) ? -1 :
                    ((a.created < b.created) ? 1 : 0));
            }

            function denoteCurrentUsersNotes(notes) {
                var length = notes.length;
                var user = session.getUser().toLowerCase();
                for (var i=0; i<length; i++) {
                    var note = notes[i];
                    if (note.userEntered && note.username.toLowerCase() === user) {
                        note._currentUser = true;
                    }
                }
            }

            function onAlertSuccess(alert) {
                // only if not removed
                if (expandedAlerts[alert.uri]) {
                    // sort notes by time
                    alert.changeLog.sort(compareNotes);
                    denoteCurrentUsersNotes(alert.changeLog);
                    // format notification
                    alert._notification = {category: 'alerts',
                        sourceCategory: alert.associatedResource.resourceCategory};
                    notificationFormatter.format(alert._notification, alert);
                    
                    // connect alert Uri with corresponding event URI 
                   
                    if (alert.associatedEventUris && (alert.associatedEventUris.length > 0)) {
                        alertToEventUris[alert.uri] = alert.associatedEventUris[0];
                    }
                    dispatcher.fire('alertChange', alert);
                    // update Event details without waiting for a timer to do so 
                    if (alertToEventUris[alert.uri]) {  
                        getEvent(alertToEventUris[alert.uri]);
                    }
                }
            }

            function getAlert(uri) {
                service.getEventByUri(uri, {
                    success: onAlertSuccess,
                    error: function (errorInfo) {
                        // TBD
                    }
                });
            }

            function eventDetailNameComparison(a, b) {
                return ((a.eventItemName.toLowerCase() <
                        b.eventItemName.toLowerCase()) ? -1 :
                    ((a.eventItemName.toLowerCase() >
                        b.eventItemName.toLowerCase()) ? 1 : 0));
            }

            function getEvent(uri) {
                service.getEventByUri(uri, {
                    success: function (event) {
                        // only if not removed
                        if (expandedEvents[uri]) {
                            // sort details by name
                            event.eventDetails.sort(eventDetailNameComparison);
                            dispatcher.fire('eventChange', event);
                        }
                    },
                    error: function (errorInfo) {
                        // TBD
                    }
                });
            }

            function getExpanded() {                
                clearTimeout(timer);
                timer = null;
                $.each(expandedAlerts, function (uri, ignore) {                   
                    getAlert(uri);
                });
                
                // no need to get events here as onAlertSuccess will do getEvent
                if (expandedAlertCount > 0) {
                    timer = setTimeout(getExpanded,
                        settings.getRefreshInterval());
                }
            }

            /**
             * Retrieves index results based on the URIs passed in.  If no URIs are specified,
             * ActivityResource is queried for the currently selected uris first.  These index results
             * are then split into 'usable' and 'ignore' based on which ones are alerts and match
             * the state specified.
             */
            function getResultsForState(state, ignoreLifecycle, uris) {
                if (! uris) {
                    uris = resource.getSelection().uris;
                }
                var length = uris.length;
                var result = {usable: [], ignore: []};

                for (var i=0; i<length; i++) {
                    var indexResult = resource.getIndexResultForUri(uris[i]);
                    if ('alerts' !== indexResult.category.toLowerCase() ||
                        (state && state.toLowerCase() !==
                            indexResult.state.toLowerCase()) ||
                        (ignoreLifecycle &&
                            'true' === indexResult.attributes.lifeCycle)) {
                        result.ignore.push(indexResult);
                    } else {
                        result.usable.push(indexResult);
                    }
                }

                return result;
            }

            function setState(uri, state) {
                pendingReplies += 1;
                service.setAlertState(uri, state, batchHandlers);
            }

            function changeSelectedState(oldState, newState) {
                var split = getResultsForState(oldState);
                var uri, length = split.usable.length;
                pendingReplies += length;
                for (var i=0; i<length; i++) {
                    uri = split.usable[i].uri;
                    service.setAlertState(uri, newState, batchHandlers);
                }
            }

            /**
             * @public
             */
            this.expandAlert = function (uri) {
                expandedAlerts[uri] = true;
                expandedAlertCount += 1;
                getAlert(uri);
                if (! timer) {
                    timer = setTimeout(getExpanded,
                        settings.getRefreshInterval());
                }
            };

            this.collapseAlert = function (uri) {
                delete expandedAlerts[uri];
                expandedAlertCount -= 1;
                
                if ((expandedEvents[uri]) && (alertToEventUris[uri]) ) {              
                    collapseEvent(alertToEventUris[uri]);      
                }                
                delete alertToEventUris[uri];
                           
            };

            this.expandEvent = function (uri) {
                if (! expandedEvents[uri]) {
                    expandedEventCount += 1;
                }
                expandedEvents[uri] = true;
                getEvent(uri);
            };
            
             this.collapseEvent = function (uri) {
                delete expandedEvents[uri];
                expandedEventCount -= 1;
            };            

            this.createNote = function (uri, note) {
                service.addAlertNote(uri, note, {
                    success: function () {
                        getAlert(uri); // re-get
                    },
                    error: function () {
                        // TBD
                    }
                });
            };

            this.deleteNote = function (alertUri, noteUri) {
                service.deleteAlertNote(noteUri, {
                    success: function () {
                        getAlert(alertUri); // re-get
                    },
                    error: function () {
                        // TBD
                    }
                });
            };

            this.getResultsForState = getResultsForState;
            
            this.changeState = function (uri, state) {
                setState(uri, state);
            };

            this.clear = function (uri) {
                setState(uri, 'Cleared');
            };

            this.clearSelected = function () {
                changeSelectedState('Active', 'Cleared');
            };

            this.restoreSelected = function () {
                changeSelectedState('Cleared', 'Active');
            };
            
            // used to assign a user to the alerts with the specified uris
            this.assignUserToAlertByUris = function (uris, owner) {
                // TODO: mass assign instead of one by one
                var uri, length = uris.length;
                var unassigned = localizer.getString('fs.activity.unassigned');
                if (owner === unassigned) {
                    owner = null;
                }
                pendingReplies += length;
                for (var i=0; i<length; i++) {
                    uri = uris[i];
                    service.assignUserToAlertByUri(uri, owner, batchHandlers);
                }
            };

            // used to assign a user to the alert with the specified uri
            this.assignUserToAlertByUri = function (uri, owner) {
                var unassigned = localizer.getString('fs.activity.unassigned');
                if (owner === unassigned) {
                    owner = null;
                }
                service.assignUserToAlertByUri(uri, owner, {
                    success: function () {
                        // refresh in case our filter needs it
                        resource.getIndexResults();
                    },
                    error: function () {
                        // TBD
                    }
                });
            };

            this.getPotentialOwners = function (query, handlers, includeUnassigned, includeAssignOther) {
                service.getOwners({
                    success: function(data){
                        var names = [];
                        var sessionUser = session.getUser();
                        var regexp = new RegExp(query, 'i');
                        if (data && data.members && data.members.length !== 0) {
                            $.each(data.members, function(index, user) {
                                if (user.match(regexp)) {
                                    names.push({name: user});
                                }
                            });
                        }
                        else {
                            if (sessionUser.match(regexp)) {
                                names.push({name: sessionUser});
                            }
                        }
                        if (includeUnassigned) {
                            //should be the first item in the list
                            names.unshift({name: localizer.getString('fs.activity.unassigned')});
                        }
                        if (includeAssignOther) {
                            //should be the last item in the list
                            names.push({
                                name: localizer.getString('fs.activity.assignOther'),
                                ignore: true
                            });
                        }

                        handlers.success(names);
                    },
                    error: handlers.error
                });
            };

            this.getOwner = function (uris, handlers) {
                if (uris && uris.length === 1) {
                    service.getEventByUri(uris[0], {
                        success: function (alert) {
                            handlers.success(alert.assignedToUser);
                        },
                        error: function (errorInfo) {
                            handlers.error(errorInfo);
                        }
                    });
                } else {
                    handlers.success(null);
                }
            };

            this.pause = function () {
                clearTimeout(timer);
                timer = null;                
            };

            this.resume = function () {
                if (expandedAlertCount > 0) {
                    timer = setTimeout(getExpanded,
                        settings.getActivityRefreshInterval());
                }
            };

            this.init = function () {
            };

            /**
             * @public
             * Add a listener for a specified event.
             * @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 new ActivityAlertPresenter();
    }());

    return ActivityAlertPresenter;
});
