var batcheditInterface = (function () {
    function debounce(callback, timeout) {
        var timeoutId = null;

        var wrapper = function() {
            var self = this;
            var args = arguments;

            if (timeoutId) {
                clearTimeout(timeoutId);
            }

            timeoutId = setTimeout(function () {
                callback.apply(self, args);

                timeoutId = null;
            }, timeout);
        };

        return wrapper;
    }

    function escapeId(id) {
        return id.replace(/([:.])/g, '\\$1');
    }

    function observeStyleMutations($element, callback) {
        return new MutationObserver(debounce(callback, 500)).observe($element.get(0), {
            attributes: true, attributeFilter: ['style']
        });
    }

    function getLang(id) {
        if (id in batcheditLang) {
            return batcheditLang[id];
        }

        return 'undefined';
    }

    function updateConfig(id, value) {
        var config = Cookies.getJSON('BatchEditConfig');

        if (typeof config != 'undefined') {
            config[id] = value;

            Cookies.set('BatchEditConfig', config, { path: '', sameSite: 'Strict' });
        }
    }

    function initializeTooltip() {
        jQuery.widget.bridge('uitooltip', jQuery.ui.tooltip);
        jQuery('#batchedit').uitooltip({
            tooltipClass: 'be-tooltip',
            show: {delay: 1000},
            track: true
        });
    }

    function initializeApplyCheckboxes() {
        jQuery('#be-applyall').click(function() {
            jQuery('.be-file input').prop('checked', this.checked);
        });

        jQuery('.be-file .be-stats input').click(function() {
            jQuery('.be-match input[id^=' + escapeId(this.id) + ']').prop('checked', this.checked);
        });

        // When all single matches of a file have been checked, mark the appropriate file box as checked, too.
        jQuery('.be-match input').click(function() {
            var pageId = escapeId(this.id.substr(0, this.id.indexOf('#')));
            var pageMatches = jQuery('.be-match input[id^=' + pageId + ']').get();

            jQuery('#' + pageId).prop('checked', pageMatches.reduce(function(checked, input) {
                return checked && input.checked;
            }, true));
        });

        // Consolidate the list of all checked match ids into single hidden input field as
        // a JSON-encoded array string. This avoids problems for huge replacement sets
        // exceeding `max_input_vars` in `php.ini`.
        jQuery('#batchedit form').submit(function() {
            // Consolidate checked matches into a single string variable to be posted to the backend.
            jQuery('input[name=apply]').val(JSON.stringify(jQuery('.be-match input:checked').map(function() {
                return this.id;
            }).get()));
        });
    }

    function initializeTotalStatsFloater() {
        var $anchor = jQuery('#be-totalstats');
        var $floater = $anchor.children('div');

        var updateFloater = function() {
            if ($anchor.length == 0) {
                return;
            }

            if (window.pageYOffset > $anchor.offset().top) {
                $floater.addClass('be-floater').width($anchor.css('width'));
            }
            else {
                $floater.removeClass('be-floater');
            }
        };

        jQuery(window).scroll(updateFloater);

        updateFloater();
    }

    function initializeSearchMode() {
        var $searchMode = jQuery('input[name=searchmode]');
        var $advancedRegexp = jQuery('input[name=advregexp]');
        var $searchInputs = jQuery('#be-searchedit, #be-searcharea');
        var $replaceInputs = jQuery('#be-replaceedit, #be-replacearea');

        function updatePlaceholders(searchMode, advancedRegexp) {
            var replaceMode = searchMode;

            if (searchMode == 'regexp' && advancedRegexp) {
                searchMode = 'advregexp';
            }

            $searchInputs.prop('placeholder', getLang('hnt_' + searchMode + 'search'));
            $replaceInputs.prop('placeholder', getLang('hnt_' + replaceMode + 'replace'));
        }

        $searchMode.click(function() {
            updatePlaceholders(this.value, $advancedRegexp.prop('checked'));
            updateConfig('searchmode', this.value);
        });

        $advancedRegexp.click(function() {
            updatePlaceholders($searchMode.filter(':checked').val(), this.checked);
            updateConfig('advregexp', this.checked);
        });
    }

    function initializeMatchCase() {
        jQuery('input[name=matchcase]').click(function() {
            updateConfig('matchcase', this.checked);
        });
    }

    function initializeMultiline() {
        var $multiline = jQuery('input[name=multiline]');
        var $searchEdit = jQuery('#be-searchedit');
        var $searchArea = jQuery('#be-searcharea');
        var $replaceEdit = jQuery('#be-replaceedit');
        var $replaceArea = jQuery('#be-replacearea');

        $multiline.click(function() {
            if (this.checked) {
                $searchEdit.hide();
                $replaceEdit.hide();
                $searchArea.val($searchEdit.val()).show();
                $replaceArea.val($replaceEdit.val()).show();
            }
            else {
                $searchArea.hide();
                $replaceArea.hide();
                $searchEdit.val($searchArea.val().replace(/\n/g, '\\n')).show();
                $replaceEdit.val($replaceArea.val().replace(/\n/g, '\\n')).show();
            }

            updateConfig('multiline', this.checked);
        });

        observeStyleMutations($searchArea, function() {
            // Avoid using $searchArea.outerHeight() as it will have to modify display style
            // of the element when it's hidden in order to get its height. This style mutation
            // will trigger the observer again, causing an infintite loop.
            if ($searchArea.get(0).offsetHeight > 0) {
                updateConfig('searchheight', $searchArea.get(0).offsetHeight);
            }
        });

        observeStyleMutations($replaceArea, function() {
            if ($replaceArea.get(0).offsetHeight > 0) {
                updateConfig('replaceheight', $replaceArea.get(0).offsetHeight);
            }
        });

        jQuery('#batchedit form').submit(function() {
            if (!$multiline.prop('checked')) {
                $searchArea.val($searchEdit.val());
                $replaceArea.val($replaceEdit.val());
            }
        });
    }

    function initializeAdvancedOptions() {
        $document = jQuery(document);
        $options = jQuery('#be-extoptions');

        function onClickOutside(event) {
            if (!$options.get(0).contains(event.target)) {
                console.log('outside');
                close();
            }
        }

        function open() {
            $options.show();
            $document.on('click', onClickOutside);
        }

        function close() {
            $options.hide();
            $document.off('click', onClickOutside);
        }

        jQuery('a[href="javascript:openAdvancedOptions();"]').click(function() {
            open();

            return false;
        });

        jQuery('a[href="javascript:closeAdvancedOptions();"]').click(function() {
            close();

            return false;
        });
    }

    function initializeMatchContext() {
        var $contextChars = jQuery('input[name=ctxchars]');
        var $contextLines = jQuery('input[name=ctxlines]');

        jQuery('input[name=matchctx]').click(function() {
            $contextChars.prop('disabled', !this.checked);
            $contextLines.prop('disabled', !this.checked);
            updateConfig('matchctx', this.checked);
        });

        $contextChars.change(function() {
            updateConfig('ctxchars', this.value);
        });

        $contextLines.change(function() {
            updateConfig('ctxlines', this.value);
        });
    }

    function initializeSearchLimit() {
        var $searchMax = jQuery('input[name=searchmax]');

        jQuery('input[name=searchlimit]').click(function() {
            $searchMax.prop('disabled', !this.checked);
            updateConfig('searchlimit', this.checked);
        });

        $searchMax.change(function() {
            updateConfig('searchmax', this.value);
        });
    }

    function initializeKeepMarks() {
        var $markPolicy = jQuery('select[name=markpolicy]');

        jQuery('input[name=keepmarks]').click(function() {
            $markPolicy.prop('disabled', !this.checked);
            updateConfig('keepmarks', this.checked);
        });

        $markPolicy.change(function() {
            updateConfig('markpolicy', this.value);
        });
    }

    function initializeApplyTemplatePatterns() {
        jQuery('input[name=tplpatterns]').click(function() {
            updateConfig('tplpatterns', this.checked);
        });
    }

    function initializeCheckSummary() {
        jQuery('input[name=checksummary]').click(function() {
            updateConfig('checksummary', this.checked);
        });
    }

    function startProgressMonitor() {
        var hidden = true;
        var $progress = jQuery('#be-progress');

        function updateProgress(data) {
            $progress.text(data.operation).width((data.progress / 10) + "%");
        }

        function checkProgress() {
            setTimeout(function () {
                batcheditServer.checkProgress(onProgressUpdate);
            }, 500);
        }

        function onProgressUpdate(data) {
            if (hidden && data.progress < 400) {
                jQuery('#be-progressbar').css('display', 'flex');
                jQuery('input[name^=cmd').prop('disabled', true);

                hidden = false;
            }

            if (!hidden) {
                updateProgress(data);
                checkProgress();
            }
        }

        checkProgress();
    }

    function initializePreview() {
        jQuery('input[name=cmd\\[preview\\]]').click(function() {
            startProgressMonitor();
        });
    }

    function initializeApply() {
        jQuery('input[name=cmd\\[apply\\]]').click(function() {
            var proceed = true;

            if (jQuery('input[name=checksummary]').prop('checked') &&
                    jQuery('input[name=summary]').val().replace(/\s+/, '') == '') {
                proceed = confirm(getLang('war_nosummary'));
            }

            if (proceed) {
                startProgressMonitor();
            }

            return proceed;
        });
    }

    function initializeCancel() {
        jQuery('input[name=cancel]').click(function() {
            batcheditServer.cancelOperation();
        });
    }

    function initialize() {
        initializeTooltip();
        initializeApplyCheckboxes();
        initializeTotalStatsFloater();
        initializeSearchMode();
        initializeMatchCase();
        initializeMultiline();
        initializeAdvancedOptions();
        initializeMatchContext();
        initializeSearchLimit();
        initializeKeepMarks();
        initializeApplyTemplatePatterns();
        initializeCheckSummary();
        initializePreview();
        initializeApply();
        initializeCancel();
    }

    return {
        initialize : initialize
    }
})();

jQuery(function () {
    batcheditInterface.initialize();
});
