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

define(['hp/core/EventDispatcher',
    'hp/services/IndexFilter',
    'hp/model/NotificationResource',
    'hp/core/NotificationFormatter',
    'fs/model/activity/ActivityResource',    
    'hp/model/DevelopmentSettings',
    'hp/services/Log'], 
function(EventDispatcher, IndexFilter, NotificationResource, notificationFormatter, activityResource, 
    settings, log) {"use strict";

    var ResourceNotificationsPresenter = ( function() {
      
        var STATUS_PRIORITY =
            {critical: 1, error: 1, warning: 2, ok: 3, unknown: 3, disabled: 3};
        // for internal comparison functions
        var FIRST = -1;
        var SECOND = 1;

        /**
         * @constructor
         * @type {ResourceNotificationsPresenter}
         */
        function ResourceNotificationsPresenter() {

            var dispatcher = new EventDispatcher();
            var timer = null;
            var notificationResource;
            var categoryResource;
            var enableDetails = false;
            var selectionUri = null; // for tracking preExistingOkUris
            var preExistingOkUris = null;
            
            function poll(selection) {
                var uris;
                if (selection) {
                    uris = selection.uris;
                } else {
                    uris = categoryResource.getSelection().uris;
                }
                
                if (uris && uris.length > 0) {
                    // NOTE: Doesn't work for multi-select yet
                    // Commenting this line, since "associatedResourceUri" filter is not handled in the engine which causes issue in updating the master pane status
                    /*notificationResource.filter().
                        setProperty('associatedResourceUri', uris[0]); */
                    notificationResource.getNotifications();
                }
                
                clearTimeout(timer);
                timer = setTimeout(poll, settings.getActivityRefreshInterval());
            }
            
            // choose best result to select based on this priority:
            // 1 - pending task
            // 2 - running task
            // 3 - failed task
            // 4 - critical alert
            // 5 - pending task
            // 6 - warning alert
            // 7 - completed task finishing within the last 10 minutes

            function compareNotificationStatus(a, b) {
                var result,
                    aPending = (a.state && a.state.toLowerCase() === 'pending'),
                    bPending = (b.state && b.state.toLowerCase() === 'pending');
                if (aPending !== bPending && (aPending || bPending)) {
                    result = (aPending ? FIRST : SECOND);
                } else if (a.changing !== b.changing && (a.changing || b.changing)) {
                    result = (a.changing ? FIRST : SECOND);
                } else if (a.status !== b.status) {
                    if (a.status && b.status) {   // if both statuses are defined                                       
                        result = (( STATUS_PRIORITY[a.status] <
                            STATUS_PRIORITY[b.status])? FIRST : SECOND);
                    } else if (a.status) {
                        result=FIRST;
                    } else {
                        result=SECOND;
                    }
                } else {
                    result = ((a.timestamp > b.timestamp) ? FIRST : SECOND);                    
                }
                return result;
            }
            
            function selectBest(data) {
                var notifications = data.notifications;
                var length = notifications.length;
                var index = (length > 0 ? 0 : -1);
                var notification;
                
                // don't auto select if we're expanded on a particular one
                if (!enableDetails) {
                    for (var i=0; i<length; i++) {
                        notification = notifications[i];
                        if (compareNotificationStatus(
                            notifications[index], notification) > 0) {
                            index = i;
                        }
                    }
                
                    if (index >= 0) {
                        data.selection.notification = notifications[index];
                        data.selection.index = index;
                    }
                }
            }
            
            function prune(data) {
                var length = data.notifications.length;
                var notification, latestTask = null;
                
                if (null === preExistingOkUris && data.indexQueried) {
                    // We haven't been here yet for the current selection,
                    // remember which tasks were 'ok' when we started so we
                    // can prune them out. This allows tasks that were running
                    // when we started but have since completed to be preserved.
                    preExistingOkUris = [];
                    for (var i=0; i<length; i++) {
                        notification = data.notifications[i];
                        if (notification.status &&
                            ('ok' === notification.status.toLowerCase())) {
                            preExistingOkUris.push(notification.uri);
                        }
                    }
                }
                
                data.notifications = $.grep(data.notifications,
                    function (notification) {
                        var result = true;
                        // prune out all but the latest task
                        if ('tasks' === notification.category) {
                            result = (null === latestTask);
                            latestTask = notification;
                            
                            if (result) {
                                // prune out any that were OK when we started
                                result = ($.inArray(notification.uri,
                                        preExistingOkUris) === -1);
                            }
                        }
                        return result;
                    });
            }
            
            // Resource events
            
            function onNotificationsChange(data) {
                dispatcher.fire('notificationsChange', data);
                if (enableDetails) {
                    notificationResource.getSelectionDetails();
                }
            }
            
            function onNotificationsError(errorInfo) {
                dispatcher.fire('notificationsError', errorInfo);
            }
            
            function onSelectionChange(data) {
                dispatcher.fire('selectionChange', data);
                if (enableDetails) {
                    notificationResource.getSelectionDetails();
                }
            }
            
            function onResourceChange(data) {
                dispatcher.fire('notificationChange', data.selection.notification);
            }
            
            function onResourceError(errorInfo) {
                dispatcher.fire('resourceError', errorInfo);
            }
            
            function onResourceSelectionChange(selection) {
                if (selection.uris.length > 0 &&
                    selectionUri !== selection.uris[0]) {
                    selectionUri = selection.uris[0];
                    notificationResource.clear();
                    preExistingOkUris = null;
                    poll(selection);
                }
            }
            
            function onResourceActivityChange(item) {
                poll();
            }

            /**
             * @public
             */
            this.init = function (categoryResourceArg) {
                categoryResource = categoryResourceArg;
                notificationResource = new NotificationResource();
                notificationResource.init({
                    autoSelect: selectBest,
                    preFilter: prune,
                    pruneDuplicates : true
                });
            };
            
            this.pause = function () {
                if (categoryResource) {
                    clearTimeout(timer);
                    timer = null;
                    categoryResource.off('selectionChange', onResourceSelectionChange);
                    categoryResource.off('activityChange', onResourceActivityChange);
                }
                notificationResource.off('notificationsChange', onNotificationsChange);
                notificationResource.off('notificationsError', onNotificationsError);
                notificationResource.off('selectionChange', onSelectionChange);
                notificationResource.off('resourceChange', onResourceChange);
                notificationResource.off('resourceError', onResourceError);
            };
            
            this.resume = function () {
                if (categoryResource) {
                    categoryResource.on('activityChange', onResourceActivityChange);
                }
                notificationResource.on('notificationsChange', onNotificationsChange);
                notificationResource.on('notificationsError', onNotificationsError);
                notificationResource.on('selectionChange', onSelectionChange);
                notificationResource.on('resourceChange', onResourceChange);
                notificationResource.on('resourceError', onResourceError);
            };
            
            // separate from resume() for now to handle partners who aren't
            // using pause/resume yet.
            this.poll = function () {
                if (categoryResource) {
                    categoryResource.on('selectionChange', onResourceSelectionChange);
                    poll();
                }
            };
            
            this.selectUri = function (uri) {
                notificationResource.selectUri(uri);
            };
            
            this.selectTimestamp = function (timestamp) {
                notificationResource.selectTimestamp(timestamp);
            };
            
            this.selectNext = function () {
                notificationResource.selectNext();
            };
            
            this.selectPrevious = function () {
                notificationResource.selectPrevious();
            };
            
            this.deselect = function () {
                notificationResource.deselect();
            };
            
            this.wantDetails = function (enableDetailsArg) {
                if (enableDetailsArg !== enableDetails) {
                    enableDetails = enableDetailsArg;
                    if (enableDetails) {
                        notificationResource.getSelectionDetails();
                    }
                }
            };
            
            this.add = function (notification) {
                notificationResource.add(notification);
            };
            
            this.remove = function (notification) {
                notificationResource.remove(notification);
            };
            
            this.clear = function () {
                notificationResource.clear();
            };

            this.resetActivityResourceFilters = function () {
                var filter = new IndexFilter(activityResource.getIndexFilter());
                if (filter) {
                    filter.resetToDefaults();
                    activityResource.setIndexFilter(filter);
                    activityResource.getIndexResults(); // to be handled by IndexPresenter
                }
            };
            
            /**
             * @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 ResourceNotificationsPresenter;
    }());

    return ResourceNotificationsPresenter;
});
