// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.
/**
 * @type {Pager}
 *
 * Manages the lifecycle of dynamically loading and removing DOM elements
 * corresponding to routes and their associated views.
 */
define(['hp/model/DevelopmentSettings',
    'hp/services/Log',
    'hp/core/Localizer',
    'jquery'],
function (developmentSettings, Log, Localizer) { "use strict";

    var Pager = (function () {
      
        var ACTIVE = 'hp-active';
      
        function Pager() {
      
            var elements = {}; // [id] = {page and view}
            var activeElements = {}; // [containerId] = {page and view}
            var spinners = {}; // [containerId] = $(spinnerId)
            var watchers = {}; // [containerId] = [{pause: func, resume: func}, ...]
            
            function log(message) {
                if (false || developmentSettings.routingLogLevel() > 0) {
                    Log.log('PAGER: ' + message);
                }
            }
            
            function findSpinner(containerId) {
                var spinner = spinners[containerId];
                
                if (! spinner) {
                    spinner = $(containerId + ' > .hp-spinner');
                    spinners[containerId] = spinner;
                }
                return spinner;
            }
            
            function pauseWatchers(containerId) {
                if (watchers[containerId]) {
                    $.each(watchers[containerId], function (index, handlers) {
                        if (handlers.pause) {
                            handlers.pause($(containerId));
                        }
                    });
                }
            }
            
            function resumeWatchers(containerId) {
                if (watchers[containerId]) {
                    $.each(watchers[containerId], function (index, handlers) {
                        if (handlers.resume) {
                            handlers.resume($(containerId));
                        }
                    });
                }
            }
            
            function deactivate(containerId) {
                var activeElement = activeElements[containerId];
                
                pauseWatchers(containerId);
                
                if (activeElement) {
                    if (activeElement.view && activeElement.view.pause) {
                        log("pause " + activeElement.context);
                        activeElement.view.pause();
                    }
                    delete activeElements[containerId];
                }
                
                $(containerId).removeClass(ACTIVE).children().detach();
            }

            this.unloadElement = function(containerId, newId) {
                var spinner = findSpinner(containerId);
                
                log("unload " + containerId);
                
                deactivate(containerId);
                
                if ('#hp-change-page-container' === containerId) {
                    $('#hp-overlay').removeClass(ACTIVE + ' hp-changing');
                }
                if ('#hp-dialog-container' === containerId) {
                    $('#hp-dialog-overlay').removeClass(ACTIVE + ' hp-changing');
                }
                
                // if we don't have an element yet, assume it will take a while to get
                if ((! newId || ! elements[newId]) && spinner.length) {
                    $(containerId).append(spinner);
                }
            };
        
            this.loadElement = function(containerId, id, page, view) {
                var element, activeElement, context, viewName;
                
                element = elements[id];
                if (! element) {
                    if (view) {
                        // IE doesn't have the ability to get the name like this
                        if(view.constructor) {
                            viewName = view.constructor.name;
                        }else{
                            viewName = 'un-nameable view';
                        }
                    } else {
                        viewName = 'no view';
                    }
                    context = id + " at " + containerId + " with " + viewName;
                    element =  {context: context, page: $(page), view: view};
                    elements[id] = element;
                    Localizer.localizeDom(element.page);
                }
                
                activeElement = activeElements[containerId];
                
                // only if we're changing
                if (activeElement !== element) {
                  
                    findSpinner(containerId); // in case we load without unloading first
                    
                    deactivate(containerId);
                
                    if ($(containerId).length === 0) {
                        Log.error("Unable to find container " + containerId);
                    }
                    $(containerId).append(element.page).addClass(ACTIVE);
                    
                    // Special case the page change container
                    // to work around IE problems :(
                    if ('#hp-change-page-container' === containerId) {
                        $('#hp-overlay').addClass(ACTIVE + ' hp-changing');
                    }
                    if ('#hp-dialog-container' === containerId) {
                        $('#hp-dialog-overlay').addClass(ACTIVE + ' hp-changing');
                    }
                    
                    if (element.view) {
                        if (! element.initialized) {
                            if (element.view.init) {
                                log("init " + element.context);
                                element.view.init();
                            }
                            element.initialized = true;
                        } else if (element.view.resume) {
                            log("resume " + element.context);
                            element.view.resume();
                        }
                    } else {
                        log("loaded " + element.context + " without a view");
                    }
                    
                    resumeWatchers(containerId);
                
                    activeElements[containerId] = element;
                } else {
                    log("already at " + element.context);
                }
            };
            
            /**
             * Registers handlers that will be called when the container
             * contents are changed.
             * handlers: {pause: function, resume: function}
             * The pause function is called after the view has been paused.
             * The resume function is called before the view is resumed.
             */
            this.watch = function (containerId, handlers) {
                if (! watchers[containerId]) {
                    watchers[containerId] = [];
                }
                watchers[containerId].push(handlers);
            };
        }
        
        return new Pager();
    }());
    
    return Pager;
});
