﻿/* ********************************************************** */
/* KeaneCallbackManagerPrototype declaration                  */        
/* ********************************************************** */
var KeaneCallbackManagerPrototype = function(spec) {
    // Private properties/methods.
    var 
        that = {},
        constants = spec.constants,
        popupManager = spec.popupManager,
        cacheManager = spec.cacheManager,
        handlers = [],
        response;

    // Validates the json response.
    var validateResponse = function() {
        // Defensive coding.
        if (response == null) {
            KeaneUtils.throwError("Developer message :: Callback response could not be deserialized to Json.", "Response Deserialization Error");
        }

        // Exception if expected attributes do not exist.        
        if ((response.hasOwnProperty("commandResponseInfo") !== true) ||
            (response.commandResponseInfo.hasOwnProperty("name") !== true) ||
            (response.commandResponseInfo.hasOwnProperty("data") !== true) ||
            (response.commandResponseInfo.hasOwnProperty("succeeded") !== true) ||
            (response.hasOwnProperty("commandStateCollection") !== true) ||
            (response.hasOwnProperty("domUpdateCollection") !== true) ||
            (response.hasOwnProperty("entityInfo") !== true) ||
            (response.entityInfo.hasOwnProperty("id") !== true) ||
            (response.entityInfo.hasOwnProperty("indexViolationException") !== true) ||
            (response.entityInfo.hasOwnProperty("concurrencyException") !== true) ||
            (response.hasOwnProperty("isInError") !== true) ||
            (response.hasOwnProperty("isInvalid") !== true) ||
            (response.hasOwnProperty("nameValuePairCollection") !== true) ||
            (response.hasOwnProperty("messageCollection") !== true) ||
            (response.hasOwnProperty("redirectInfo") !== true) ||
            (response.redirectInfo.hasOwnProperty("url") !== true) ||
            (response.redirectInfo.hasOwnProperty("toNewWindow") !== true)) {
            KeaneUtils.throwError("Developer message :: Callback response failed standard validation.", "Response Typecheck Error");
        }

        // Response was validated, expose to public.
        that.response = response;
    };

    // Deserializes the response from the callback arguments.
    var deserializeResponse = function(rawResponse) {
        if (rawResponse != null) {
            response = eval('(' + rawResponse + ')');
        }
        validateResponse();
    };

    // Returns the response message collection filtered by type.
    var getMessageCollection = function(messageType) {
        var result = [], message, i;
        if (response.messageCollection.length > 0) {
            for (i = 0; i < response.messageCollection.length; i++) {
                message = response.messageCollection[i];
                if (message.type === messageType) {
                    result.push(message);
                }
            }
        }
        return result;
    };

    // Processes the handlers within the collection.
    var processHandlers = function() {
        if (handlers.length > 0) {
            for (i = 0; i < handlers.length; i++) {
                handler = handlers[i];
                if (handler) {
                    handler();
                }
            }
        }
    }

    // Processes messages arising as the result of a callback response.
    var processMessages = function() {
        var messageCollection;
        // Error messages.
        messageCollection = getMessageCollection(constants.MESSAGE_TYPE_ERROR);
        if (messageCollection.length > 0) {
            popupManager.displayMessageCollection(constants.MESSAGE_TYPE_ERROR, messageCollection);
            return;
        }
        // Validation messages.
        messageCollection = getMessageCollection(constants.MESSAGE_TYPE_VALIDATION);
        if (messageCollection.length > 0) {
            popupManager.displayMessageCollection(constants.MESSAGE_TYPE_VALIDATION, messageCollection);
            return;
        }
        // Failure messages.
        messageCollection = getMessageCollection(constants.MESSAGE_TYPE_FAILURE);
        if (messageCollection.length > 0) {
            popupManager.displayMessageCollection(constants.MESSAGE_TYPE_FAILURE, messageCollection);
            return;
        }
        // Information messages.
        messageCollection = getMessageCollection(constants.MESSAGE_TYPE_INFORMATION);
        if (messageCollection.length > 0) {
            popupManager.displayMessageCollection(constants.MESSAGE_TYPE_INFORMATION, messageCollection);
            return;
        }
        // Redirect messages.
        messageCollection = getMessageCollection(constants.MESSAGE_TYPE_REDIRECT);
        if (messageCollection.length > 0) {
            popupManager.displayMessageCollection(constants.MESSAGE_TYPE_REDIRECT, messageCollection);
            return;
        }
    };

    // Processes redirects arising as the result of a callback response.
    var processRedirect = function() {
        if (response.redirectInfo.toNewWindow === true) {
            KeaneUtils.openUrl(response.redirectInfo.url);
        }
        else {
            KeaneUtils.redirectToUrl(response.redirectInfo.url);
        }
    };

    // Processes cache updates arising as the result of a callback response.
    var processCacheUpdates = function() {
        // Update entity id (if necessary).
        if (response.entityInfo.id > 0 &&
            cacheManager.entityInfo.id === 0) {
            cacheManager.updateEntityId(response.entityInfo.id);
        }
    };

    // Processes command state updates arising as the result of a callback response.
    var processCommandStateUpdates = function() {
        var commandStateInfo, i;
        for (i = 0; i < response.commandStateCollection.length; i++) {
            commandStateInfo = response.commandStateCollection[i];
            GuiController.setCommandState(commandStateInfo);
        }
    };

    // Processes command response information.
    var processCommandResponseInfo = function() {
        var commandResponseInfo = response.commandResponseInfo;
        if (commandResponseInfo.succeeded === false) {
            GuiController.processCommandFailure(commandResponseInfo.name);
        }
        else {
            GuiController.processCommandSuccess(commandResponseInfo.name);
        }
    };

    // Processes dom updates arising as the result of a callback response.
    var processDomUpdates = function() {
        var domUpdate, i;
        for (i = 0; i < response.domUpdateCollection.length; i++) {
            domUpdate = response.domUpdateCollection[i];
            switch (domUpdate.type) {
                case "AspNetTextBox":
                    updateElementValue(domUpdate.clientId, domUpdate.value);
                    updateElementForeColor(domUpdate.clientId, domUpdate.foreColor);
                    break;
                case "AspNetLabel":
                    updateElementInnerHtml(domUpdate.clientId, domUpdate.value);
                    updateElementForeColor(domUpdate.clientId, domUpdate.foreColor);
                    break;
                case "HtmlInput":
                    updateElementValue(domUpdate.clientId, domUpdate.value);
                    updateElementForeColor(domUpdate.clientId, domUpdate.foreColor);
                    break;
                case "DXTextBox":
                    updateElementValue(domUpdate.clientId + '_I', domUpdate.value);
                    updateElementForeColor(domUpdate.clientId, domUpdate.foreColor);
                    break;
                case "DXSelector":
                    updateElementValue(domUpdate.clientId, domUpdate.value);
                    updateElementForeColor(domUpdate.clientId, domUpdate.foreColor);
                    break;
                case "DXComboBox":
                    dxUpdateComboBox(domUpdate.clientId, domUpdate.value);
                    break;
                default:
                    updateElementValue(domUpdate.clientId, domUpdate.value);
                    updateElementForeColor(domUpdate.clientId, domUpdate.foreColor);
                    break;
            }
        }
    };

    // Gets a named value item contained within the response.
    var getNamedValue = function(name) {
        var result = null, i;
        if (name &&
            response &&
            response.hasOwnProperty("nameValuePairCollection")) {
            for (i = 0; i < response.nameValuePairCollection.length; i++) {
                var nameValue = response.nameValuePairCollection[i];
                if (nameValue.name === name) {
                    result = nameValue.value;
                    break;
                }
            }
        }
        return result;
    };

    // Processes a server response generated by a callback.
    var processResponse = function(rawResponse) {
        // Initialise.
        response = null;
        that.response = null;

        // Deserialize (implicitly validates).
        deserializeResponse(rawResponse);

        // Process.
        if (response) {
            processHandlers();
            processMessages();
            if (response.redirectInfo.url !== null) {
                processCommandResponseInfo();
                processRedirect();
            }
            else {
                processCacheUpdates();
                processDomUpdates();
                processCommandStateUpdates();
                processCommandResponseInfo();
            }
        }

        // Return.
        return response;
    };

    // Executes a server callback for the passed command.
    var executeCommandCallback = function(command) {
        if (command) {
            _callbackManager.PerformCallback(command.name + '||' + command.data);
        }
    };

    // Handler registration.
    var registerHandler = function(handler) {
        handlers.push(handler);
    };

    // Public properties/methods.
    that.registerHandler = registerHandler;
    that.getNamedValue = getNamedValue;
    that.executeCommandCallback = executeCommandCallback;
    that.processResponse = processResponse;

    // Return constructed object.
    return that;
}
