export class PortalUtils {
    static calculateAvailableSpace(referenceElement) {
        const rect = referenceElement.getBoundingClientRect();
        const viewportHeight = window.innerHeight;
        const spaceBelow = viewportHeight - rect.bottom;
        const spaceAbove = rect.top;
        return { spaceAbove, spaceBelow, viewportHeight };
    }
    static getOptimalPlacement(referenceElement) {
        const { spaceAbove, spaceBelow } = this.calculateAvailableSpace(referenceElement);
        if (spaceBelow < 200 && spaceAbove > spaceBelow) {
            return 'top';
        }
        return 'bottom';
    }
    static findBoundaryElements(component) {
        const boundaryElements = [];
        let currentElement = component.parentElement;
        while (currentElement && currentElement !== document.body) {
            const computedStyle = window.getComputedStyle(currentElement);
            const overflow = computedStyle.overflow;
            const overflowY = computedStyle.overflowY;
            const overflowX = computedStyle.overflowX;
            if (overflow === 'auto' || overflow === 'scroll' ||
                overflowY === 'auto' || overflowY === 'scroll' ||
                overflowX === 'auto' || overflowX === 'scroll') {
                boundaryElements.push(currentElement);
            }
            if (currentElement.hasAttribute('data-floating-boundary') ||
                currentElement.classList.contains('floating-boundary') ||
                currentElement.classList.contains('scroll-container')) {
                boundaryElements.push(currentElement);
            }
            currentElement = currentElement.parentElement;
        }
        return boundaryElements.length > 0 ? boundaryElements : undefined;
    }
    static calculateOptimalHeight(referenceRect, viewportHeight, placement) {
        const spaceBelow = viewportHeight - (referenceRect.y + referenceRect.height);
        const spaceAbove = referenceRect.y;
        if (spaceAbove > spaceBelow) {
            return Math.max(spaceAbove - 20, 100);
        }
        else if (spaceBelow > spaceAbove) {
            return Math.max(spaceBelow - 20, 100);
        }
        return Math.max(Math.min(spaceAbove, spaceBelow) - 20, 100);
    }
    static extractStylesAsCSS(styles) {
        if (typeof styles === 'string') {
            return styles;
        }
        if (Array.isArray(styles)) {
            return styles.map(style => this.extractStylesAsCSS(style)).join('\n');
        }
        if (styles && typeof styles === 'object' && styles.cssText) {
            return styles.cssText;
        }
        return '';
    }
    static generateStyleId() {
        return `nile-select-styles-${Math.random().toString(36).substring(2, 11)}`;
    }
    static isPositioningOptimal(placement, referenceElement) {
        const { spaceAbove, spaceBelow } = this.calculateAvailableSpace(referenceElement);
        const isAbove = placement.startsWith('top');
        const isBelow = placement.startsWith('bottom');
        if (isAbove && spaceBelow > spaceAbove)
            return false;
        if (isBelow && spaceAbove > spaceBelow)
            return false;
        return true;
    }
    static applyCollisionData(element, middlewareData, placement) {
        if (middlewareData.flip) {
            const { overflows } = middlewareData.flip;
            element.setAttribute('data-placement', placement);
            if (overflows && overflows.length > 0) {
                const overflowPlacements = overflows.map(overflow => overflow.placement).join(',');
                element.setAttribute('data-overflow', overflowPlacements);
            }
            else {
                element.removeAttribute('data-overflow');
            }
        }
        if (middlewareData.shift) {
            const { x, y } = middlewareData.shift;
            if (x !== undefined && y !== undefined && (x !== 0 || y !== 0)) {
                element.setAttribute('data-shift', `${x},${y}`);
            }
            else {
                element.removeAttribute('data-shift');
            }
        }
        if (middlewareData.size) {
            const { availableWidth, availableHeight } = middlewareData.size;
            if (availableWidth !== undefined) {
                element.setAttribute('data-available-width', availableWidth.toString());
            }
            if (availableHeight !== undefined) {
                element.setAttribute('data-available-height', availableHeight.toString());
            }
        }
    }
    static createFloatingUIMiddleware(boundary, onSizeApply) {
        return [];
    }
}
export class PortalContentUtils {
    static createBaseListbox(component) {
        const listbox = document.createElement('div');
        listbox.className = `select__listbox ${component.searchEnabled ? 'select__search-enabled ' : ''}`;
        listbox.setAttribute('tabindex', '-1');
        return listbox;
    }
    static addSearchSection(listbox, component) {
        if (!component.searchEnabled)
            return;
        const searchDiv = document.createElement('div');
        searchDiv.className = 'select__search';
        searchDiv.innerHTML = `
      <nile-input size="small" clearable value="${component.searchValue}" placeholder="${component.internalSearchPlaceHolder}">
        <nile-icon name="var(--nile-icon-search, var(--ng-icon-search-lg))" method="var(--nile-svg-method-fill, var(--ng-svg-method-stroke))" slot="suffix"></nile-icon>
      </nile-input>
    `;
        listbox.appendChild(searchDiv);
    }
    static addLoadingSection(listbox, component) {
        if (!component.optionsLoading)
            return;
        const loaderSpan = document.createElement('span');
        loaderSpan.className = 'select__loader';
        loaderSpan.innerHTML = `
      <nile-icon class="select__loader--icon" name="var(--nile-icon-button-loading-blue, var(--ng-icon-button-loading-blue))" method="var(--nile-svg-method-fill, var(--ng-svg-method-stroke))"></nile-icon>
    `;
        listbox.appendChild(loaderSpan);
    }
    static addOptionsSection(listbox, component) {
        const optionsContainer = document.createElement('div');
        optionsContainer.className = `select__options ${component.searchEnabled ? 'select__options__search-enabled' : ''}`;
        this.addNoResultsMessage(optionsContainer, component);
        this.addClonedOptions(optionsContainer, component);
        listbox.appendChild(optionsContainer);
    }
    static addNoResultsMessage(container, component) {
        if (!component.showNoResults)
            return;
        const noResultsDiv = document.createElement('div');
        noResultsDiv.className = 'select__no-results';
        noResultsDiv.textContent = component.noResultsMessage;
        container.appendChild(noResultsDiv);
    }
    static addClonedOptions(container, component) {
        const options = Array.from(component.querySelectorAll('nile-option'));
        options.forEach((option) => {
            const clonedOption = this.cloneOption(option);
            container.appendChild(clonedOption);
        });
    }
    static cloneOption(option) {
        const clonedOption = option.cloneNode(true);
        Array.from(option.attributes).forEach((attr) => {
            clonedOption.setAttribute(attr.name, attr.value);
        });
        this.copyOptionProperties(option, clonedOption);
        return clonedOption;
    }
    static copyOptionProperties(originalOption, clonedOption) {
        const properties = ['selected', 'disabled', 'current', 'hidden'];
        properties.forEach(prop => {
            if (originalOption[prop] !== undefined) {
                clonedOption[prop] = originalOption[prop];
            }
        });
    }
    static addFooterSection(listbox, component) {
        const hasCustomFooter = component.querySelectorAll('[slot="pre-footer"]').length > 0;
        const hasBuiltInFooter = component.multiple;
        if (!hasCustomFooter && !hasBuiltInFooter)
            return;
        const footerArea = document.createElement('div');
        footerArea.setAttribute('part', 'footer-area');
        footerArea.className = 'select__footer-area';
        if (hasCustomFooter) {
            this.addCustomFooter(footerArea, component);
        }
        if (hasBuiltInFooter) {
            const builtInFooter = this.createFooter(component);
            footerArea.appendChild(builtInFooter);
        }
        listbox.appendChild(footerArea);
    }
    static addCustomFooter(container, component) {
        const footerContent = Array.from(component.querySelectorAll('[slot="pre-footer"]'));
        if (footerContent.length === 0)
            return;
        const customFooter = document.createElement('div');
        customFooter.className = 'select__custom-footer';
        customFooter.setAttribute('part', 'custom-footer');
        footerContent.forEach((el) => {
            customFooter.appendChild(el.cloneNode(true));
        });
        customFooter.addEventListener('click', () => component.hide());
        container.appendChild(customFooter);
    }
    static createFooter(component) {
        const footerDiv = document.createElement('div');
        footerDiv.setAttribute('part', 'footer');
        footerDiv.className = 'select__footer';
        this.addShowSelectedToggle(footerDiv, component);
        this.addClearAllButton(footerDiv, component);
        return footerDiv;
    }
    static addShowSelectedToggle(footer, component) {
        const showSelectedSpan = document.createElement('span');
        showSelectedSpan.style.cursor = 'pointer';
        const checkbox = document.createElement('nile-checkbox');
        checkbox.disabled = component.selectedOptions.length === 0;
        checkbox.checked = component.showSelected;
        checkbox.innerHTML = '&nbsp; Show Selected';
        showSelectedSpan.appendChild(checkbox);
        footer.appendChild(showSelectedSpan);
    }
    static addClearAllButton(footer, component) {
        if (component.selectedOptions.length === 0)
            return;
        const clearAllSpan = document.createElement('span');
        clearAllSpan.className = 'select__clear';
        clearAllSpan.textContent = 'Clear All';
        clearAllSpan.style.cursor = 'pointer';
        footer.appendChild(clearAllSpan);
    }
    static updateClonedOptions(clonedListbox, component) {
        const optionsContainer = clonedListbox.querySelector('.select__options');
        if (!optionsContainer)
            return;
        const originalOptions = Array.from(component.querySelectorAll('nile-option'));
        const clonedOptions = Array.from(optionsContainer.querySelectorAll('nile-option'));
        originalOptions.forEach((originalOption, index) => {
            const clonedOption = clonedOptions[index];
            if (clonedOption) {
                this.updateClonedOption(originalOption, clonedOption);
            }
        });
    }
    static updateClonedOption(originalOption, clonedOption) {
        clonedOption.selected = originalOption.selected;
        clonedOption.disabled = originalOption.disabled;
        clonedOption.current = originalOption.current;
        clonedOption.hidden = originalOption.hidden;
        this.updateClonedOptionAttributes(originalOption, clonedOption);
    }
    static updateClonedOptionAttributes(originalOption, clonedOption) {
        const attributes = [
            { prop: 'selected', attr: 'selected' },
            { prop: 'disabled', attr: 'disabled' },
            { prop: 'current', attr: 'current' },
            { prop: 'hidden', attr: 'hidden' }
        ];
        attributes.forEach(({ prop, attr }) => {
            if (originalOption[prop]) {
                clonedOption.setAttribute(attr, '');
            }
            else {
                clonedOption.removeAttribute(attr);
            }
        });
    }
    static createPortalListbox(component) {
        const listbox = this.createBaseListbox(component);
        this.addSearchSection(listbox, component);
        this.addLoadingSection(listbox, component);
        this.addOptionsSection(listbox, component);
        this.addFooterSection(listbox, component);
        return listbox;
    }
}
export class PortalEventUtils {
    static setupPortalEventListeners(clonedListbox, component) {
        if (!clonedListbox)
            return;
        this.setupOptionClickListeners(clonedListbox, component);
        this.setupScrollListeners(clonedListbox, component);
        this.setupSearchListeners(clonedListbox, component);
        this.setupFooterListeners(clonedListbox, component);
        this.setupSlotListeners(clonedListbox, component);
    }
    static setupOptionClickListeners(clonedListbox, component) {
        if (!clonedListbox)
            return;
        clonedListbox.addEventListener('mouseup', (event) => {
            const target = event.target;
            const option = target.closest('nile-option');
            if (option) {
                this.handleOptionClick(option, component);
            }
        });
    }
    static handleOptionClick(option, component) {
        const originalOption = component.querySelector(`nile-option[value="${option.getAttribute('value')}"]`);
        if (originalOption) {
            const syntheticEvent = new MouseEvent('mouseup', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            Object.defineProperty(syntheticEvent, 'target', {
                value: originalOption,
                writable: false
            });
            if (component.handleOptionClick) {
                component.handleOptionClick(syntheticEvent);
            }
        }
    }
    static setupScrollListeners(clonedListbox, component) {
        if (!clonedListbox)
            return;
        clonedListbox.addEventListener('scroll', (event) => {
            if (component.handleScroll) {
                component.handleScroll(event);
            }
        });
    }
    static setupSearchListeners(clonedListbox, component) {
        if (!clonedListbox)
            return;
        const searchInput = clonedListbox.querySelector('nile-input');
        if (searchInput) {
            searchInput.addEventListener('nile-input', (event) => {
                if (component.handleSearchChange) {
                    component.handleSearchChange(event);
                }
            });
            searchInput.addEventListener('nile-focus', (event) => {
                if (component.handleSearchFocus) {
                    component.handleSearchFocus();
                }
            });
            searchInput.addEventListener('nile-blur', (event) => {
                if (component.handleSearchBlur) {
                    component.handleSearchBlur();
                }
            });
        }
    }
    static setupFooterListeners(clonedListbox, component) {
        if (!clonedListbox)
            return;
        const footer = clonedListbox.querySelector('.select__footer');
        if (footer) {
            this.setupFooterClickHandlers(footer);
            this.setupShowSelectedToggle(footer, component);
            this.setupClearAllHandler(footer, component);
        }
        this.setupCustomFooterListeners(clonedListbox, component);
    }
    static setupCustomFooterListeners(clonedListbox, component) {
        const customFooter = clonedListbox.querySelector('.select__custom-footer');
        if (!customFooter)
            return;
        customFooter.addEventListener('click', (event) => {
            event.stopPropagation();
        });
    }
    static setupFooterClickHandlers(footer) {
        footer.addEventListener('click', (event) => {
            event.stopPropagation();
            event.preventDefault();
        });
    }
    static setupShowSelectedToggle(footer, component) {
        const showSelectedSpan = footer.querySelector('span[style*="cursor: pointer"]');
        if (showSelectedSpan) {
            showSelectedSpan.addEventListener('click', (event) => {
                event.stopPropagation();
                event.preventDefault();
                if (component.toggleShowSelected) {
                    component.toggleShowSelected(event);
                }
            });
        }
    }
    static setupClearAllHandler(footer, component) {
        footer.addEventListener('click', (event) => {
            const target = event.target;
            if (target.classList.contains('select__clear')) {
                event.stopPropagation();
                event.preventDefault();
                if (component.unSlectAll) {
                    component.unSlectAll();
                }
            }
        });
    }
    static setupSlotListeners(clonedListbox, component) {
        if (!clonedListbox)
            return;
        const slot = clonedListbox.querySelector('slot');
        if (slot) {
            slot.addEventListener('slotchange', () => {
                if (component.updatePortalContent) {
                    component.updatePortalContent();
                }
            });
        }
    }
}
//# sourceMappingURL=portal-utils.js.map