/*jshint esversion: 6 */
////
// Plugin - breadcrumb
// adds the functionality for an interactive breadcrumb navigation
//
//this plugin makes use of the jquery UI plugin
//
// @author OstrickiDa
//
(function(){
    // Constructor
    (BreadcrumbHandler = function(element, options) {
        this.root = jQuery(element);
        // Merge options with default values
        this.settings = jQuery.extend({}, this.defaultValues, options || {});
        this.init();
    }).prototype = {

        outerContainerDiv : null,
        innerContainerDiv : null,
        lastRequest : null,

        defaultValues : {
            'hideMenuOnDocumentClick' : 	true,

            'elementOuterContainerSelector' : 	'#breadcrumbOuterContainer',
            'elementInnerContainerSelector' : 	'#breadcrumbInnerContainer',

            'elementWrapperSelector' : 	'.BreadcrumbElement',
            'linkWrapperSelector' : 	'.BreadcrumbAncestor',
            'childrenButtonSelector' : 	'.BreadcrumbChildButton',

            'childrenOuterContainerSelector' : '.BreadcrumbChildList',

            'childrenButtonClass_Unselected' : 	'BreadcrumbButtonUnselected',
            'childrenButtonClass_Selected' 	 : 	'BreadcrumbButtonSelected',

            'childrenSuccessorHighlightClass'	:	'BreadcrumbActiveSuccessor',
            'childLinkSelectorPattern'		 	:	'#breadcrumb_child_%childNodeId% a'
        },

        /* ****************************************************************
         * 						initialization
         * ***************************************************************/

        init : function() {
            this.outerContainerDiv = this.findUniqueElement(this.root,this.settings['elementOuterContainerSelector']);
            this.innerContainerDiv = this.findUniqueElement(this.root,this.settings['elementInnerContainerSelector']);

            var breadcrumbElements = this.getAllBreadcrumbElements();

            for (var i = 0; i < breadcrumbElements.length; i++){
                var breadcrumbElement = jQuery(breadcrumbElements[i]);
                var childButton = this.getChildButtonOfBreadcrumbElement(breadcrumbElement);

                if(!childButton) {
                    continue;
                }

                var nodeId = this.readNodeIdFromBreadcrumbElement(breadcrumbElement);

                childButton.on('click', {
                    "node": nodeId
                }, jQuery.proxy(this.childButtonClicked, this));
            }

            if (this.settings['hideMenuOnDocumentClick'] && this.settings['hideMenuOnDocumentClick'] === true){
                jQuery(document).on('click touchstart onmsgesturestart', jQuery.proxy(function(e){
                    // cancel requests in progress
                    this.lastRequest = null;
                    // deactivate button and close child lists
                    for (const breadcrumbObject of this.getAllBreadcrumbElements()) {
                        const breadcrumbElement = jQuery(breadcrumbObject);
                        if (this.isBreadcrumbElementSelected(breadcrumbElement)) {
                            this.closeChildListBox(breadcrumbElement);
                        }
                    }
                }, this));
            }

            this.innerContainerDiv.on('click touchstart onmsgesturestart', function(event){
                event.stopPropagation();
            });

        },


        /* ****************************************************************
         * 							events
         * ***************************************************************/
        childButtonClicked : function (event) {

            var clickedNodeId = event.data.node;

            for (const breadcrumbObject of this.getAllBreadcrumbElements()) {
                const breadcrumbElement = jQuery(breadcrumbObject);
                if (this.isBreadcrumbElementSelected(breadcrumbElement)) {
                    this.closeChildListBox(breadcrumbElement);
                } else if (clickedNodeId === this.readNodeIdFromBreadcrumbElement(breadcrumbElement)) {
                    this.openChildListBox(breadcrumbElement, clickedNodeId);
                }
            }

            event.stopPropagation();
        },

        /* ****************************************************************
         * 						general behaviour
         * ***************************************************************/

        openChildListBox : function (breadcrumbElement, nodeId) {
            var childButtonElement = this.getChildButtonOfBreadcrumbElement(breadcrumbElement);
            this.activateChildButton(childButtonElement);
            this.lookupChildren(breadcrumbElement, nodeId);
        },

        closeChildListBox : function (breadcrumbElement) {
            var childButtonElement = this.getChildButtonOfBreadcrumbElement(breadcrumbElement);
            this.deactivateChildButton(childButtonElement);
            var childListElement = this.getChildListOfBreadcrumbElement(breadcrumbElement);
            this.hideChildList(childListElement);
        },

        activateChildButton: function(button) {
            if (!button) {
                return;
            }
            button.removeClass(this.settings.childrenButtonClass_Unselected);
            button.addClass(this.settings.childrenButtonClass_Selected);
        },

        deactivateChildButton: function(button) {
            if (!button) {
                return;
            }
            button.removeClass(this.settings.childrenButtonClass_Selected);
            button.addClass(this.settings.childrenButtonClass_Unselected);
        },

        lookupChildren : function (breadcrumbElement, nodeId) {

            var uri = this.getLookupUrl(breadcrumbElement);

            var lastRequestID = Math.floor((Math.random()*64000)+1);
            this.lastRequest = lastRequestID;

            jQuery.ajax({
                type : 'GET',
                url : uri,
                dataType : 'html',
                success :  jQuery.proxy(function(data){
                    this.handleChildrenResponseSuccess(data, nodeId, lastRequestID);
                }, this),
                error :    jQuery.proxy(function(data){
                    this.handleChildrenResponseError(data, nodeId, lastRequestID);
                }, this)
            });
        },

        handleChildrenResponseSuccess : function (html, nodeId, lastRequestID) {

            //ignore response -> another request has been triggert after that one
            if(lastRequestID != this.lastRequest){
                this.log('Discarded breadcrumb lookup request -> a newer request is in progress');
                return;
            }

            this.insertHtmlFromResponse(html,nodeId);
            this.highlightSuccessor(nodeId);
        },

        handleChildrenResponseError : function (data, nodeId, lastRequestID) {

            //ignore response -> another request has been triggert after that one
            if(lastRequestID != this.lastRequest){
                this.log('Discarded breadcrumb lookup request -> a newer request is in progress');
                return;
            }

            this.log('Breadcrumb lookup request failed.');

            //if server down do nothing
            //TODO maybe show a JS error message
            if(data.responseText && data.responseText != ""){
                var html = data.responseText;
                this.insertHtmlFromResponse(html,nodeId);
            }
        },

        insertHtmlFromResponse : function (html, nodeId) {
            var breadcrumbElement = this.getBreadcrumbElement(nodeId);

            var childrenOuterDiv = this.showChildList(breadcrumbElement, html);

            this.positionChildrenListRelativeToLink(breadcrumbElement, childrenOuterDiv);
        },

        highlightSuccessor: function (nodeId) {

            var highlightingClass = this.settings['childrenSuccessorHighlightClass'];
            var childLinkSelector = this.settings['childLinkSelectorPattern'];

            if(highlightingClass && childLinkSelector){

                var currentBreadcrumbElement = this.getBreadcrumbElement(nodeId);

                if(currentBreadcrumbElement){

                    var successingBreadcrumbElement =  currentBreadcrumbElement.next(this.settings['elementWrapperSelector'])[0];

                    if(successingBreadcrumbElement){

                        var sucessorNodeId = this.readNodeIdFromBreadcrumbElement(successingBreadcrumbElement);

                        childLinkSelector = childLinkSelector.replace('%childNodeId%', sucessorNodeId);

                        var successorChildElement = this.findUniqueElement(
                            this.root,
                            childLinkSelector
                        );
                        if(successorChildElement){
                            successorChildElement.addClass(highlightingClass);
                        }
                    }
                }
            }
        },


        positionChildrenListRelativeToLink : function (mainElement, childrenListElement) {
            var mainElementX = mainElement.position().left;
            var mainElementWidth = mainElement.outerWidth();
            var childrenListElementWidth = childrenListElement.outerWidth(true);

            childrenListElement.css({
                left: `${Math.round(mainElementX + mainElementWidth)}px`,
            });

            //fix for ipad -> never go above the 1024px -> outside the windowWidth
            if(!this.elementFullyVisibleInViewport(childrenListElement)){
                var outerContainerWidth = this.outerContainerDiv.outerWidth();
                x = outerContainerWidth - childrenListElementWidth - 10;
                childrenListElement.css({
                    'left': Math.round(x)+'px'
                });
            }
        },

        hideChildList : function (childListElement) {
            if(childListElement){
                childListElement.removeClass('BreadcrumbChildrenVisible');
                childListElement.off('click touchstart onmsgesturestart');
            }
        },

        showChildList : function (breadcrumbElement, htmlContent) {
            var childrenOuterDiv = this.findUniqueElement(
                breadcrumbElement,
                this.settings.childrenOuterContainerSelector
            );
            childrenOuterDiv.html(htmlContent);
            childrenOuterDiv.addClass('BreadcrumbChildrenVisible');

            childrenOuterDiv.on('click touchstart onmsgesturestart', function(event){
                event.stopPropagation();
            });

            return childrenOuterDiv;
        },

        /* ****************************************************************
         * 						  help functions
         * ***************************************************************/

        log : function (msg) {
            if(window.console && window.console.log){
                window.console.log(msg);
            }
        },

        isSafariIPad : function() {
            var os = navigator.userAgent;
            return (os.indexOf("Mac") != -1 && os.indexOf("Safari") != -1 && os.indexOf("AppleWebKit") != -1 && os.indexOf("Chrome") == -1);
        },

        findUniqueElement : function (parent, cssSelector) {
            var elements = parent.find(cssSelector);
            if(elements.length > 0){
                return jQuery(elements[0]);
            }else{
                return null;
            }
        },

        getAllBreadcrumbElements : function () {
            return this.root.find(this.settings['elementWrapperSelector']);
        },

        getBreadcrumbElement : function (nodeId) {
            return this.findUniqueElement(
                this.root,
                '#breadCrumb_node_'+nodeId
            );
        },

        getChildButtonOfBreadcrumbElement : function (breadcrumbElement) {
            return this.findUniqueElement(
                breadcrumbElement,
                this.settings['childrenButtonSelector']
            );
        },

        getChildListOfBreadcrumbElement : function (breadcrumbElement) {
            return this.findUniqueElement(
                breadcrumbElement,
                this.settings.childrenOuterContainerSelector
            );
        },

        getLookupUrl : function (breadcrumbElement) {
            return breadcrumbElement.data("childurl");
        },

        isBreadcrumbElementSelected : function (breadcrumbElement) {
            var button = this.getChildButtonOfBreadcrumbElement(breadcrumbElement);
            if(button) {
                return button.hasClass(this.settings['childrenButtonClass_Selected']);
            }
            return false;
        },

        elementFullyVisibleInViewport : function (el) {
            var windowWidth = jQuery(window).width();
            var elemPos = el.offset().left;
            var elemWidth = el.outerWidth();
            return (elemPos + elemWidth) < windowWidth;
        },

        readNodeIdFromBreadcrumbElement : function (breadcrumbElement) {
            var id = '';
            if(breadcrumbElement[0]){
                id = breadcrumbElement[0].id;
            }else{
                id = breadcrumbElement.id;
            }
            return id.split('_')[2];
        }
    };

    jQuery.fn.breadcrumb = function(options) {
        return this.each(function() {
            var element = jQuery(this);
            // Return early if this element already has a plugin instance
            if (element.data('breadcrumbHandler')) {
                return;
            }
            // Store plugin object in this element's data
            element.data('breadcrumbHandler', new BreadcrumbHandler(this, jQuery.extend({}, options)));
        });
    };
})();
//
////
