(function ($) {
    $.fn.customSelect = function (data) {
        this.each((index, value) => {
            generateCustomSelect($(value));

            if ($(value).hasClass("inputSelect"))
                createInputForSelect($(value));
        });
    };

    function generateCustomSelect($element) {
        $element.off("mousedown.customSelect");
        $element.on("mousedown.customSelect", function (e) {
            e.preventDefault();
            this.blur();
            window.focus();

            $element.attr("data-initial", $element.val());
            openCustomSelect($element);
        });
    }

    function createInputForSelect($element) {
        if ($("#" + $element.attr("input-id")).length === 0 && $element.parent().find('input.inputOnSelect').length === 0) {
            $element.parent().append('<input value="' + $element.attr("input-val") + '" data-val="' + $element.attr("input-val") + '"' +
                ' class= "' + $element.attr("input-class") + '" name = "' + $element.attr("input-id") + '"' +
                ' id="' + $element.attr("input-id") + '" onblur="' + $element.attr("input-onblur") + '"' + ($element.attr("input-disabled") ? ' readonly' : "") +
                ' step="' + $element.attr("input-step") + '" onfocus="this.select()" autocomplete="off" type="text">');
        }
    }

    function openCustomSelect($element) {
        if ($element.hasClass("custom-select-open")) {
            closeAllCustomSelects();
            return;
        }

        closeAllCustomSelects();
        $element.addClass("custom-select-open");

        let $select = $("<div class='custom-select-container'></div>");
        let selectedVal = $element.val();
        $element.find("option").each((index, value) => {
            $select.append(generateCustomSelectOption($element, $(value), selectedVal === $(value).val()));
        });

        let positionLeft = $element.offset().left - $(window).scrollLeft();
        let positionTop = $element.offset().top - $(window).scrollTop() + $element.outerHeight();
        let maxWidth = $element.width() * 2 < 250 ? 130 : $element.width();

        $select.css("top", positionTop).css("left", positionLeft).css("min-width", $element.innerWidth()).css("visibility", "hidden");
        if (maxWidth < $(window).width() / 3) $select.css("max-width", maxWidth);

        $("body").append($select);
        $element.focus();
        $element.on("keydown.customSelect", function (e) {
            if (e.keyCode === 13) {
                e.preventDefault();
                $select.find(".custom-select-option-selected").trigger("click");
            }
        });
        $element.on("keyup.customSelect", function () {
            $select.find(".custom-select-option-selected").removeClass("custom-select-option-selected");

            let $selectedElement = $select.find("div[data-val='" + $(this).val() + "']");
            $selectedElement.addClass("custom-select-option-selected");
            if ($selectedElement.length > 0) $selectedElement[0].scrollIntoView();
        });
        $element.on("blur.customSelect", function () {
            $element.off("keydown.customSelect");
            $element.off("keyup.customSelect");
            $element.off("blur.customSelect");
        });

        if (positionTop + $select.outerHeight() + 2 > $(window).height())
            $select.css("top", positionTop - (positionTop + $select.outerHeight() - $(window).height()) - 2);

        if (positionLeft + $select.outerWidth() + 2 > $(window).width())
            $select.css("left", positionLeft - (positionLeft + $select.outerWidth() - $(window).width()) - 2);

        let $selectedOption = $select.find(".custom-select-option-selected");
        if ($selectedOption.length > 0) $selectedOption[0].scrollIntoView();

        $select.css("visibility", "visible");
    }

    function generateCustomSelectOption($select, $option, selected) {
        let val = $option.val();
        let $customOption = $("<div class='custom-select-option " + ($option.attr("hidden") ? 'hidden' : '') + "' data-val='" + val + "'>" + ($option.attr("data-displaytext") ? $option.attr("data-displaytext") : $option.text()) + "</div>");

        if (selected) $customOption.addClass("custom-select-option-selected");

        $customOption.on("click", function () {
            $select.val(val);
            $select.trigger("change");
            closeAllCustomSelects();
        });

        return $customOption;
    }
}(jQuery));

function closeAllCustomSelects() {
    let currentValue = $(".custom-select-open").val();
    let initialValue = $(".custom-select-open").attr("data-initial");
    if (currentValue && initialValue && initialValue !== currentValue) {
        $(".custom-select-open").trigger("customSelectChange");
    }
    $(".custom-select-open").removeClass("custom-select-open");
    $(".custom-select-container").remove();
}

function setInputSelectFocus() {
    $(".inputSelect").focus(function () {
        $(this).next().focus();
    });

    $(".inputSelect").on("change", function () {
        $(this).next().focus();
    });
}

$(document).ready(function () {
    $(".custom-select").customSelect();

    $(window).resize(function () {
        closeAllCustomSelects();
    });

    $(window).scroll(function () {
        closeAllCustomSelects();
    });

    $(window).mousedown(function (e) {
        if ($(e.target).hasClass('custom-select-container') || $(e.target).hasClass('custom-select-option') || $(e.target).hasClass('custom-select')) return;

        closeAllCustomSelects();
    });

    setInputSelectFocus();
});