/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * autoCompletion.js
 *
 * LICENSE: This source file is subject to version 1.0 of the OpenFlyers
 * license that is available through the world-wide-web at the following
 * URI: http://www.openflyers.com/license/semifreelicense1_0.txt. If you did not receive a
 * copy of the OpenFlyers License and are unable to obtain it through the
 * web, please send a note to contact@openflyers.com so we can mail you
 * a copy immediately.
 *
 * @category    autoCompletion
 * @package     OpenFlyers
 * @author      Christophe LARATTE <christophe.laratte@openflyers.com>
 * @copyright   2008 OPENFLYERS S.A.R.L. <contact@openflyers.com>
 * @license     http://www.openflyers.com/license/semifreelicense1_0.txt  OpenFlyers License
 * @link        http://www.openflyers.com, https://work.openflyers.com/OF4-AutoCompletion
 * @since       Thu Jan 13 2010
 */
 
/**
 * Constructor
 *
 * Init code on page load
 *
 * @return void
 */
$(document).ready(function() {
    // Catch events for Combo autoComplete (flexselect)
    catchTriggerEventsForFlexSelect();
    // Catch events for an input of type number
    catchTriggerEventsForInputTypeNumber();
});

/**
 * catchTriggerEventsForFlexSelect
 *
 * @return void
 */
function catchTriggerEventsForFlexSelect() {
    // Combo autoComplete
    var flexSelectInputList = document.querySelectorAll('input.flexselect');
    if (flexSelectInputList !== null) {
        for (i=0; i <= flexSelectInputList.length-1; i++) {
            var flexSelectId = flexSelectInputList[i].getAttribute('id').replace('_flexselect', '');

            // If the input field has a value different to '-1' that must be associated with the first option and  ('0' or the first option of the flexselect has a value equal to '-1')
            // Display the clear button and hide the arrow down picto
            if ((($('#' + flexSelectId).val() != -1) || ($('#' + flexSelectId).find('option')[0].value != -1)) && (($('#' + flexSelectId).val() != 0) || ($('#' + flexSelectId).find('option')[0].value == -1))) {
                $('#' + flexSelectId + '-reset').show();
                $('#' + flexSelectId + '-arrow-down').hide();
            }
            // Otherwise the clear button will be hidden and the arrow down picto will be display
            else {
                $('#' + flexSelectInputList[i].getAttribute('id')).val('');
                $('#' + flexSelectId + '-reset').hide();
                $('#' + flexSelectId + '-arrow-down').show();
            }

            // Catch the input/select event
            $('#'+ flexSelectInputList[i].getAttribute('id')).bind('input select', function() {
                if ($('#' + this.getAttribute('id')).val()) {
                    $('#' + this.getAttribute('id').replace('_flexselect', '') + '-reset').show();
                    $('#' + this.getAttribute('id').replace('_flexselect', '') + '-arrow-down').hide();
                }
                else {
                    $('#' + this.getAttribute('id').replace('_flexselect', '') + '-reset').hide();
                    $('#' + this.getAttribute('id').replace('_flexselect', '') + '-arrow-down').show();
                }
            });

            // Catch the change event for the select element
            $('#' + flexSelectId).bind('change', function(){
                // If the input field has a value equal to '-1' and this value is associated with the first option
                // The input field must be empty, otherwise it must be filled by the selected option
                $('#' + this.getAttribute('id') + '_flexselect').val(((($(this).val() == -1) && ($(this).find('option')[0].value == -1)) ? '' : $.trim($(this).find('option:selected').text())));
            });

            // Catch the focus event for the input element
            $('#' + flexSelectInputList[i].getAttribute('id')).bind('focus', function() {
                inputValue        = $('#' + this.getAttribute('id')).val();
                selectElement     = document.getElementById(this.getAttribute('id').replace('_flexselect', ''));
                selectedOption    = selectElement.options[selectElement.selectedIndex];
                resetStyleDisplay = document.getElementById(this.getAttribute('id').replace('_flexselect', '-reset')).style.display;
                /**
                 * If there is a selected option
                 * And the value of the input is the option selected
                 * And the reset button is displayed
                 * Hide the dropdown menu when focus on the input
                 */
                if (selectedOption && (inputValue  === selectedOption.innerText) && (resetStyleDisplay == 'inline-block'))
                    $( '#' + this.getAttribute('id') + '_dropdown').hide() ;
            });

            // Targeting Click of Clear Button (X).
            $('#' + flexSelectId + '-reset').click({param :  flexSelectInputList[i]}, resetAutoComplete);

            // If flexselect has class 'has-optgroup' add same class name to dropdown menu
            // And if the first item is choose a value remove bold effect from it by adding 'hasNonBoldDisabledItem' in the ul element
            if (flexSelectInputList[i].classList.contains('has-optgroup')) {
                $('#' + flexSelectInputList[i].getAttribute('id') + '_dropdown').addClass('has-optgroup');
                if (($('#'+ flexSelectId).val() == -1) && ($('#' + flexSelectId).find('option')[0].innerText == ('-- ' + translate('CHOOSE_VALUE') + ' --'))) {
                    document.getElementById(flexSelectInputList[i].getAttribute('id') + '_dropdown').childNodes[0].classList.value = 'hasNonBoldDisabledItem';
                }
            }
        }

        // Add an alert when we try to send the form without selecting any option other than "choose value" in flexselect fields
        $(flexSelectInputList).closest('form').submit(function(event) {
            // Stock error message to print after checking flexselect fields
            errorMessageReturnedOnSubmit = '';
            // Get all flexselect fields in the form to check if they are required
            formFlexSelectInputList = $(this).find('input.flexselect');
            // For each flexselect field in the form check if the selected value is 'choose value' and if the field is required
            for (i=0; i <= formFlexSelectInputList.length-1; i++) {
                // Extract the id of the select element
                var flexSelectId = formFlexSelectInputList[i].getAttribute('id').replace('_flexselect', '');
                // Check if the flexSelect field has to be filled
                if (document.getElementById(flexSelectId).getAttribute('required') !== null) {
                    // Check if the selected value is 'choose value'
                    if (($('#'+ flexSelectId).val() == -1) && ($('#' + flexSelectId).find('option')[0].innerText == ('-- ' + translate('CHOOSE_VALUE') + ' --'))) {
                        // Restocking errors
                        errorMessageReturnedOnSubmit += translate('THE_FIELD') + ' ' + $('#' + formFlexSelectInputList[i].getAttribute('id')).parents('.form-field').find('span.label').text().replace(':', '') + ' ' + translate('ALERT_EMPTY_FIELD') + '\n';
                        // Add the 'required' class to the container class of the flexselct 'form-field' to require and notify alerts
                        $('#'+ formFlexSelectInputList[i].getAttribute('id')).parents('.form-field').addClass('required');
                    }
                }
            }

            // If there is an error message print it with an alert and stop the submit
            if (errorMessageReturnedOnSubmit.length) {
                event.preventDefault();
                alert(errorMessageReturnedOnSubmit);
                return false;
            }
        });
    }
}

/**
 * catchTriggerEventsForInputTypeNumber
 *
 * @return void
 */
 function catchTriggerEventsForInputTypeNumber () {
    // input of type number
    var inputNumberList = document.querySelectorAll('input[type=number]');
    if (inputNumberList !== null) {
        for( i=0; i <= inputNumberList.length-1; i++ ) {
            // Catch the Click event of minus1 Button and subtract a 1 from the value of the input field.
            $('#' + inputNumberList[i].getAttribute('id') + '-minus1').click({param : inputNumberList[i]}, function(event) {
                var value = parseInt($('#' + event.data.param.getAttribute('id')).val());
                if ( value > event.data.param.getAttribute('min') &&  value <= event.data.param.getAttribute('max') ) {
                    $('#' + event.data.param.getAttribute('id')).val( value - 1 );
                    document.getElementById(event.data.param.getAttribute('id')).dispatchEvent(new Event('change'));
                }
            });
            // Catch the Click event of add1 Button and add a 1 to the value of the input field.
            $('#' + inputNumberList[i].getAttribute('id') + '-add1').click({param : inputNumberList[i]}, function(event) {
                var value = parseInt($('#' + event.data.param.getAttribute('id')).val());
                if ( value < event.data.param.getAttribute('max') && value >= event.data.param.getAttribute('min') ) {
                    $('#' + event.data.param.getAttribute('id')).val( value + 1 );
                    document.getElementById(event.data.param.getAttribute('id')).dispatchEvent(new Event('change'));
                }
            });
        }
    }
}

/**
 * highlightMatch
 *
 * Helper function for the formatter
 *
 * @link https://work.openflyers.com/OF4-AutoCompletion#highlightMatch
 * @param string name
 * @param string query
 * @return string
 */
function highlightMatch(name, query) {
    var matcher = new RegExp('(' + query + ')', 'gi' );
    return name.replace(matcher, '<strong>$1</strong>');
}

/**
 * resetAutoComplete
 *
 * on click Clear Button (X) clear the input field
 * and erase input value
 * and fill the value of the select with '-1' if there is the choose value option or 'null' if not
 * and set the size to 28
 * and hide the button 
 * and show the arrow down picto
 * and show the flexselect_dropdown
 * 
 * @param event Event object, and it represents the event being fired which caused our function to be executed.
 * @return void
 */
function resetAutoComplete(event) {
    event.preventDefault();
    event.data.param.value = '';
    document.getElementById(event.data.param.getAttribute('id').replace('_flexselect', '')).value =
    ($('#' + event.data.param.getAttribute('id').replace('_flexselect', '')).find('option')[0].innerText == ('-- ' + translate('CHOOSE_VALUE') + ' --')) ? -1 : null;
    event.data.param.size = 28;
    $('#' + event.data.param.getAttribute('id')).focus();
    $('#' + event.data.param.getAttribute('id')).keydown();
    $('#' + event.data.param.getAttribute('id')).keyup();
    $(this).hide();
    $('#' + event.data.param.getAttribute('id').replace('_flexselect', '') + '-arrow-down').show();
}

/**
 * setAutoCompletion
 *
 * Using jquery ui autocomplete
 *
 * @link https://work.openflyers.com/OF4-AutoCompletion#SetAutoCompletion
 * @param action, string or array - if string call ajax action, if array directly create autocompletion
 * @param inputId, string - html id of the input where autocomplete has to be enable
 * @param onSelectFunction, callback when an item is selected
 * @param formatLabel, callback to format label
 * @param formatValue, callback to format value
 * @param displayWhenEmpty, boolean - allow to trigger search if input is empty
 * @param customClass, string - add a class to the ul containing the items.
 * @param treatUnfoundedLocation, bool - define if we are working with locations, and iw we need to treat with unfounded locations
 */
function setAutoCompletion(action, inputId, onSelectFunction, formatLabel, formatValue, displayWhenEmpty, customClass, treatUnfoundedLocation) {
    // LocalComplete is true if not asynchronous
    var localComplete = $.isArray(action);
    var postData      = '';
    if (arguments.length > 7) {
        for ( var i = 7; i < arguments.length; i++) {
            postData += '&arguments[' + (i+1) + ']=' + arguments[i];
        }
    }

    /* Callback used for focus and keyup, allow to show the dropdown if the input is empty */
    var triggerEmptySearch = function () {
        if (displayWhenEmpty && $(this).val() === '') {
            // If input value is empty display all users
            $(this).autocomplete('search', ' ' );
        }
    };
    // If input is display add autocomplete
    if ($('#' + inputId).length) {
        $('#' + inputId).autocomplete({
            // Input string min length when autocomplete will activate
            minLength: displayWhenEmpty ? 0 : 1,
            source: (localComplete) ? action :
                function( request, response ) {
                    // Ajax call to retrieve items
                    $.ajax({
                        url: 'actionOnDemand.php',
                        type: 'POST',
                        data: 'arguments[0]=' + action + '&character=' + request.term + postData,
                        dataType: 'json',
                        processData: false,
                        success: function(data) {
                            // SPECIFIC TO A CERTAIN CASE, WHEN USED TO GET LOCATION
                            // If it's used to get a location list, and we want to handle unfounded location, and no corresponding have been found.
                            if (treatUnfoundedLocation == true && data.data.length === 0) { 
                                // Create a fake Location, with a name and an Icao Code,  to simulate that a Location has been found.
                                var fakeLocation          = new Object(); 
                                fakeLocation['name']      = translationTag['ASK_OF_ADD_UNFOUNDED_LOCATION']; //la trad
                                fakeLocation['icao_name'] = request.term; // Stock the code that the user is looking for.
                                data.data.push(fakeLocation); // Push the fake Location in the array of Object.
                            }
                            response( $.map( data.data, function( item ) {
                                return {
                                    label: formatLabel(item, request),
                                    value: formatValue(item, request),
                                    dataResult: item
                                }
                            }));
                        }
                    });
                },
            select: function(event, ui) {
                onSelectFunction(ui.item.dataResult, event);
            }
        }).focus(triggerEmptySearch)
            .data('autocomplete')._renderItem = function(ul, item) {
            if (customClass) {
                ul.addClass(customClass);
            }
            var li = $('<li></li>').data('item.autocomplete', item);
            localComplete ? li.append('<a>' + formatLabel(item, $('#' + inputId).val()) + '</a>') : li.append('<a>' + item.label + '</a>');
            return li.appendTo(ul);
        };
    }
}