/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { isDefined } from '@tylertech/forge-core';
import { BUSY_INDICATOR_CONSTANTS } from './busy-indicator-constants';
/**
 * Provides facilities and helper methods for creating a busy indicator component.
 */
export class BusyIndicatorFoundation {
    constructor(_adapter) {
        this._adapter = _adapter;
        this._canCancel = false;
        this._showSpinner = true;
        this._showProgressBar = false;
        this._progressBarDeterminate = false;
        this._progress = 0;
        this._buffer = 0;
        this._cancelListenerAttached = false;
        this._direction = 'row';
        this._manageFocus = true;
        this._fixed = true;
    }
    destroy() {
        this._adapter.removeCancelButtonEventListener('click', this._onCancelClick);
    }
    show() {
        this._applyDirection();
        this._adapter.setParentAttribute(BUSY_INDICATOR_CONSTANTS.attributes.PARENT_OPEN, 'true');
        this._adapter.setHostAttribute('tabindex', '0');
        this._adapter.setSurfaceOpacity(0);
        this._adapter.setFixed(this._fixed);
        if (!this._titleText) {
            this._adapter.setTitleVisibility(false);
        }
        if (this._message) {
            this._adapter.setMessage(this._message);
        }
        this._adapter.setMessageVisibility(!!this._message);
        if (!this._canCancel) {
            this._adapter.setCancelButtonVisibility(false);
        }
        else {
            this._attachCancelClickListener();
        }
        if (!this._showSpinner) {
            this._adapter.setSpinnerVisibility(false);
        }
        if (!this._showProgressBar) {
            this._adapter.setProgressBarVisibility(false);
        }
        else {
            this._adapter.setProgressBarDeterminate(this._progressBarDeterminate);
            this._adapter.setProgressBarProgress(this._progress);
            this._adapter.setProgressBarBuffer(this._buffer);
        }
        if (this._width) {
            this._adapter.setSurfaceWidth(typeof this._width === 'number' ? `${this._width}px` : this._width);
        }
        if ((!this._message || this._message.length === 0) && this._showSpinner && (!this.titleText || this._titleText.length === 0) && !this._canCancel) {
            this._adapter.setContainerInvisible();
            this._adapter.setBackdropAppearance('light');
        }
        this.fadeIn();
    }
    /**
     * Removes the element from the DOM.
     * @param {boolean} [force=false] Whether to force removal of the busy indicator or not.
     */
    hide(force = false) {
        if (force) {
            if (this._manageFocus) {
                this._releaseFocus();
            }
            this._adapter.remove();
            this._adapter.removeParentAttribute(BUSY_INDICATOR_CONSTANTS.attributes.PARENT_OPEN);
        }
        else {
            this.fadeOut();
            this._adapter.hideBackdrop();
            setTimeout(() => {
                if (this._manageFocus) {
                    this._releaseFocus();
                }
                this._adapter.remove();
                this._adapter.removeParentAttribute(BUSY_INDICATOR_CONSTANTS.attributes.PARENT_OPEN);
            }, BUSY_INDICATOR_CONSTANTS.numbers.TRANSITION_LENGTH);
        }
    }
    /** Sets the elements opacity to 0 which triggers the CSS transition to fade out. */
    fadeOut() {
        this._adapter.setSurfaceOpacity(0);
    }
    /** Sets the elements opacity to 1 which triggers the CSS transition to fade in after the current delay value. */
    fadeIn() {
        this._adapter.setSurfaceOpacity(1);
        if (this._manageFocus) {
            this._captureFocus();
        }
    }
    /** Attaches the click listener to the cancel button. */
    _attachCancelClickListener() {
        if (!this._cancelListenerAttached) {
            this._adapter.addCancelButtonEventListener('click', this._onCancelClick.bind(this));
            this._cancelListenerAttached = true;
        }
    }
    /** Handles clicks on the cancel button. */
    _onCancelClick() {
        this._adapter.setCancelButtonAttribute('disabled', 'disabled');
        this._adapter.setCancelButtonText(BUSY_INDICATOR_CONSTANTS.strings.CANCELLING);
        this._adapter.removeCancelButtonEventListener('click', this._onCancelClick);
        this._adapter.emitHostEvent(BUSY_INDICATOR_CONSTANTS.events.CANCEL);
    }
    /** Cache currently focused element, set focus to the busy indicator. */
    _captureFocus() {
        this._previouslyFocusedElement = this._adapter.getFocusedElement();
        this._adapter.captureFocus();
    }
    /** Gives focus back to the element that had it when the busy indicator was displayed. */
    _releaseFocus() {
        if (this._previouslyFocusedElement && this._adapter.hasFocus()) {
            this._previouslyFocusedElement.focus();
        }
    }
    /** The title to be displayed. */
    set titleText(value) {
        if (this._titleText !== value) {
            this._titleText = value;
            this._adapter.setTitle(this._titleText);
            this._adapter.setTitleVisibility(!!this._titleText);
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.TITLE_TEXT, this._titleText);
        }
    }
    get titleText() {
        return this._titleText;
    }
    /** The message to be displayed. */
    set message(value) {
        if (this._message !== value) {
            this._message = value;
            this._adapter.setMessage(this._message);
            this._adapter.setMessageVisibility(!!this._message);
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.MESSAGE, this._message);
        }
    }
    get message() {
        return this._message;
    }
    /** Controls whether the cancel button is visible or not. */
    set cancel(canCancel) {
        if (this._canCancel !== canCancel) {
            this._canCancel = canCancel;
            this._adapter.setCancelButtonVisibility(!!this._canCancel);
            if (this._canCancel) {
                this._attachCancelClickListener();
            }
            else {
                this._adapter.removeCancelButtonEventListener('click', this._onCancelClick);
            }
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.CANCEL, this._canCancel.toString());
        }
    }
    get cancel() {
        return this._canCancel;
    }
    /** Controls whether the progress spinner is visible or not. */
    set spinner(showSpinner) {
        if (this._showSpinner !== showSpinner) {
            this._showSpinner = showSpinner;
            this._adapter.setSpinnerVisibility(!!this._showSpinner);
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.SPINNER, '' + this._showSpinner);
        }
    }
    get spinner() {
        return this._showSpinner;
    }
    /** Controls whether the progres bar is visible or not. */
    set progressBar(showProgressBar) {
        if (this._showProgressBar !== showProgressBar) {
            this._showProgressBar = showProgressBar;
            this._adapter.setProgressBarVisibility(!!this._showProgressBar);
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.PROGRESS_BAR, this._showProgressBar.toString());
        }
    }
    get progressBar() {
        return this._showProgressBar;
    }
    /** Sets the progress bar mode. */
    set progressBarDeterminate(determinate) {
        if (this._progressBarDeterminate !== determinate) {
            this._progressBarDeterminate = determinate;
            this._adapter.setProgressBarDeterminate(determinate);
        }
    }
    get progressBarDeterminate() {
        return this._progressBarDeterminate;
    }
    /** The progress amount of the progress bar. */
    set progress(value) {
        if (this._progress !== value && this._progressBarDeterminate) {
            this._progress = value;
            this._adapter.setProgressBarProgress(value);
        }
    }
    get progress() {
        return this._progress;
    }
    /** The buffer amount of the progress bar. */
    set buffer(value) {
        if (this._buffer !== value && this._progressBarDeterminate) {
            this._buffer = value;
            this._adapter.setProgressBarBuffer(value);
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.BUFFER, isDefined(this._buffer) ? this._buffer.toString() : '0');
        }
    }
    get buffer() {
        return this._buffer;
    }
    get direction() {
        return this._direction;
    }
    set direction(value) {
        if (value !== this._direction) {
            this._direction = value;
            this._applyDirection();
        }
    }
    _applyDirection() {
        if (this._direction) {
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.DIRECTION, String(this._direction));
        }
    }
    /** Sets the width of the busy indicator element. */
    set width(value) {
        if (this._width !== value) {
            if (typeof value === 'number' && value < 0) {
                value = 'auto';
            }
            this._width = value;
            this._adapter.setSurfaceWidth(typeof this._width === 'number' ? `${this._width}px` : this._width);
            this._adapter.setHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.WIDTH, this._width.toString());
        }
    }
    get width() {
        return this._width;
    }
    get manageFocus() {
        return this._manageFocus;
    }
    set manageFocus(value) {
        if (this._manageFocus !== value) {
            this._manageFocus = value;
            this._adapter.toggleHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.MANAGE_FOCUS, this._manageFocus);
        }
    }
    get fixed() {
        return this._fixed;
    }
    set fixed(value) {
        if (this._fixed !== value) {
            this._fixed = value;
            this._adapter.setFixed(this._fixed);
            this._adapter.toggleHostAttribute(BUSY_INDICATOR_CONSTANTS.attributes.FIXED, this._fixed);
        }
    }
}
