export default class InputStatusModule {

    private $originalElement: JQuery;
    private $elementToCover: JQuery;

    private $iconElement: JQuery;
    private $iconWrapperElement: JQuery;
    
    private originalButtonHtml: string;

    constructor($element: JQuery) {
        this.$originalElement = $element;
        this.createIconElement(this.$originalElement);
    }

    public showLoading() {

        if (this.$iconElement === undefined) {
            console.log("Called showLoading() when this.$iconElement was undefined");
            return;
        }
            
        this.$iconElement.removeClass("loading success warning error");
        this.$iconElement.addClass("loading");

        if (this.$elementToCover !== undefined) {
            this.$elementToCover.removeClass("input-success input-warning input-danger");
        }
    }

    public showSuccess() {

        if (this.$iconElement === undefined) {
            console.log("Called showSuccess() when this.$iconElement was undefined");
            return;
        }

        this.$iconElement.removeClass("loading success warning error");
        this.$iconElement.addClass("success");

        if (this.$elementToCover !== undefined) {
            this.$elementToCover.removeClass("input-success input-warning input-danger");
            this.$elementToCover.addClass("input-success");
        }
    }

    public showWarning() {

        if (this.$iconElement === undefined) {
            console.log("Called showWarning() when this.$iconElement was undefined");
            return;
        }
        
        this.$iconElement.removeClass("loading success warning error");
        this.$iconElement.addClass("warning");

        if (this.$elementToCover !== undefined) {
            this.$elementToCover.removeClass("input-success input-warning input-danger");
            this.$elementToCover.addClass("input-warning");
        }
    }

    public showError() {

        if (this.$iconElement === undefined) {
            console.log("Called showError() when this.$iconElement was undefined");
            return;
        }

        this.$iconElement.removeClass("loading success warning error");
        this.$iconElement.addClass("error");

        if (this.$elementToCover !== undefined) {
            this.$elementToCover.removeClass("input-success input-warning input-danger");
            this.$elementToCover.addClass("input-danger");
        }
    }

    public removeWithFadeOut(doneCallback?: () => void) {
        
        const self = this;
        const animationEndEvent = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";

        this.$iconElement.on(animationEndEvent,
            function() {
                self.remove();
                if (doneCallback !== undefined) {
                    doneCallback();
                }
            });

        this.$iconElement.addClass("animated fadeOut");

        // Manually trigger animationend if animations are disabled on OS
        const animationsDisabled = window.matchMedia("prefers-reduced-motion").matches;
        if (animationsDisabled === true) {
            this.$iconElement.trigger("animationend");
        }
    }

    public remove() {
        this.$iconElement.remove();
        this.$iconElement = undefined;
        
        if (this.$elementToCover !== undefined) {
            this.$elementToCover.removeClass("input-success input-warning input-danger");
        }

        if (this.$iconWrapperElement !== undefined) {
            this.$iconWrapperElement.remove();
            this.$iconWrapperElement = undefined;
        }

        if (this.$originalElement.prop("nodeName") === "BUTTON") {
            this.$originalElement.html(this.originalButtonHtml);
        }

        this.$originalElement = undefined;
    }

    public isInitialised() {
        return this.$iconElement !== undefined;
    }

    private createIconElement($element: JQuery): void {

        if ($element.prop("nodeName") === "BUTTON") {
            this.createIconElementForButton($element);
        } else {
            this.createIconElementForInput($element);
        }
        
    }
    private createIconElementForButton($element: JQuery): void {

        this.originalButtonHtml = $element.html();

        this.$iconWrapperElement = $("<div></div>");
        this.$iconWrapperElement.addClass("element-status-icon-wrapper");

        this.$iconElement = $("<div></div>");
        this.$iconElement.addClass("element-status-icon");
        this.$iconElement.addClass("element-type-button");

        this.$iconWrapperElement.append(this.$iconElement);

        $element.html("");
        $element.append(this.$iconWrapperElement);
    }

    private createIconElementForInput($element: JQuery): void {
        this.$elementToCover = $element;

        let isSelect2 = false;
        if ($element.hasClass("select2-hidden-accessible")) {
            isSelect2 = true;
            this.$elementToCover = $element.next("span.select2");
        }

        const offsetPosition = this.$elementToCover.position();

        this.$iconElement = $("<div></div>");

        this.$iconElement.css("position", "absolute");

        this.$iconElement.css("top", offsetPosition.top);

        this.$iconElement.addClass("element-status-icon");

        const isCheckbox = $element.prop("type") === "checkbox";
        if (isCheckbox === true) {
            this.$iconElement.addClass("updating-checkbox");
        } else {
            const width = this.$elementToCover.outerWidth();

            let left = offsetPosition.left + width - 40;

            if (isSelect2 === true) {
                left = left - 30;
            }

            this.$iconElement.css("left", left);
            this.$iconElement.css("width", 40);
            this.$iconElement.css("height", this.$elementToCover.outerHeight());
        }

        this.$iconElement.on("click", function() {

            if (isSelect2 === true) {
                $element.select2("open");
            } else {
                $element.focus();
            }

        });

        const isSwitch = this.$elementToCover.hasClass("switch");
        if (isSwitch === true) {
            this.$iconElement.addClass("updating-switch");
            this.$elementToCover.parent(".switch-container").before(this.$iconElement);
        } else if (isCheckbox === true) {
            this.$elementToCover.before(this.$iconElement);
        } else {
            this.$elementToCover.after(this.$iconElement);
        }
    }
}
