/*global Granite, DQM, document*/
/**
 * Layer
 *
 * DQM Validation Layer - entry point of a TouchUI DQM Validator
 * Registering dqm.Layer gives the user possibility to select "DQM Validation" from the layers dropdown.
 *
 */
(function ($, ns, dqm, channel) {
    "use strict";

    var self = {
        rootSuffix: "jcr:content"
    };

    (function () {
        function appendOverlayStylesheet() {
            var css =
                    ".cq-Overlay.dqm-is-invalid," +
                    ".cq-Overlay.is-disabled.dqm-is-invalid {" +
                    "  border-color: " + self.borderColor +
                    "}" +
                    ".cq-Overlay.dqm-is-invalid .dqm-overlay-issues," +
                    ".cq-Overlay.is-disabled.dqm-is-invalid .dqm-overlay-issues {" +
                    "  background: " + self.borderColor + " no-repeat" +
                    "}",
                head = document.head || document.getElementsByTagName("head")[0],
                style = document.createElement("style");

            style.type = "text/css";
            if (style.styleSheet) {
                style.styleSheet.cssText = css;
            } else {
                style.appendChild(document.createTextNode(css));
            }
            head.appendChild(style);
        }

        return $.ajax({
            cache: false,
            url: "/services/crownpeakdqm/layer",
            data: {
                path: Granite.HTTP.internalize(ns.getPageInfoLocation())
            },
            dataType: "json"
        }).done(function (data) {
            self.available = data.layerAvailable;
            self.borderColor = data.borderColor;
            appendOverlayStylesheet();
        });
    })();

    /**
     * Fetches the content of a side-panel skeleton and triggers validation.
     */
    function setUpSidePanel() {
        ns.ui.SidePanel.loadContent({
            selector: ".js-SidePanel-content--validation",
            path: "/apps/crownpeakdqm/touchui/jcr:content/sidepanel/validation.html"
        }).then(function () {
            ns.ui.SidePanel.showContent("js-SidePanel-content--validation");
            ns.ui.SidePanel.open(true);
            channel.trigger("dqm-revalidate");
            dqm.bindListeners();
        });
    }

    function tearDownSidePanel() {
        dqm.unbindListeners();
    }

    function isRootComponent(path) {
        return path.indexOf(self.rootSuffix, path.length - self.rootSuffix.length) !== -1;
    }

    // Code copied from Granite.author.ContentFrame.getEditables to extend default behaviour of finding editables
    function _findEditables(root) {
        var editables = [];
        // Default behaviour
        (root || ns.ContentFrame.getDocument()).find("cq").each(function (i, element) {
            var editable = new ns.Editable(element);

            // If the editable is a container, it should be re-ordered (because we always get the <cq> children before their parent)
            if (editable.isContainer()) {
              var containerPath = editable.path + "/";
              var firstChild =
                  editables.filter(function (e) {
                    return e.path.indexOf(containerPath) === 0;
                  })[0];

              if (firstChild) {
                // Insert container before its first child
                var index = editables.indexOf(firstChild);
                editables.splice(index, 0, editable);
              } else {
                // Should be unlikely due to the way we fetch the <cq> elements (children before parent)
                editables.push(editable);
              }
            } else {
              // If the editable is not a container, simply push it at the end of the array
              editables.push(editable);
            }
        });
        return editables;
    }

    /**
     * Looks up for all editables (components that can be edited on the page)
     * and inspectables (not editable components, e.g. defined in template) on current page.
     * All found inspectables are wrapped with dqm.Validatable to prevent any actions on the overlay.
     *
     * @param root
     * @returns {Array.<ns.Inspectable>}
     */
    function findEditables(root) {
        var paths = [],
            inspectables = [],
            editables = _findEditables(root);
        editables.forEach(function (editable) {
            paths.push(editable.path);
        });

        // using findInspectables from developer layer to find all inspectables,
        // filtering by path those that are already in editables array
        ns.developer.findInspectables().forEach(function (inspectable) {
            var inspectablePath = inspectable.path;
            if (paths.indexOf(inspectablePath) === -1 && !isRootComponent(inspectablePath)) {
                inspectables.push(new dqm.Validatable(inspectable.config, inspectable.dom));
            }
        });
        if (root) {
            inspectables = inspectables.filter(function () {
                return $(inspectables.dom).closest(root).length;
            });
        }
        return editables.concat(inspectables);
    }

    self.config = $.extend(true, {}, ns.edit.CONFIG, {
        _isDQMValidation: true,
        name: "DQM-Validation",
        title: "DQM Validation",
        iconClass: "coral-Icon--code",
        overlayConstructor: dqm.Overlay,
        findEditables: findEditables,
        sidePanel: {
            setUp: setUpSidePanel,
            tearDown: tearDownSidePanel
        }
    });

    dqm.Layer = ns.util.extendClass(ns.edit.Layer, {
        config: self.config,
        constructor: function () {
          dqm.Layer.super_.constructor.call(this, self.config);
        },
        isAvailable: function () {
          return self.available;
        }
    });

    channel.on("cq-layer-activated", function(e) {
        if (e.layer === "DQM-Validation") {
          ns.MsmAuthoringHelper.tearDown();
          ns.MsmAuthoringHelper.initialize();
        }
    });

    /**
     * Registers the layer in layerManager, so the user can select "DQM Validation" layer from the layer dropdown,
     * if the layer is available on given page.
     */
    ns.layerManager.registerLayer(new dqm.Layer());

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