class Select {

    constructor( container ) {

        this.container = container;

        this.init();        
        this.reset();        
    }

   
    
    init() {

        this.container.style.display = 'none';
        this.container.insertAdjacentHTML('afterbegin', '<option value="" style="color:red">Seleziona un elemento</option>') ;       
        this.updateItems();
    }

    updateItems() {

        this.items = [].map.call( this.container.querySelectorAll('option'), item => { item.visible = true; return item } );
    }

    reset() {

        this.container.selectedIndex = 0;
    }

    getVisibles() {

        return this.items.filter( item => item.visible );
    }

    getIndexByValue( value ){

        let options = [].map.call( this.container.options, i => i );

        let results = options.filter( i => i.value == value );

        if( results.length == 0 ) return 0;
        
        let selectedOption =  results.shift(); 

        return options.indexOf( selectedOption );
    }

    filter( text ) {

        this.items = this.items.map( item => { item.visible = item.textContent.toLowerCase().includes(text.toLowerCase()); return item; })
    }
    
}




class Input {

    constructor( container, select, selectionCallback ) {

        this.container         = container;
        this.select            = select;
        this.selectionCallback = selectionCallback;

        this.filterResults = this.filterResults.bind(this);
        this.selection     = this.selection.bind(this);

        this.container.addEventListener('keyup' , this.filterResults );

        this.results = this.initResults();
        this.autocomplete();
    }




    initResults() {

        let results = document.createElement('div');
        results.id = "results";

        let ul = document.createElement('ul');
        
        results.insertAdjacentElement( 'beforeend', ul );

        this.container.insertAdjacentElement( 'afterend', results );

        return ul;
    }
    
    reset() {

        this.results.innerHTML = '';
    }

    filterResults( evt ) {

        let filterText = this.container.value.length < 3 ?  '': this.container.value ;
        
        this.select.filter( filterText );
        this.select.reset();        
        this.autocomplete();
    }


    initRow( option ){

        let row = document.createElement('li');
        row.className='autocomplete-row';
        row.textContent = option.textContent;
        row.dataset.value = option.value;

        row.addEventListener( 'click', this.selection );

        return row;
        
    }

    autocomplete() {

        let visibles = this.select.getVisibles();

        this.reset();

        visibles.forEach( option => {

            this.results.appendChild( this.initRow( option ) );
        });
    }


    selection( event ) {

        // this.close();        
        this.select.container.selectedIndex = this.select.getIndexByValue( event.target.dataset.value );
        this.selectionCallback();
    }

}

class ComboSearch {

    constructor( selectElement, callback = null ){

        this.select     = new Select( selectElement );

        this.container  = this.render();

        this.callback   = callback != null ? callback : () => {};
        
        this.selected   = this.container.querySelector('.selected-element');        
        this.searchbox  = this.container.querySelector('.search-container');  
        this.input      = new Input( this.container.querySelector('input'), this.select , this.choice.bind(this) );

        this.toggle  = this.toggle.bind(this);
        
        this.isOpen = false;
        this.selected.addEventListener('click', this.toggle );
        
        this.choice();
        this.observe();
        
    }

    updateItems() {

        this.select.updateItems();
        this.input.autocomplete();        
    }


    observe() {

        // Select the node that will be observed for mutations
        const targetNode = this.select.container;

        // Options for the observer (which mutations to observe)
        const config = { attributes: false, childList: true, subtree: false };

        // Callback function to execute when mutations are observed
        const callback = ( mutationList, observer ) => {
            
            for (const mutation of mutationList) {
                if (mutation.type === "childList") {
                    
                    this.updateItems();
                }
            }
        };

        // Create an observer instance linked to the callback function
        const observer = new MutationObserver(callback);

        // Start observing the target node for configured mutations
        observer.observe(targetNode, config);
    }
    
    choice() {

        this.selected.innerHTML = this.select.container.selectedOptions[0].textContent;
        this.callback();
        this.close();
    }


    toggle( event ) {

        this.isOpen = !this.isOpen;
        
        if( this.isOpen ) this.open( event );
        else              this.close( event );
    } 

    open( event ) { 

        this.selected.classList.add('up');
        this.searchbox.classList.remove('hidden');
    }

    close(){
        
        this.searchbox.classList.add('hidden');
        this.selected.classList.remove('up');
    }

    render() {

        let selectContainer = document.createElement('div');

        selectContainer.className = 'select-container';

        selectContainer.insertAdjacentHTML('afterbegin', this.markup() );
        
        this.select.container.insertAdjacentElement('afterend', selectContainer );
        
        selectContainer.insertAdjacentHTML('afterend',   this.style()  );

        return selectContainer;
    }


    markup() {

        return `          
            <div class="selected-element"></div>
            <div class="search-container hidden">
                <input type="text" placeholder="cosa stai cercando?" value="">
            </div>            
        `;
    }

    style() {

        return `
            <style>
            .hidden { display:none }

            .selected-element {
                border-radius: 5px;
                border: 1px solid lightgrey;
                padding: 6px 0 2px 6px;
                position: relative;                    
            }

            .select-container {
                border-radius: 5px;
                font: 14px/1em sans-serif;
                width: 90%;
                margin: 0 auto;
                background: white;
                font-size: 14px;
            }
            
            .search-container {
                border-radius: 0 0 5px 5px;
                border: 1px solid lightgrey;
                font: 12px/1em sans-serif;
                padding: 5px;
                position: relative;
            }

            .search-container input {
                line-height: 1.2em;
                width: 100%;
                border: 1px solid lightgrey;
                border-color: transparent transparent #afafaf transparent;
                outline: none;
                margin: 0px 0 10px 0;
                margin: 0 0 10px 0;
                padding: 5px 0 10px 0;
            }

        
            .selected-element:after {
                position: absolute;
                content: "";
                top: 9px;
                right: 10px;
                width: 0;
                height: 0;
                border: 6px solid #8d8d8d;
                border-color: #505050 transparent transparent transparent;
                border-radius: 2px;
            }
            
            .selected-element.up:after {
                border-color: transparent transparent #505050 transparent;
                top: 3px;
            }

            
            #results {

                background-color: #f8f8f8;
                border-radius: 0 0 5px 5px;
                overflow-y: scroll;
                height: 10em;
            }
            #results ul {
                list-style: none;   
                margin:0;             
                padding:0;           
            }

            #results ul li {
                margin:3px 5px;
                padding:1px 3px;
            }

            #results ul li:hover {
                background:lightgrey;
                cursor: pointer;
                
            }

            </style>
        `;
        
    }

}
