﻿/* ********************************************************** */
/* KeaneCommandManagerPrototype declaration                   */        
/* ********************************************************** */
var KeaneCommandManagerPrototype = function (spec) {
    // Private properties/methods.
    var     
        that = {},
        constants = spec.constants,
        cacheManager = spec.cacheManager,
        callbackManager = spec.callbackManager,
        postbackManager = spec.postbackManager,
        popupManager = spec.popupManager,
        commands = [],
        commandStack = [];

    // Removes a command from the cache by name.
    var remove = function(name) {
        var i, command, newCommands = [];
        for (i = 0; i < commands.length; i += 1) {
            command = commands[i];
            if (command.name !== name) {
                newCommands.push(command);
            }
        }
        commands = newCommands; 
    };
        
    // Removes a command from the command stack by name.
    var removeFromStack = function(name) {
        var i, command, newStack = [];
        for (i = 0; i < commandStack.length; i += 1) {
            command = commandStack[i];
            if (command.name !== name) {
                newStack.push(command);
            }
        }
        commandStack = newStack; 
    };

    // Command retrieval from cache by name.
    var getCommand = function(name) {
        var result, i, command;
        if (name) {
            for (i = 0; i < commands.length; i += 1) {
                command = commands[i];
                if (command.name === name) {
                    result = command;
                    break;
                }
            }
        }
        return result;
    };

    // Sets the state of the command.
    var setCommandState = function(commandStateInfo) {
        var command;
        if (commandStateInfo) {
            command = getCommand(commandStateInfo.name)
            if (command) {                
                command.setState(commandStateInfo.state);
            }
        }
    };

    // Determines whether the command is supported.
    var isSupported = function(name) {
        var result = false;
        if (getCommand(name)) {
            result = true;
        }
        return result;
    };
    
    // Command registration.
    var register = function(command) {
        if (isSupported(command.name) === true) {
            remove(command.name);
        }
        commands.push(command);
    };

    // Processes the command after an invocation.
    var processPostInvoke = function(command)
    {
        if (command) {
            if (command.isInError === false) {
                command.onInvoked();
            }
            else {
                command.onInvokedFailure();
            }                        
        }
    };
    
    // Command execution (in 3 phases).
    var execute = function(command) {
        command.isInError = false;
        if (command.invokeMode === constants.INVOKE_MODE_SERVER_CALLBACK) {
            command.onInvoking();
            commandStack.push(command);
            command.onInvoke();
        }
        else if (command.invokeMode === constants.INVOKE_MODE_SERVER_POSTBACK) {
            command.onInvoking();
            command.onInvoke();
        }
        else if (command.invokeMode === constants.INVOKE_MODE_CLIENT_JSHANDLER) {
            command.onInvoking();
            command.onInvoke();
            processPostInvoke(command);
        }
    };
    
    // Command invocation confirmation event handler.
    var onConfirmation = function() {
        var command = commandStack.pop();
        if (command) {
            execute(command);
        }
    };

    // Command invocation confirmation cancellation event handler.
    var onConfirmationCancel = function() {
        commandStack.pop();
    };

    // Command invocation confirmation.
    var confirm = function(command) {
        commandStack.push(command);
        GuiController.onCommandConfirmation = onConfirmation;
        GuiController.onCommandCancellation = onConfirmationCancel;
        command.displayConfirmationMessage();
    };
    
    // Command invocation.
    var invoke = function(name, data) {
        var command = getCommand(name);
        if (command) {
            command.setData(data);
            // If validation fails then display validation message.
            // NOTE - validateInvoke should return a validation code.
            var validationErrorCode = command.validateInvoke();
            if (validationErrorCode >= 0) { 
                command.onValidationError(validationErrorCode);    
            }
            else {      
                // Either confirm or execute as appropriate.                
                if (command.requiresConfirmation()) {
                    confirm(command);
                } 
                else {
                    execute(command);
                }
            }
        }
    };
    
    // Event handler for when a command is invoked.
    var onCommandInvoked = function(name, errorState) {
        var command;
        // Get from collection (ensuring it is removed from stack).
        if (name) {
            command = getCommand(name);        
            if (command) {
                removeFromStack(name);
            }
        }
        if (!command) {
            command = commandStack.pop();        
        }       
        // Set error status and process post invoke.
        if (command) {
            command.isInError = errorState;
            processPostInvoke(command);            
        }
    };

    // Event handler for when a command suceeds.
    var onSuccess = function(name) {
        onCommandInvoked(name, false);
    };
    
    // Event handler for when a command fails.
    var onFailure = function(name) {
        onCommandInvoked(name, true);
    };   
   
    // Refreshes the state of the UI for all commands.
    var refreshUI = function() {
        var i, command;
        for (i = 0; i < commands.length; i += 1) {
            command = commands[i];
            if (command.refreshUI) {
                command.refreshUI();
            }
        }
    };   

    // Standard initialisation routine.
    var initialise = function() {
        var i, command, commandInfo, commandInfoCollection, commandState, commandStateCollection;
        
        // Initialise commands via collection held in cache.
        commandInfoCollection = cacheManager.getCommandInfoCollection();
        if (commandInfoCollection) {
            for (i = 0; i < commandInfoCollection.length; i++) {
                commandInfo = commandInfoCollection[i];
                if (commandInfo) {
                    command = KeaneCommandPrototype( { info : commandInfo , constants : constants, cacheManager : cacheManager, callbackManager : callbackManager, postbackManager : postbackManager, popupManager : popupManager } );
                    register(command);
                }
            }
        }
        cacheManager.clearCommandInfoCollection();

        // Initialise command states via collection held in cache.
        commandStateCollection = cacheManager.getCommandStateCollection();
        if (commandStateCollection) {
            for (i = 0; i < commandStateCollection.length; i++) {
                setCommandState(commandStateCollection[i]);
            }
        }
        cacheManager.clearCommandStateCollection();
    };    
    
    // Performs page load tasks.
    var onPageLoad = function() {
        if (cacheManager && 
            cacheManager.pageLoadCommand) {
            invoke(cacheManager.pageLoadCommand, cacheManager.pageLoadCommandData);
        }
    };   
    
    // Public properties/methods.
    that.initialise = initialise;
    that.onPageLoad = onPageLoad;
    that.getCommand = getCommand;
    that.setCommandState = setCommandState;
    that.refreshUI = refreshUI;
    that.invoke = invoke;
    that.register = register;
    that.onFailure = onFailure;
    that.onSuccess = onSuccess;

    // Return constructed object.
    return that;
};