/**
 * @preserve Sticky Anything 2.22 | @senff | GPL2 Licensed
 */

console.error(
    "PLEASE NOTE: this is just a notification that the Sticky Menu (or Anything!) plugin is now working in Debug Mode."
);
console.error(
    "Even though this mode will not impact any functionality, do NOT use this mode in production environments!"
);

(function($) {
    $.fn.stickThis = function(options) {
        var settings = $.extend({
                // Default
                top: 0,
                minscreenwidth: 0,
                maxscreenwidth: 99999,
                zindex: 1,
                legacymode: false,
                dynamicmode: false,
                debugmode: false,
                pushup: "",
                adminbar: false,
            },
            options
        );

        var numElements = $(this).length;
        var numPushElements = $(settings.pushup).length;

        if (numPushElements < 1) {
            // There are no elements on the page with the called selector for the Push-up Element.
            if (settings.debugmode == true && settings.pushup) {
                console.error(
                    'STICKY ANYTHING DEBUG: There are no elements with the selector/class/ID you selected for the Push-up element ("' +
                    settings.pushup +
                    '").'
                );
            }
            // Resetting it to NOTHING.
            settings.pushup = "";
        } else if (numPushElements > 1) {
            // You can't use more than one element to push up the sticky element.
            // Make sure that you use a selector that applies to only ONE SINGLE element on the page.
            // Want to find out quickly where all the elements are that you targeted? Uncomment the next line to debug.
            // $(settings.pushup).css('border','solid 3px #ff0000');
            if (settings.debugmode == true) {
                console.error(
                    "STICKY ANYTHING DEBUG: There are " +
                    numPushElements +
                    ' elements on the page with the selector/class/ID you selected for the push-up element ("' +
                    settings.pushup +
                    '"). You can select only ONE element to push the sticky element up.'
                );
            }
            // Resetting it to NOTHING.
            settings.pushup = "";
        }

        if (numElements < 1) {
            // There are no elements on the page with the called selector.
            if (settings.debugmode == true) {
                console.error(
                    'STICKY ANYTHING DEBUG: There are no elements with the selector/class/ID you selected for the sticky element ("' +
                    this.selector +
                    '").'
                );
            }
        } else if (numElements > 1) {
            // This is not going to work either. You can't make more than one element sticky. They will only get in eachother's way.
            // Make sure that you use a selector that applies to only ONE SINGLE element on the page.
            // Want to find out quickly where all the elements are that you targeted? Uncomment the next line to debug.
            // $(this).css('border','solid 3px #00ff00');
            if (settings.debugmode == true) {
                console.error(
                    "STICKY ANYTHING DEBUG: There There are " +
                    numPushElements +
                    ' elements with the selector/class/ID you selected for the sticky element ("' +
                    this.selector +
                    '"). You can only make ONE element sticky.'
                );
            }
        } else {
            if (settings.legacymode == true) {
                // LEGACY MODE
                $(this)
                    .addClass("sticky-element-original")
                    .addClass("element-is-not-sticky");
                if (settings.dynamicmode != true) {
                    // Create a clone of the menu, right next to original (in the DOM) on initial page load
                    createClone(settings.top, settings.zindex, settings.adminbar);
                }
                checkElement = setInterval(function() {
                    stickItLegacy(
                        settings.top,
                        settings.minscreenwidth,
                        settings.maxscreenwidth,
                        settings.zindex,
                        settings.pushup,
                        settings.dynamicmode,
                        settings.adminbar
                    );
                }, 10);
            } else {
                // MODERN MODE
                $(this)
                    .addClass("sticky-element-original")
                    .addClass("element-is-not-sticky");
                orgAssignedStyles = cssStyles($(this)); // All original element styles, assigned by CSS.
                orgInlineStyles = $(".sticky-element-original").attr("style");
                if (orgInlineStyles == null) {
                    orgInlineStyles = "";
                }
                createPlaceholder();

                checkElement = setInterval(function() {
                    stickIt(
                        settings.top,
                        settings.minscreenwidth,
                        settings.maxscreenwidth,
                        settings.zindex,
                        settings.pushup,
                        settings.adminbar,
                        orgAssignedStyles,
                        orgInlineStyles
                    );
                }, 10);
            }
        }

        return this;
    };

    // The new StickIt function
    function stickIt(
        stickyTop,
        minwidth,
        maxwidth,
        stickyZindex,
        pushup,
        adminbar,
        originalAssignedStyles,
        originalInlineStyles
    ) {
        // We need to check the position of the ACTIVE element.
        // This is the original one when it's not sticky, but when it's sticky, it's the placeholder.
        if ($(".sticky-element-active").length < 1)
            return;
        $listenerElement = $(".sticky-element-active");

        var orgElementPos = $listenerElement.offset();
        orgElementTop = orgElementPos.top;

        if (pushup) {
            var pushElementPos = $(pushup).offset();
            pushElementTop = pushElementPos.top;
        }

        // Calculating actual viewport width
        var e = window,
            a = "inner";
        if (!("innerWidth" in window)) {
            a = "client";
            e = document.documentElement || document.body;
        }
        viewport = e[a + "Width"];

        if (adminbar && $("body").hasClass("admin-bar") && viewport > 600) {
            // below 600, the adminbar is not fixed
            adminBarHeight = $("#wpadminbar").height();
        } else {
            adminBarHeight = 0;
        }

        if (
            $(window).scrollTop() >= orgElementTop - stickyTop - adminBarHeight &&
            viewport >= minwidth &&
            viewport <= maxwidth
        ) {
            // We've scrolled PAST the original position; this is where we need to make the element sticky.

            // Placeholder element should always have same left position as original element (see comment below).
            // The sticky element will NOT have a TOP or the LEFT margin. This is because the left/top reference point of the original
            // element does not consider the margin. So, we're checking the left/top point of the actual original element and then
            // use that position for the sticky element.

            // LEFT POSITION
            coordsOrgElement = $listenerElement.offset();
            leftOrgElement = coordsOrgElement.left; // This is the position REGARDLESS of the margin.

            // WIDTH/HEIGHT
            // The placeholder needs to have the width and height of the original element, WITHOUT the margins but WITH the padding and borders
            // Whatever margins the original has, the placeholder needs to have that too.

            widthPlaceholder = $listenerElement[0].getBoundingClientRect().width;
            if (!widthPlaceholder) {
                widthPlaceholder = $listenerElement.css("width"); // FALLBACK for subpixels
            }
            heightPlaceholder = $listenerElement[0].getBoundingClientRect().height;
            if (!heightPlaceholder) {
                heightPlaceholder = $listenerElement.css("height"); // FALLBACK for subpixels
            }

            // WIDTH/HEIGHT OF STICKY ELEMENT
            // The original element though, needs to have the inner width and height of the original (non-sticky) element
            // No padding, no borders, because that will be applied later anyway, regardless of box-sizing
            widthSticky = $(".sticky-element-original").css("width");
            if (widthSticky == "0px") {
                widthSticky = $(".sticky-element-original")[0].getBoundingClientRect()
                    .width;
            }
            heightSticky = $(".sticky-element-original").height();

            // PADDING
            // If padding is percentages, convert to pixels when it becomes sticky
            // Just a leftover from the old method. We will not use padding for the placeholder
            paddingOrgElement = [
                $(".sticky-element-original").css("padding-top"),
                $(".sticky-element-original").css("padding-right"),
                $(".sticky-element-original").css("padding-bottom"),
                $(".sticky-element-original").css("padding-left"),
            ];
            paddingSticky =
                paddingOrgElement[0] +
                " " +
                paddingOrgElement[1] +
                " " +
                paddingOrgElement[2] +
                " " +
                paddingOrgElement[3];

            // MARGIN
            marginOrgElement = [
                $listenerElement.css("margin-top"),
                $listenerElement.css("margin-right"),
                $listenerElement.css("margin-bottom"),
                $listenerElement.css("margin-left"),
            ];
            marginPlaceholder =
                marginOrgElement[0] +
                " " +
                marginOrgElement[1] +
                " " +
                marginOrgElement[2] +
                " " +
                marginOrgElement[3];

            // OTHER ELEMENTS
            // if original has float, display, etc., we need to assign that to the placeholder
            // Though not as important as the width/height/margin/padding

            assignedStyles = "";
            for (var importantStyle in originalAssignedStyles) {
                if (originalAssignedStyles[importantStyle] == "inline") {
                    assignedStyles += importantStyle + ":inline-block; ";
                } else {
                    assignedStyles +=
                        importantStyle +
                        ":" +
                        originalAssignedStyles[importantStyle] +
                        "; ";
                }
            }

            // Fixes bug where height of original element returns zero
            // Is this still needed for the post-2.0 mode??
            elementHeight = 0;
            if (heightPlaceholder < 1) {
                elementHeight = $(".sticky-element-cloned").outerHeight();
            } else {
                elementHeight = $(".sticky-element-original").outerHeight();
            }

            // If scrolled position = pushup-element (top coordinate) - space between top and element - element height - admin bar
            // In other words, if the pushup element hits the bottom of the sticky element
            if (
                pushup &&
                $(window).scrollTop() >
                pushElementTop - stickyTop - elementHeight - adminBarHeight
            ) {
                stickyTopMargin =
                    pushElementTop - stickyTop - elementHeight - $(window).scrollTop();
            } else {
                stickyTopMargin = adminBarHeight;
            }

            assignedStyles +=
                "width:" +
                widthPlaceholder +
                "px; height:" +
                heightPlaceholder +
                "px; margin:" +
                marginPlaceholder +
                ";";

            $(".sticky-element-original")
                .removeClass("sticky-element-active")
                .removeClass("element-is-not-sticky")
                .addClass("element-is-sticky")
                .css(
                    "cssText",
                    originalInlineStyles + "margin-top: " +
                    stickyTopMargin +
                    "px !important; margin-left: 0 !important"
                )
                .css("position", "fixed")
                .css("left", leftOrgElement + "px")
                .css("top", stickyTop + "px")
                .css("width", widthSticky)
                .css("padding", paddingSticky)
                .css("z-index", stickyZindex);

            if (!$(".sticky-element-placeholder").hasClass("sticky-element-active")) {
                $(".sticky-element-placeholder")
                    .addClass("sticky-element-active")
                    .attr("style", assignedStyles);
            }
        } else {
            // not scrolled past the menu; only show the original element.
            $(".sticky-element-original")
                .addClass("sticky-element-active")
                .removeClass("element-is-sticky")
                .addClass("element-is-not-sticky")
                .attr("style", originalInlineStyles);
            if ($(".sticky-element-placeholder").hasClass("sticky-element-active")) {
                $(".sticky-element-placeholder")
                    .removeClass("sticky-element-active")
                    .removeAttr("style")
                    .css("width", "0")
                    .css("height", "0")
                    .css("margin", "0")
                    .css("padding", "0");
            }
        }
    }

    function createPlaceholder() {
        $(".sticky-element-original")
            .addClass("sticky-element-active")
            .before(
                '<div class="sticky-element-placeholder" style="width:0; height:0; margin:0; padding:0; visibility:hidden;"></div>'
            );
    }

    // Helper function: get the important CSS rules from an element
    function cssStyles(el) {
        o = {};

        o["display"] = el.css("display");
        o["float"] = el.css("float");
        o["flex"] = el.css("flex");
        o["box-sizing"] = el.css("box-sizing");
        o["clear"] = el.css("clear");
        o["overflow"] = el.css("overflow");
        o["transform"] = el.css("transform");

        // For some reason, this original loop doesn't work with some themes/plugins.
        // importantStyles = ['display','float','flex','box-sizing','clear','overflow','transform'];
        // for(var styleProp in importantStyles) {
        //   o[importantStyles[styleProp]] = el.css(importantStyles[styleProp]);
        // }

        return o;
    }

    // The old StickIt function
    function stickItLegacy(
        stickyTop,
        minwidth,
        maxwidth,
        stickyZindex,
        pushup,
        dynamic,
        adminbar
    ) {
        if ($(".sticky-element-original").length < 1)
            return;
        var orgElementPos = $(".sticky-element-original").offset();
        orgElementTop = orgElementPos.top;

        if (pushup) {
            var pushElementPos = $(pushup).offset();
            pushElementTop = pushElementPos.top;
        }

        // Calculating actual viewport width
        var e = window,
            a = "inner";
        if (!("innerWidth" in window)) {
            a = "client";
            e = document.documentElement || document.body;
        }
        viewport = e[a + "Width"];

        if (adminbar && $("body").hasClass("admin-bar") && viewport > 600) {
            adminBarHeight = $("#wpadminbar").height();
        } else {
            adminBarHeight = 0;
        }

        if (
            $(window).scrollTop() >= orgElementTop - stickyTop - adminBarHeight &&
            viewport >= minwidth &&
            viewport <= maxwidth
        ) {
            // scrolled past the original position; now only show the cloned, sticky element.

            // Cloned element should always have same left position and width as original element.
            orgElement = $(".sticky-element-original");
            coordsOrgElement = orgElement.offset();
            leftOrgElement = coordsOrgElement.left;
            widthOrgElement = orgElement[0].getBoundingClientRect().width;
            if (!widthOrgElement) {
                widthOrgElement = orgElement.css("width"); // FALLBACK for subpixels
            }
            heightOrgElement = orgElement.outerHeight();

            // If padding is percentages, convert to pixels
            paddingOrgElement = [
                orgElement.css("padding-top"),
                orgElement.css("padding-right"),
                orgElement.css("padding-bottom"),
                orgElement.css("padding-left"),
            ];
            paddingCloned =
                paddingOrgElement[0] +
                " " +
                paddingOrgElement[1] +
                " " +
                paddingOrgElement[2] +
                " " +
                paddingOrgElement[3];

            if (dynamic == true && $(".sticky-element-cloned").length < 1) {
                // DYNAMIC MODE: if there is no clone present, create it right now
                createClone(stickyTop, stickyZindex);
            }

            // Fixes bug where height of original element returns zero
            elementHeight = 0;
            if (heightOrgElement < 1) {
                elementHeight = $(".sticky-element-cloned").outerHeight();
            } else {
                elementHeight = $(".sticky-element-original").outerHeight();
            }

            // If scrolled position = pushup-element (top coordinate) - space between top and element - element height - admin bar
            // In other words, if the pushup element hits the bottom of the sticky element
            if (
                pushup &&
                $(window).scrollTop() >
                pushElementTop - stickyTop - elementHeight - adminBarHeight
            ) {
                stickyTopMargin =
                    pushElementTop - stickyTop - elementHeight - $(window).scrollTop();
            } else {
                stickyTopMargin = adminBarHeight;
            }

            $(".sticky-element-cloned")
                .css("left", leftOrgElement + "px")
                .css("top", stickyTop + "px")
                .css("width", widthOrgElement)
                .css("margin-top", stickyTopMargin)
                .css("padding", paddingCloned)
                .show();
            $(".sticky-element-original").css("visibility", "hidden");
        } else {
            // not scrolled past the menu; only show the original menu.
            if (dynamic == true) {
                $(".sticky-element-cloned").remove();
            } else {
                $(".sticky-element-cloned").hide();
            }
            $(".sticky-element-original").css("visibility", "visible");
        }
    }

    function createClone(cloneTop, cloneZindex) {
        $(".sticky-element-original")
            .clone()
            .insertAfter($(".sticky-element-original"))
            .addClass("sticky-element-cloned")
            .removeClass("element-is-not-sticky")
            .addClass("element-is-sticky")
            .css("position", "fixed")
            .css("top", cloneTop + "px")
            .css("margin-left", "0")
            .css("z-index", cloneZindex)
            .removeClass("sticky-element-original")
            .hide();
    }
})(jQuery);