
	(function ($, window, document, undefined) {
    	"use strict";
    	
    	var pluginName = "C_TreeView",
        	defaults = {
            	expandIcon: 'fa fa-angle-down fa-fw',
            	collapseIcon: 'fa fa-angle-right fa-fw',
            	expandClass: 'show',
            	indent: 1.25,
            	parentsMarginLeft: '1.25rem',
            	openNodeLinkOnNewTab: true

        	};

        var templates = {
        	treeview: 				       '<ul role="tree" id="tree"></u>',
        	treeviewItem: 			       '<li role="treeitem" class="m-0 p-0 pt-1 pb-1" aria-expanded="false" tabindex="0"></li>',
        	treeviewGroupItem: 		       '<ul role="group" class="mb-0 pb-0"></ul>',
        	treeviewItemStateIcon:         '<i class="state-icon" onclick="IconClicked (this)"></i>',
        	treeviewItemContentDiv:        '<div class="d-inline m-0 p-0" onclick="stopCheckboxClick(event)" style="cursor: pointer !important;"></div>',
        	treeviewItemContentInput:      '<input class="form-check-input" type="checkbox" onclick="TV_CheckBoxClicked (this)" >',
        	// treeviewItemContentLabel:      '<span class="form-check-label ps-2 pe-2 pb-1" style="cursor: pointer !important;" onclick="TV_LabelClicked (this)"></span>',
            treeviewItemContentLabel:      '<span class="xxx form-check-label ms-1 ps-2 pe-2 pb-1" style="cursor: pointer !important;"></span>',
        	treeviewItemIcon:              '<i class="item-icon"></i>',
            treeviewItemIconFile:          '<img style="width:16px;height:16px;"></img>'
    	};

        
        function C_TreeView ( container, options, callback ) 
        {
            callback ( 345 );
            container.innerHTML = '';

            this.lastSearchIndex = -1;
            this.lastSearchText    = '';
            this.callback          = callback;
        	this.element           = container;
        	this.itemIdPrefix      = container.id + "-item-";
	        this.settings          = $.extend({}, defaults, options);
            this.SpanIdx           = 0;
        	this.init();
    	}


    	$.extend ( C_TreeView.prototype, {

    		init: function () {
            	this.tree = [];
            	this.nodes = [];

            	if (this.settings.data) 
            	{	
                	if (this.settings.data.isPrototypeOf(String)) 
                	{
                    	this.settings.data = $.parseJSON(this.settings.data);
                	}
                	this.tree = $.extend(true, [], this.settings.data);
                	delete this.settings.data;
            	}
            
            	// Set main bstreeview class to element.
            	// $(this.element).addClass('bstreeview');

            	this.initData ( { nodes: this.tree } );

            	var _this = this;

            	this.build ( $(this.element), this.tree, 0 );

            	// Update angle icon on collapse
            	
            	$(this.element).on('click', '.list-group-item', function (e) 
            	{
                	$('.state-icon', this)
                    .toggleClass(_this.settings.expandIcon)
                    .toggleClass(_this.settings.collapseIcon);
                	// navigate to href if present
                	if (e.target.hasAttribute('href')) {
                    if (_this.settings.openNodeLinkOnNewTab) {
                        window.open(e.target.getAttribute('href'), '_blank');
                    }
                    else {
                        window.location = e.target.getAttribute('href');
                    }
                	}
                	else
                	{
                    	// Toggle the data-bs-target. Issue with Bootstrap toggle and dynamic code
                    	$($(this).attr("data-bs-target")).collapse('toggle');
                }
            	});
	       	},

	       	initData: function (node) 
	       	{
            	if (!node.nodes) 
                	return;
            	var parent = node;
            	var _this = this;
            	$.each(node.nodes, function checkStates(index, node) 
            	{
                	node.nodeId = _this.nodes.length;
                	node.parentId = parent.nodeId;
                	_this.nodes.push(node);

                	if (node.nodes) 
                	{
                    	_this.initData(node);
                	}
            	});
        	},
            SelectNextItem: function (text) 
            {
                const callback      = this.callback.bind ( this );
                const labelClicked  = this.LabelClicked.bind ( this );

                const $spans = $('#' + this.element.id).find ( 'span' );
                const searchText = text.toLowerCase ();

                if ( this.lastSearchText !== searchText ) 
                {
                    this.lastSearchIndex    = -1;
                    this.lastSearchText     = searchText;
                }

                const total         = $spans.length;
                let found           = false;
                let currentIndex    = this.lastSearchIndex;

                for (let i = 1; i <= total; i++) 
                {
                    let     nextIndex   = (currentIndex + i) % total;
                    const   span        = $spans.eq(nextIndex);
                    const   val         = span.text().toLowerCase();

                    if ( val.includes(searchText) ) 
                    {
                        labelClicked ( span, callback );

                        this.lastSearchIndex = nextIndex; 
                        found = true;
                        break;
                    }
                }

                if ( !found ) 
                {
                    this.lastSearchIndex = -1; // reset pour prochaine recherche
                }
            },

            SelectItem: function (data1, data2) 
            {
                const callback      = this.callback.bind ( this );
                const labelClicked  = this.LabelClicked.bind ( this );

                const $spans = $('#' + this.element.id).find ( 'span' );

                const total         = $spans.length;
                let found           = false;
                let currentIndex    = this.lastSearchIndex;

                for (let i = 0; i < total; i++) 
                {
                    const   span        = $spans.eq(i);
                    const   val         = span.text();
                    

                    let spanData1 = span.attr('data-data1');
                    let spanData2 = span.attr('data-data2');

                    if ( spanData1 == data1 && spanData2 == data2 ) 
                    {
                        labelClicked ( span, callback );
                        found = true;
                        break;
                    }
                }

                if ( !found ) 
                {
                    this.lastSearchIndex = -1; // reset pour prochaine recherche
                }
            },

            SelectFirstItem: function () 
            {
                const callback      = this.callback.bind ( this );
                const labelClicked  = this.LabelClicked.bind ( this );
                const $spans = $('#' + this.element.id).find ( 'span' );
                const total         = $spans.length;

                if ( total > 0 )
                {
                    const   span        = $spans.eq(0);
                    const   val         = span.text();

                    let spanData1 = span.attr('data-data1');
                    let spanData2 = span.attr('data-data2');

                    labelClicked ( span, callback );
                }

                this.lastSearchIndex = -1; // reset pour prochaine recherche
            },

            CollapseAll: function ()
            {
                const elements = $('#' + this.element.id).find ( '.state-icon' );
                for ( let i=0; i<elements.length; i++ )
                {
                    let parent = elements[i].parentElement;
                    parent.setAttribute('aria-expanded', 'false');

                    elements [i].classList.remove ( 'fa-angle-down' );
                    elements [i].classList.add ( 'fa-angle-right' );
                }
                
            },

            ExpandAll: function ()
            {
                const elements = $('#' + this.element.id).find ( '.state-icon' );
                for ( let i=0; i<elements.length; i++ )
                {
                    let parent = elements[i].parentElement;
                    parent.setAttribute('aria-expanded', 'true');

                    elements [i].classList.remove ( 'fa-angle-right' );
                    elements [i].classList.add ( 'fa-angle-down' );
                }
            },

            LabelClicked: function (element, callback)
            {
                const parentsList = [];

                if (element instanceof jQuery) 
                {
                    element = element[0];
                }
                
                const parent = $(element).closest('.treecontainer');
                // const parent = element.closest('.treecontainer');
                
                let spanlist = document.querySelectorAll('#'+parent.attr('id')+' span');
                spanlist.forEach(span => {
                
                if ( span == element )
                {
                    span.style.fontWeight = 'bold';
                    span.style.backgroundColor = '#62BCFC';

                    callback ( span.dataset.data1, span.dataset.data2 );
                }
                else
                {
                    span.style.backgroundColor = '';
                    span.style.fontWeight = 'normal';
                }
                });
            },

        	build: function (parentElement, nodes, depth) 
        	{
            	var _this = this;

            	// Calculate item padding.
            	var leftPadding = _this.settings.parentsMarginLeft;

                let spanIdx = _this.SpanIdx;

            	if (depth > 0) 
            	{
                	leftPadding = (_this.settings.indent + depth * _this.settings.indent).toString() + "rem;";
            	}
            	depth += 1;

                let spanBaseID = _this.element.id + "_span_";
                
            	// Add each node and sub-nodes.
            	$.each(nodes, function addNodes(id, node) 
            	{
                	// Main node element.
                	/*
                	var treeItem = $(templates.treeviewItem)
                    .attr('data-bs-target', "#" + _this.itemIdPrefix + node.nodeId)
                    .attr('style', 'padding-left:' + leftPadding)
                    .attr('aria-level', depth);
                	*/
                	var treeItem = $(templates.treeviewItem);

                	treeItem.attr( 'id', _this.itemIdPrefix + node.nodeId );
                
                	// Set Expand and Collapse icones.
                	if (node.nodes) 
                	{
                        // Test
                        treeItem.attr( 'aria-expanded', node.expanded );

                    	var treeItemStateIcon = $(templates.treeviewItemStateIcon)
                        .addClass((node.expanded)?_this.settings.expandIcon:_this.settings.collapseIcon);
                    	treeItem.append(treeItemStateIcon);
                	}

                	// set node icon if exist.
                	
                	if (node.icon) 
                	{
                    	var treeItemIcon = $(templates.treeviewItemIcon)
                        	.addClass(node.icon);
                    	treeItem.append(treeItemIcon);
                	}

                    if (node.iconFile) 
                    {
                        var treeItemIcon = $(templates.treeviewItemIconFile)
                            .attr('src', node.iconFile );
                        treeItem.append(treeItemIcon);
                    }

                    
                	

                	// Set node Text.
                	// treeItem.append ( node.text );
                

                	var treeItemContentDiv      = $(templates.treeviewItemContentDiv);
                    if (!node.icon && !node.iconFile )
                    {
                	var treeItemContentInput    = $(templates.treeviewItemContentInput);
                	// treeItemContentInput.attr ('id', 'idc_chk_'+node.nodeId);
                    if ( node.ident != undefined && node.ident != '' )
                    {
                        let chkIdent = _this.element.id + "_cb_" + node.ident;
                        treeItemContentInput.attr ('id', chkIdent);
                        treeItemContentInput.attr ( 'data-container', _this.element.id );
                    }
                    if ( node.checked == true )
                        treeItemContentInput.prop ( 'checked', node.checked );
                    
                	treeItemContentDiv.append ( treeItemContentInput );
                    }



                	var treeItemContentLabel = $(templates.treeviewItemContentLabel);
                	treeItemContentLabel.attr ('for', 'idc_chk_'+node.nodeId);
                	treeItemContentLabel.append ( node.text );
                    let spanID = spanBaseID+_this.SpanIdx;
                    treeItemContentLabel.attr('id', spanID);
                    

                    // let callbackSpanClicked = _this.callback.bind ( this );

                    // treeItemContentLabel.on ( 'click', callbackSpanClicked );

                    treeItemContentDiv.append ( treeItemContentLabel );

                    let callback = _this.callback.bind(this);
                    let labelClicked = _this.LabelClicked.bind ( this, treeItemContentLabel, callback );
                    treeItemContentLabel.on ( 'click', labelClicked );

                    treeItemContentLabel.on ( 'mousedown', function(e) {
                        if (e.button === 2) 
                        {
                            labelClicked();
                            // e.preventDefault(); // optionnel
                        }
                    });

                    _this.SpanIdx++;

                	treeItem.append ( treeItemContentDiv );


                	// Reset node href if present
                	if (node.href) 
                	{
                    	treeItem.attr('href', node.href);
                	}

                	// Add class to node if present
                	if (node.class) 
                	{
                    	treeItem.addClass(node.class);
                	}

                	// Add custom id to node if present
                	if (node.id) {
                    	treeItem.attr('id', node.id);
                	}

                    if ( node.data1 )
                    {
                        treeItemContentLabel.attr( 'data-data1', node.data1 );
                    }

                    if ( node.data2 )
                    {
                        treeItemContentLabel.attr( 'data-data2', node.data2 );
                    }

                	// Attach node to parent.
                	parentElement.append(treeItem);
                	// Build child nodes.
                	if (node.nodes) 
                	{
                    	// Node group item.
                    	// var treeGroup = $(templates.treeviewGroupItem).attr('id', _this.itemIdPrefix + node.nodeId);
                    	var treeGroup = $(templates.treeviewGroupItem);

                    	// parentElement.append(treeGroup);
                    	treeItem.append(treeGroup);

                    	_this.build(treeGroup, node.nodes, depth);
                    
                    	if (node.expanded) 
                        	treeGroup.addClass(_this.settings.expandClass);
                	}

                    context.attach ( '#'+spanID, node.menu );
            	});
        
            }

    	});

        $.fn[pluginName] = function (options,callback) 
        {
        	return this.each(function () 
        	{
           		// if (!$.data(this, "plugin_" + pluginName)) 
           		{
               		$.data(this, "plugin_" +
                   	pluginName, new C_TreeView(this, options,callback));
           		}
        	});
    	};

    }) ( jQuery, window, document );


	function stopCheckboxClick(event) 
	{

    	event.stopPropagation(); // empêche l'ouverture/fermeture
  	}

  	
  	function IconClicked (element)
  	{
  		let parent = element.parentElement;
  		const isExpanded = parent.getAttribute('aria-expanded') === 'true';

  		if (parent.querySelector('[role="group"]')) 
      	{
        	parent.setAttribute('aria-expanded', String(!isExpanded));

            let icons = parent.querySelectorAll ( '.state-icon' );

            // if ( icons.length == 1 )
            {
                if ( isExpanded == false )
                {
                    icons [0].classList.remove ( 'fa-angle-right' );
                    icons [0].classList.add ( 'fa-angle-down' );
                }
                else
                {
                    icons [0].classList.remove ( 'fa-angle-down' );
                    icons [0].classList.add ( 'fa-angle-right' );
                }
            }
      	}
  	}


    function TV_LabelClicked (element)
    {
        const parent = $(element).closest('.treecontainer');

        let spanlist = document.querySelectorAll('#'+parent.attr('id')+' span');

        spanlist.forEach(span => {
            // if (span.classList.contains('cible')) 
            if ( span == element )
            {
                span.style.fontWeight = 'bold';
                span.style.backgroundColor = '#62BCFC';
            }
            else
            {
                span.style.backgroundColor = '';
                span.style.fontWeight = 'normal';
            }
        });

        /*
        $('#'+parent.attr('id') ).find ( 'span' ).each (
            function () {

                if ( $(this).attr('id') == element.id )
                {
                    console.log ( " element.id : " + element.id );
                    $(this).css ( 'background-color', 'FF0000' );
                }

            });
        */

        /*
        let spanlist = document.querySelectorAll('#'+parent.attr('id')+' span');
        console.log ( "spanlist.length : " + spanlist.length );


        let gp = element.parentElement.parentElement;
        let cblist = gp.querySelectorAll('[type="checkbox"]');

        for ( let i=0; i<cblist.length; i++ ) 
            cblist [i].checked = check;
        */
    }

    function TV_CheckBoxClicked (element)
    {
        let check = element.checked;


        $('#'+element.dataset.container ).find ( 'input[type="checkbox"]' ).each (
            function () {
                if ( $(this).attr('id') == element.id )
                {
                    $(this).prop ( 'checked', check );
                }

            });




        let gp = element.parentElement.parentElement;
        let cblist = gp.querySelectorAll('[type="checkbox"]');

        for ( let i=0; i<cblist.length; i++ ) 
            cblist [i].checked = check;
    }


    function TreeViewCheckAll ( container )
    {
        $('#'+container ).find ( 'input[type="checkbox"]' ).each (
            function () {
                $(this).prop ( "checked", true );
            });
    }

    function TreeViewUncheckAll ( container )
    {
        $('#'+container ).find ( 'input[type="checkbox"]' ).each (
            function () {
                $(this).prop ( "checked", false );
            });
    }
        
    function TreeViewCheckItem ( container, ident )
    {
        $('#'+container ).find ( 'input[type="checkbox"]' ).each (
            function () {
                let id = container + "_cb_" + ident;

                if ( id == $(this).attr('id') )
                {
                    $(this).prop ( 'checked', true );
                }
            });
    }

    function TreeViewGetSelectedItems ( container )
    {
        let result = new Array ();

        $('#'+container ).find ( 'input[type="checkbox"]' ).each (
            function () {
                if ( $(this).prop ( 'checked' ) == true && $(this).attr('id') != undefined )
                {
                    let id = $(this).attr('id').replace ( container+"_cb_", "" );

                    result.push ( id );
                }

            });

        return result;
    }

    function TreeViewGetUnselectedItems ( container )
    {
        let result = new Array ();

        $('#'+container ).find ( 'input[type="checkbox"]' ).each (
            function () {
                if ( $(this).prop ( 'checked' ) == false && $(this).attr('id') != undefined )
                {
                    let id = $(this).attr('id').replace ( container+"_cb_", "" );

                    result.push ( id );
                }

            });

        return result;
    }

    /*
    function TreeViewSelectNextItem ( container, text )
    {
        console.log ( "TreeViewSelectNextItem..." );
        console.log ( " text : " + text );

        
        $('#'+container ).find ( 'span' ).each (
            function () {
                    let val = $(this).text();
                    if ( val.toLowerCase().includes ( text.toLowerCase () ) )
                        console.log ( " val : " + val );

            });

        return;
    }
    */
    
