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

define(['hp/core/EventDispatcher', 
        'hp/services/IndexService',
        'hp/services/IndexFilter',
        'hp/core/UrlFragment',
        'hp/core/NotificationFormatter',
        'hp/services/Log'], 
function(EventDispatcher, indexService, IndexFilter, urlFragment, notificationFormatter, log) {"use strict";

    var SearchBoxPresenter = ( function() {

        // consts/statics can go here.
        //

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

            var dispatcher = new EventDispatcher();
            var global = true;
            var category = null;
            var history = {global: []}; // category -> [query, ...]
            var suggestions = [];
            var suggestionIndex = -1;
            var recentIndex = -1;
            var currentQuery = '';
            var currentGlobal = global;
            
            function currentRecents() {
                return history[(global ? 'global' : category)] || [];
            }
            
            function fireRecentsChange() {
                var recents = history[(global ? 'global' : category)];
                dispatcher.fire('recentsChange', recents);
            }
            
            function addToHistory(userQuery) {
                if (userQuery) {
                    var recents = currentRecents();
                    // see if we already have it
                    var index = recents.indexOf(userQuery);
                    if (index !== -1) {
                        recents.splice(index, 1);
                    } else {
                        recents.splice(4, 1);
                    }
                    recents.unshift(userQuery);
                    fireRecentsChange();
                }
            }
            
            function onSuggestionsChange(data) {
                var length = data.suggestions.length;
                // collapse inline links
                for (var i=0; i<length; i++) {
                    data.suggestions[i] =
                        notificationFormatter.collapseInlineLinks(data.suggestions[i]);
                }
                suggestions = data.suggestions;
                suggestionIndex = -1;
                dispatcher.fire('suggestionsChange', data);
            }

            /**
             * @public
             */
            this.init = function () {
            };
            
            this.reset = function (globalArg, userQuery) {
                currentQuery = userQuery;
                currentGlobal = globalArg;
                if (globalArg !== global) {
                    global = globalArg;
                    dispatcher.fire('scopeChange', global);
                }
            };
            
            this.currentQuery = function () {
                return currentQuery;
            };
            
            /**
             * @public
             */
            this.getSuggestions = function (userQuery, start, count) {
                var searchCategory = (global ? null : category);
                suggestions = [];
                suggestionIndex = -1;
                
                // don't bother if the query is a syntax the index service can't handle
                if (userQuery.indexOf(':') === -1) {
                    indexService.suggestions(searchCategory, userQuery,
                        start, count, {
                        success : onSuggestionsChange,
                        error : function(errorInfo) {
                            log.warn(errorInfo.errorMessage);
                        }
                    });
                }
            };
            
            this.setCategory = function (categoryArg) {
                var result = (category !== categoryArg || ! categoryArg);
                if (categoryArg !== category) {
                    category = categoryArg;
                    if (! history.hasOwnProperty(category)) {
                        history[category] = [];
                    }
                    fireRecentsChange();
                }
                return result;
            };
            
            this.isGlobal = function () {
                return global;
            };
            
            this.setGlobal = function (globalArg, userQuery) {
                if (globalArg !== global) {
                    global = globalArg;
                    fireRecentsChange();
                    if (userQuery) {
                        this.getSuggestions(userQuery, 0, 10);
                    }
                }
            };
            
            this.currentChoice = function () {
                if (suggestionIndex >= 0) {
                    return {text: suggestions[suggestionIndex],
                        suggestionIndex: suggestionIndex};
                } else if (recentIndex >= 0) {
                    return {text: currentRecents()[recentIndex],
                        recentIndex: recentIndex};
                } else {
                    return {};
                }
            };
            
            this.nextChoice = function () {
                var recents = currentRecents();
                if (-1 === recentIndex && suggestions.length > 0) {
                    // in suggestions
                    suggestionIndex += 1;
                    if (suggestionIndex >= suggestions.length) {
                        if (recents.length > 0) {
                            suggestionIndex = -1;
                            recentIndex = 0;
                        } else {
                            // stay at last one
                            suggestionIndex = suggestions.length - 1;
                        }
                    }
                } else if (recents.length > 0) {
                    // in recents
                    recentIndex += 1;
                    if (recentIndex >= recents.length) {
                        // stay at last one
                        recentIndex = recents.length - 1;
                    }
                }
            };
            
            this.previousChoice = function () {
                var recents = currentRecents();
                if (-1 !== suggestionIndex || -1 !== recentIndex) {
                    if (-1 === suggestionIndex && recents.length > 0) {
                        recentIndex -= 1;
                        if (recentIndex < 0) {
                            if (suggestions.length > 0) {
                                recentIndex = -1;
                                suggestionIndex = suggestions.length - 1;
                            } else {
                                recentIndex = -1;
                            }
                        }
                    } else if (suggestions.length > 0) {
                        suggestionIndex -= 1;
                        if (suggestionIndex < 0) {
                            suggestionIndex = -1;
                        }
                    }
                }
            };
            
            this.noChoice = function (clearSuggestions) {
                recentIndex = -1;
                suggestionIndex = -1;
                if (clearSuggestions) {
                    suggestions = [];
                }
            };
            
            this.doSearch = function (userQuery) {
                recentIndex = -1;
                suggestions = [];
                suggestionIndex = -1;
                
                if ((userQuery !== currentQuery || global !== currentGlobal) &&
                    (userQuery.length > 0 || ! global)) {
                    
                    currentQuery = userQuery;
                    currentGlobal = global;
                    addToHistory(currentQuery);
                
                    // lazily get this, because Router requires Banner,
                    // which requires SearchBoxView
                    require(['hp/core/Router'], function(router) {
                        if (global) {
                            router.go('/search?query=' + userQuery, 'search');
                        } else {
                            var location = router.location();
                            var newFilter = new IndexFilter(location);
                            newFilter.updateLocalSearchQuery(location, userQuery);
                            location = newFilter.updateLocation(location);
                            router.go(urlFragment.replaceUris(location, []), 'search local');
                        }
                    });
                }
            };
            
            /**
             * @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);
            };
            
            // For testing only
            this.clear = function () {
                history = {global: []};
                recentIndex = -1;
                suggestions = [];
                suggestionIndex = -1;
            };
        }

        return new SearchBoxPresenter();
    }());

    return SearchBoxPresenter;
});
