import { __rest } from "tslib";
import * as React from 'react';
import styles from '@patternfly/react-styles/css/components/Select/select';
import badgeStyles from '@patternfly/react-styles/css/components/Badge/badge';
import formStyles from '@patternfly/react-styles/css/components/FormControl/form-control';
import buttonStyles from '@patternfly/react-styles/css/components/Button/button';
import { css } from '@patternfly/react-styles';
import TimesCircleIcon from '@patternfly/react-icons/dist/js/icons/times-circle-icon';
import { SelectMenu } from './SelectMenu';
import { SelectOption } from './SelectOption';
import { SelectToggle } from './SelectToggle';
import { SelectContext, SelectVariant, SelectDirection, KeyTypes } from './selectConstants';
import { Chip, ChipGroup } from '../ChipGroup';
import { keyHandler, getNextIndex, getOUIAProps } from '../../helpers';
import { Divider } from '../Divider';
// seed for the aria-labelledby ID
let currentId = 0;
export class Select extends React.Component {
    constructor() {
        super(...arguments);
        this.parentRef = React.createRef();
        this.filterRef = React.createRef();
        this.refCollection = [];
        this.state = {
            openedOnEnter: false,
            typeaheadInputValue: null,
            typeaheadActiveChild: null,
            typeaheadFilteredChildren: React.Children.toArray(this.props.children),
            typeaheadCurrIndex: -1,
            creatableValue: ''
        };
        this.componentDidUpdate = (prevProps, prevState) => {
            if (this.props.hasInlineFilter) {
                this.refCollection[0] = this.filterRef.current;
            }
            if (!prevState.openedOnEnter && this.state.openedOnEnter) {
                this.refCollection[0].focus();
            }
            if (prevProps.children !== this.props.children) {
                this.setState({
                    typeaheadFilteredChildren: React.Children.toArray(this.props.children)
                });
            }
            if (prevProps.selections !== this.props.selections && this.props.variant === SelectVariant.typeahead) {
                this.setState({
                    typeaheadInputValue: this.props.selections
                });
            }
        };
        this.onEnter = () => {
            this.setState({ openedOnEnter: true });
        };
        this.onClose = () => {
            this.setState({
                openedOnEnter: false,
                typeaheadInputValue: null,
                typeaheadActiveChild: null,
                typeaheadFilteredChildren: React.Children.toArray(this.props.children),
                typeaheadCurrIndex: -1
            });
        };
        this.onChange = (e) => {
            const { onFilter, isCreatable, onCreateOption, createText, noResultsFoundText, children } = this.props;
            let typeaheadFilteredChildren;
            if (onFilter) {
                typeaheadFilteredChildren = onFilter(e) || children;
            }
            else {
                let input;
                try {
                    input = new RegExp(e.target.value.toString(), 'i');
                }
                catch (err) {
                    input = new RegExp(e.target.value.toString().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
                }
                typeaheadFilteredChildren =
                    e.target.value.toString() !== ''
                        ? React.Children.toArray(this.props.children).filter(child => this.getDisplay(child.props.value.toString(), 'text').search(input) === 0)
                        : React.Children.toArray(this.props.children);
            }
            if (!typeaheadFilteredChildren) {
                typeaheadFilteredChildren = [];
            }
            if (typeaheadFilteredChildren.length === 0) {
                !isCreatable &&
                    typeaheadFilteredChildren.push(React.createElement(SelectOption, { isDisabled: true, key: 0, value: noResultsFoundText, isNoResultsOption: true }));
            }
            if (isCreatable && e.target.value !== '') {
                const newValue = e.target.value;
                typeaheadFilteredChildren.push(React.createElement(SelectOption, { key: 0, value: newValue, onClick: () => onCreateOption && onCreateOption(newValue) },
                    createText,
                    " \"",
                    newValue,
                    "\""));
            }
            this.setState({
                typeaheadInputValue: e.target.value,
                typeaheadCurrIndex: -1,
                typeaheadFilteredChildren,
                typeaheadActiveChild: null,
                creatableValue: e.target.value
            });
            this.refCollection = [];
        };
        this.onClick = (e) => {
            e.stopPropagation();
        };
        this.clearSelection = (e) => {
            e.stopPropagation();
            this.setState({
                typeaheadInputValue: null,
                typeaheadActiveChild: null,
                typeaheadFilteredChildren: React.Children.toArray(this.props.children),
                typeaheadCurrIndex: -1
            });
        };
        this.sendRef = (ref, index) => {
            this.refCollection[index] = ref;
        };
        this.handleArrowKeys = (index, position) => {
            keyHandler(index, 0, position, this.refCollection, this.refCollection);
        };
        this.handleFocus = () => {
            if (!this.props.isOpen) {
                this.props.onToggle(true);
            }
        };
        this.handleTypeaheadKeys = (position) => {
            const { isOpen, isCreatable, createText } = this.props;
            const { typeaheadActiveChild, typeaheadCurrIndex } = this.state;
            if (isOpen) {
                if (position === 'enter' && (typeaheadActiveChild || this.refCollection[0])) {
                    this.setState({
                        typeaheadInputValue: (typeaheadActiveChild && typeaheadActiveChild.innerText) || this.refCollection[0].innerText
                    });
                    if (typeaheadActiveChild) {
                        typeaheadActiveChild.click();
                    }
                    else {
                        this.refCollection[0].click();
                    }
                }
                else {
                    let nextIndex;
                    if (typeaheadCurrIndex === -1 && position === 'down') {
                        nextIndex = 0;
                    }
                    else if (typeaheadCurrIndex === -1 && position === 'up') {
                        nextIndex = this.refCollection.length - 1;
                    }
                    else {
                        nextIndex = getNextIndex(typeaheadCurrIndex, position, this.refCollection);
                    }
                    this.setState({
                        typeaheadCurrIndex: nextIndex,
                        typeaheadActiveChild: this.refCollection[nextIndex],
                        typeaheadInputValue: isCreatable && this.refCollection[nextIndex].innerText.includes(createText)
                            ? this.state.creatableValue
                            : this.refCollection[nextIndex].innerText
                    });
                }
            }
        };
        this.getDisplay = (value, type = 'node') => {
            if (!value) {
                return;
            }
            const item = this.props.isGrouped
                ? React.Children.toArray(this.props.children)
                    .reduce((acc, curr) => [...acc, ...React.Children.toArray(curr.props.children)], [])
                    .find(child => child.props.value.toString() === value.toString())
                : React.Children.toArray(this.props.children).find(child => child.props.value.toString() === value.toString());
            if (item) {
                if (item && item.props.children) {
                    if (type === 'node') {
                        return item.props.children;
                    }
                    return this.findText(item);
                }
                return item.props.value.toString();
            }
            return value;
        };
        this.findText = (item) => {
            if (!item.props || !item.props.children) {
                if (typeof item !== 'string') {
                    return '';
                }
                return item;
            }
            if (typeof item.props.children === 'string') {
                return item.props.children;
            }
            const multi = [];
            React.Children.toArray(item.props.children).forEach((child) => multi.push(this.findText(child)));
            return multi.join('');
        };
        this.generateSelectedBadge = () => {
            const { customBadgeText, selections } = this.props;
            if (customBadgeText !== null) {
                return customBadgeText;
            }
            if (Array.isArray(selections) && selections.length > 0) {
                return selections.length;
            }
            return null;
        };
    }
    extendTypeaheadChildren(typeaheadActiveChild) {
        return this.state.typeaheadFilteredChildren.map((child) => React.cloneElement(child, {
            isFocused: typeaheadActiveChild &&
                (typeaheadActiveChild.innerText ===
                    this.getDisplay(child.props.value.toString(), 'text') ||
                    (this.props.isCreatable &&
                        typeaheadActiveChild.innerText === `{createText} "${child.props.value}"`))
        }));
    }
    render() {
        const _a = this.props, { children, className, customContent, variant, direction, onToggle, onSelect, onClear, toggleId, isOpen, isGrouped, isPlain, isDisabled, selections: selectionsProp, typeAheadAriaLabel, clearSelectionsAriaLabel, toggleAriaLabel, removeSelectionAriaLabel, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, placeholderText, width, maxHeight, toggleIcon, ouiaId, hasInlineFilter, isCheckboxSelectionBadgeHidden, inlineFilterPlaceholderText, 
        /* eslint-disable @typescript-eslint/no-unused-vars */
        onFilter, onCreateOption, isCreatable, createText, noResultsFoundText, customBadgeText } = _a, 
        /* eslint-enable @typescript-eslint/no-unused-vars */
        props = __rest(_a, ["children", "className", "customContent", "variant", "direction", "onToggle", "onSelect", "onClear", "toggleId", "isOpen", "isGrouped", "isPlain", "isDisabled", "selections", "typeAheadAriaLabel", "clearSelectionsAriaLabel", "toggleAriaLabel", "removeSelectionAriaLabel", 'aria-label', 'aria-labelledby', "placeholderText", "width", "maxHeight", "toggleIcon", "ouiaId", "hasInlineFilter", "isCheckboxSelectionBadgeHidden", "inlineFilterPlaceholderText", "onFilter", "onCreateOption", "isCreatable", "createText", "noResultsFoundText", "customBadgeText"]);
        const { openedOnEnter, typeaheadInputValue, typeaheadActiveChild, typeaheadFilteredChildren } = this.state;
        const selectToggleId = toggleId || `pf-toggle-id-${currentId++}`;
        const selections = Array.isArray(selectionsProp) ? selectionsProp : [selectionsProp];
        const hasAnySelections = Boolean(selections[0] && selections[0] !== '');
        let childPlaceholderText = null;
        if (!customContent) {
            if (!hasAnySelections && !placeholderText) {
                const childPlaceholder = React.Children.toArray(children).filter((child) => child.props.isPlaceholder === true);
                childPlaceholderText =
                    (childPlaceholder[0] && this.getDisplay(childPlaceholder[0].props.value, 'node')) ||
                        (children[0] && this.getDisplay(children[0].props.value, 'node'));
            }
        }
        const hasOnClear = onClear !== Select.defaultProps.onClear;
        const clearBtn = (React.createElement("button", { className: css(buttonStyles.button, buttonStyles.modifiers.plain, styles.selectToggleClear), onClick: e => {
                this.clearSelection(e);
                onClear(e);
            }, "aria-label": clearSelectionsAriaLabel, type: "button", disabled: isDisabled },
            React.createElement(TimesCircleIcon, { "aria-hidden": true })));
        let selectedChips = null;
        if (variant === SelectVariant.typeaheadMulti) {
            selectedChips = (React.createElement(ChipGroup, null, selections &&
                selections.map(item => (React.createElement(Chip, { key: item, onClick: (e) => onSelect(e, item), closeBtnAriaLabel: removeSelectionAriaLabel }, this.getDisplay(item, 'node'))))));
        }
        let filterWithChildren = children;
        if (hasInlineFilter) {
            const filterBox = (React.createElement(React.Fragment, null,
                React.createElement("div", { key: "inline-filter", className: css(styles.selectMenuSearch) },
                    React.createElement("input", { key: "inline-filter-input", type: "search", className: css(formStyles.formControl, formStyles.modifiers.search), onChange: this.onChange, placeholder: inlineFilterPlaceholderText, onKeyDown: event => {
                            if (event.key === KeyTypes.ArrowUp) {
                                this.handleArrowKeys(0, 'up');
                            }
                            else if (event.key === KeyTypes.ArrowDown) {
                                this.handleArrowKeys(0, 'down');
                            }
                        }, ref: this.filterRef, autoComplete: "off" })),
                React.createElement(Divider, { key: "inline-filter-divider" })));
            this.refCollection[0] = this.filterRef.current;
            filterWithChildren = [filterBox, ...typeaheadFilteredChildren].map((option, index) => React.cloneElement(option, { key: index }));
        }
        let variantProps;
        let variantChildren;
        if (customContent) {
            variantProps = {
                selected: selections,
                openedOnEnter,
                isCustomContent: true
            };
            variantChildren = customContent;
        }
        else {
            switch (variant) {
                case 'single':
                    variantProps = {
                        selected: selections[0],
                        openedOnEnter
                    };
                    variantChildren = children;
                    break;
                case 'checkbox':
                    variantProps = {
                        checked: selections,
                        isGrouped,
                        hasInlineFilter
                    };
                    variantChildren = filterWithChildren;
                    break;
                case 'typeahead':
                    variantProps = {
                        selected: selections[0],
                        openedOnEnter
                    };
                    variantChildren = this.extendTypeaheadChildren(typeaheadActiveChild);
                    break;
                case 'typeaheadmulti':
                    variantProps = {
                        selected: selections,
                        openedOnEnter
                    };
                    variantChildren = this.extendTypeaheadChildren(typeaheadActiveChild);
                    break;
            }
        }
        return (React.createElement("div", Object.assign({ className: css(styles.select, isOpen && styles.modifiers.expanded, direction === SelectDirection.up && styles.modifiers.top, className), ref: this.parentRef, style: { width } }, getOUIAProps('Select', ouiaId)),
            React.createElement(SelectContext.Provider, { value: { onSelect, onClose: this.onClose, variant } },
                React.createElement(SelectToggle, { id: selectToggleId, parentRef: this.parentRef, isOpen: isOpen, isPlain: isPlain, onToggle: onToggle, onEnter: this.onEnter, onClose: this.onClose, variant: variant, "aria-labelledby": `${ariaLabelledBy || ''} ${selectToggleId}`, "aria-label": toggleAriaLabel, handleTypeaheadKeys: this.handleTypeaheadKeys, isDisabled: isDisabled, hasClearButton: hasOnClear },
                    customContent && (React.createElement("div", { className: css(styles.selectToggleWrapper) },
                        toggleIcon && React.createElement("span", { className: css(styles.selectToggleIcon) }, toggleIcon),
                        React.createElement("span", { className: css(styles.selectToggleText) }, placeholderText))),
                    variant === SelectVariant.single && !customContent && (React.createElement(React.Fragment, null,
                        React.createElement("div", { className: css(styles.selectToggleWrapper) },
                            toggleIcon && React.createElement("span", { className: css(styles.selectToggleIcon) }, toggleIcon),
                            React.createElement("span", { className: css(styles.selectToggleText) }, this.getDisplay(selections[0], 'node') || placeholderText || childPlaceholderText)),
                        hasOnClear && hasAnySelections && clearBtn)),
                    variant === SelectVariant.checkbox && !customContent && (React.createElement(React.Fragment, null,
                        React.createElement("div", { className: css(styles.selectToggleWrapper) },
                            toggleIcon && React.createElement("span", { className: css(styles.selectToggleIcon) }, toggleIcon),
                            React.createElement("span", { className: css(styles.selectToggleText) }, placeholderText),
                            !isCheckboxSelectionBadgeHidden && hasAnySelections && (React.createElement("div", { className: css(styles.selectToggleBadge) },
                                React.createElement("span", { className: css(badgeStyles.badge, badgeStyles.modifiers.read) }, this.generateSelectedBadge())))),
                        hasOnClear && hasAnySelections && clearBtn)),
                    variant === SelectVariant.typeahead && !customContent && (React.createElement(React.Fragment, null,
                        React.createElement("div", { className: css(styles.selectToggleWrapper) },
                            toggleIcon && React.createElement("span", { className: css(styles.selectToggleIcon) }, toggleIcon),
                            React.createElement("input", { className: css(formStyles.formControl, styles.selectToggleTypeahead), "aria-activedescendant": typeaheadActiveChild && typeaheadActiveChild.id, id: `${selectToggleId}-select-typeahead`, "aria-label": typeAheadAriaLabel, placeholder: placeholderText, value: typeaheadInputValue !== null
                                    ? typeaheadInputValue
                                    : this.getDisplay(selections[0], 'text') || '', type: "text", onClick: this.onClick, onChange: this.onChange, onFocus: this.handleFocus, autoComplete: "off", disabled: isDisabled })),
                        (selections[0] || typeaheadInputValue) && clearBtn)),
                    variant === SelectVariant.typeaheadMulti && !customContent && (React.createElement(React.Fragment, null,
                        React.createElement("div", { className: css(styles.selectToggleWrapper) },
                            toggleIcon && React.createElement("span", { className: css(styles.selectToggleIcon) }, toggleIcon),
                            selections && (Array.isArray(selections) && selections.length > 0) && selectedChips,
                            React.createElement("input", { className: css(formStyles.formControl, styles.selectToggleTypeahead), "aria-activedescendant": typeaheadActiveChild && typeaheadActiveChild.id, id: `${selectToggleId}-select-multi-typeahead-typeahead`, "aria-label": typeAheadAriaLabel, placeholder: placeholderText, value: typeaheadInputValue !== null ? typeaheadInputValue : '', type: "text", onChange: this.onChange, onClick: this.onClick, onFocus: this.handleFocus, autoComplete: "off", disabled: isDisabled })),
                        ((selections && selections.length > 0) || typeaheadInputValue) && clearBtn))),
                isOpen && (React.createElement(SelectMenu, Object.assign({}, props, { isGrouped: isGrouped, selected: selections }, variantProps, { openedOnEnter: openedOnEnter, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, sendRef: this.sendRef, keyHandler: this.handleArrowKeys, maxHeight: maxHeight }), variantChildren)))));
    }
}
Select.defaultProps = {
    children: [],
    className: '',
    direction: SelectDirection.down,
    toggleId: null,
    isOpen: false,
    isGrouped: false,
    isPlain: false,
    isDisabled: false,
    isCreatable: false,
    'aria-label': '',
    'aria-labelledby': '',
    typeAheadAriaLabel: '',
    clearSelectionsAriaLabel: 'Clear all',
    toggleAriaLabel: 'Options menu',
    removeSelectionAriaLabel: 'Remove',
    selections: [],
    createText: 'Create',
    placeholderText: '',
    noResultsFoundText: 'No results found',
    variant: SelectVariant.single,
    width: '',
    onClear: () => undefined,
    onCreateOption: () => undefined,
    toggleIcon: null,
    onFilter: null,
    customContent: null,
    hasInlineFilter: false,
    inlineFilterPlaceholderText: null,
    customBadgeText: null
};
//# sourceMappingURL=Select.js.map