/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { ICON_CONSTANTS } from './icon-constants';
import { sanitizeSvgContent, fetchIconContent, getCachedIcon, sanitizeExternalType, awaitIconDefinition, removeIconListener } from './icon-utils';
export class IconFoundation {
    constructor(_adapter) {
        this._adapter = _adapter;
        this._external = false;
        this._externalType = 'standard';
        this._lazyListener = () => this._loadIcon();
    }
    initialize() {
        this._applyIcon();
    }
    disconnect() {
        this._adapter.destroyVisibilityObserver();
        this._clearIconQueue();
        this._tryRemoveListener();
    }
    _safeApplyIcon() {
        if (!this._adapter.isConnected) {
            return;
        }
        this._clearIconQueue();
        this._queueIconUpdate();
    }
    _tryRemoveListener() {
        if (this._registrationListener && this._name) {
            removeIconListener(this._name, this._registrationListener);
        }
    }
    _applyIcon() {
        if (this._lazy && this._adapter.canLazyLoad()) {
            this._adapter.observeVisibility(this._lazyListener);
        }
        else {
            this._loadIcon();
        }
    }
    _clearIconQueue() {
        if (this._applyTimer) {
            clearTimeout(this._applyTimer);
            this._applyTimer = undefined;
        }
    }
    _queueIconUpdate() {
        this._applyTimer = window.setTimeout(() => {
            this._applyTimer = undefined;
            this._applyIcon();
        });
    }
    async _loadIcon() {
        try {
            if (this._src) {
                // We were provided direct icon source content so just set that
                this._setIconContent(this._src);
            }
            else if (this._name) {
                // Let's attempt to get our icon from the cache
                let content = this._tryGetIcon(this._name);
                if (!content) {
                    if (!this._external) {
                        // We attach a listener to the registry to let us know when the icon is registered
                        this._registrationListener = () => this._applyIcon();
                        awaitIconDefinition(this._name, this._registrationListener);
                        // For now, we render nothing...
                        this._adapter.setContent('');
                        return;
                    }
                    // We don't have a registry icon, so let's try the network to fetch it
                    if (!this._externalType) {
                        throw new Error(`Invalid external type provided for icon: ${this._name}`);
                    }
                    const url = this._getExternalUrl(this._name, this._externalType);
                    if (url) {
                        content = await fetchIconContent(url, this._name);
                    }
                }
                this._setIconContent(content);
            }
            else {
                this._adapter.setContent('');
            }
        }
        catch (e) {
            this._adapter.setContent('');
            throw e;
        }
    }
    _setIconContent(svgContent) {
        const content = sanitizeSvgContent(svgContent, this._viewbox);
        this._adapter.setContent(content);
    }
    _tryGetIcon(key) {
        return getCachedIcon(key);
    }
    _getExternalUrl(name, type) {
        if (typeof this._externalUrlBuilder === 'function') {
            return this._externalUrlBuilder(name, type);
        }
        const setName = sanitizeExternalType(this._externalType);
        return `${ICON_CONSTANTS.strings.DEFAULT_NETWORK_BASE_URL}${setName ? `/${setName}` : ''}/${name}.svg`;
    }
    get name() {
        return this._name;
    }
    set name(value) {
        if (this._name !== value) {
            // We need to remove our listener for the previous name if we have any
            if (!!this._registrationListener) {
                this._tryRemoveListener();
            }
            this._name = (value || '').replace(/\s+/, '');
            this._safeApplyIcon();
            this._adapter.toggleHostAttribute(ICON_CONSTANTS.attributes.NAME, !!this._name, this._name);
        }
    }
    get src() {
        return this._src;
    }
    set src(value) {
        if (this._src !== value) {
            this._src = value;
            if (this._adapter.isConnected) {
                this._applyIcon();
            }
        }
    }
    get lazy() {
        return this._lazy;
    }
    set lazy(value) {
        if (this._lazy !== value) {
            this._lazy = value;
            this._safeApplyIcon();
            this._adapter.setHostAttribute(ICON_CONSTANTS.attributes.LAZY, `${this._lazy}`);
        }
    }
    get external() {
        return this._external;
    }
    set external(value) {
        if (this._external !== value) {
            this._external = value;
            this._safeApplyIcon();
            this._adapter.setHostAttribute(ICON_CONSTANTS.attributes.EXTERNAL, `${this._external}`);
        }
    }
    get externalType() {
        return this._externalType;
    }
    set externalType(value) {
        if (this._externalType !== value) {
            this._externalType = value;
            this._safeApplyIcon();
            this._adapter.setHostAttribute(ICON_CONSTANTS.attributes.EXTERNAL_TYPE, `${this._externalType}`);
        }
    }
    get externalUrlBuilder() {
        return this._externalUrlBuilder;
    }
    set externalUrlBuilder(cb) {
        if (this._externalUrlBuilder !== cb) {
            this._externalUrlBuilder = cb;
            this._safeApplyIcon();
        }
    }
    get viewbox() {
        return this._viewbox;
    }
    set viewbox(value) {
        if (this._viewbox !== value) {
            this._viewbox = value;
            this._safeApplyIcon();
            this._adapter.setHostAttribute(ICON_CONSTANTS.attributes.VIEWBOX, `${this.viewbox}`);
        }
    }
    layout() {
        if (this._adapter.isConnected) {
            this._applyIcon();
        }
    }
}
