/*global Granite, DQM, document*/
/**
 * Validation
 *
 * Responsibilities:
 *   - call validation service
 *   - postprocess validation service response
 */
(function ($, ns, dqm, channel) {
    var self = {
        revalidationTriggers: ["replace", "delete", "insertAfter", "insertBefore"],
        containers: [],
        validationDelay: 1000
    };

    function encodePath(componentPath) {
        return componentPath.split("/").map(encodeURIComponent).join("/");
    }

    /**
     * Initializes overlays of the editables that are invalid according to validation service response
     * @param componentIssues
     */
    function initializeOverlays(componentIssues) {
        for (var componentPath in componentIssues) {
            if (componentIssues.hasOwnProperty(componentPath)) {
                var editable = ns.editables.find(componentPath)[0];
                if (editable && editable.overlay) {
                    editable.overlay.setIssues(componentIssues[componentPath].issues);
                }
            }
        }
    }

    /**
     * Prepares data for the handlebars template of the side-panel
     * @param data - validation service response
     * @returns {{highlightedIssuesCount: number, generalIssuesCount: number, highlightedIssues: Array, generalIssues: Array, issuesFound: boolean}}
     */
    function postProcessErrors(data) {
        var highlightedIssuesCount = 0,
            generalIssuesCount = 0,
            highlightedIssues = [],
            generalIssues = [],
            componentIssues = {},
            inspectMarkupIndex,
            postProcessCheckpoint = function (checkpoint) {
                if (checkpoint.components) {
                    inspectMarkupIndex = 1;
                    checkpoint.components.forEach(function (component) {
                        component.name = component.id.split("/").pop();
                        component.encodedPath = encodePath(component.id);
                        component.inspectMarkupIndex = inspectMarkupIndex;
                        if (!componentIssues[component.id]) {
                            componentIssues[component.id] = {};
                            componentIssues[component.id].name = component.name;
                            componentIssues[component.id].issues = [];
                        }
                        componentIssues[component.id].issues.push(checkpoint.name);
                        inspectMarkupIndex += component.instanceCount;
                    });
                    highlightedIssues.push(checkpoint);
                    highlightedIssuesCount += checkpoint.components.length;
                } else {
                    generalIssuesCount++;
                    generalIssues.push(checkpoint);
                }
            };
        data.errors.forEach(function (error) {
            error.checkpoints.forEach(postProcessCheckpoint);
        });
        initializeOverlays(componentIssues);
        return {
            highlightedIssuesCount: highlightedIssuesCount,
            generalIssuesCount: generalIssuesCount,
            highlightedIssues: highlightedIssues,
            generalIssues: generalIssues,
            issuesFound: (highlightedIssuesCount + generalIssuesCount) > 0
        };
    }

    function onApiCallSuccess(data) {
        if (dqm.DEBUG && window.console && window.console.log) {
            window.console.log(JSON.stringify(data, null, 2));
        }
        var issues = postProcessErrors(data);
        dqm.toggleLoading(false);
        self.containers.$issues.html(dqm.templates.sidebar(issues));
        channel.trigger("dqm-issues-loaded");
    }

    function onApiCallFailure(jqXHR) {
        var errorData = dqm.handleStatusCode(jqXHR, false);
        ns.ui.helpers.notify({
            heading: errorData.title,
            content: errorData.message,
            type: ns.ui.helpers.NOTIFICATION_TYPES.ERROR,
            closable: true
        });
        // switch to Edit layer
        ns.layerManager.activateLayer("Edit");
    }

    function clearOverlays() {
        ns.editables.forEach(function (editable) {
            if (editable.overlay && editable.overlay.clearIssues) {
                editable.overlay.clearIssues();
            }
        });
    }

    function validate() {
        $.ajax({
            cache: false,
            url: "/services/crownpeakdqm/touchui",
            dataType: "json"
        })
            .done(onApiCallSuccess)
            .fail(onApiCallFailure);
    }

    // Granite.author.ContentFrame.executeCommand decoration
    var _executeCommand = ns.ContentFrame.executeCommand;
    ns.ContentFrame.executeCommand = function (path, command, data) {
        var ret = _executeCommand(path, command, data);
        if (self.revalidationTriggers.indexOf(command) > -1) {
            channel.trigger("dqm-revalidate");
        }
        return ret;
    };

    dqm.toggleLoading = function (loading) {
        if (!self.containers.length) {
            var $rail = $("#dqm-validation-rail");
            self.containers.$loader = $rail.find(".loader-container");
            self.containers.$issues = $rail.find(".issues-container");
        }
        self.containers.$loader.toggle(loading);
        self.containers.$issues.toggle(!loading);
    };

    dqm.revalidate = function () {
        if (Granite.author.layerManager._currentLayer.config._isDQMValidation) {
            dqm.toggleLoading(true);
            clearOverlays();
            validate();
        }
    };

    dqm.toggleDebug = function () {
        dqm.DEBUG = !dqm.DEBUG;
        if (window.console && window.console.log) {
            window.console.log("DQM Validation DEBUG mode " + (dqm.DEBUG ? "ON" : "OFF"));
        }
    };

    channel.on("dqm-revalidate", $.debounce(self.validationDelay, true, dqm.revalidate));

}(jQuery, Granite.author, DQM, jQuery(document)));
