"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColumnsSection = exports.ColumnsSectionSummary = void 0;
const tslib_1 = require("tslib");
const InfiniteTable_1 = require("../../../../components/InfiniteTable");
const React = tslib_1.__importStar(require("react"));
const rebass_1 = require("rebass");
const DropdownButton_1 = tslib_1.__importDefault(require("../../../../components/DropdownButton"));
const FormLayout_1 = tslib_1.__importStar(require("../../../../components/FormLayout"));
const Input_1 = tslib_1.__importDefault(require("../../../../components/Input"));
const SimpleButton_1 = tslib_1.__importDefault(require("../../../../components/SimpleButton"));
const Tabs_1 = require("../../../../components/Tabs");
const Tag_1 = require("../../../../components/Tag");
const AdaptableColumn_1 = require("../../../../AdaptableState/Common/AdaptableColumn");
const AdaptableContext_1 = require("../../../AdaptableContext");
const ValueSelector_1 = require("../../../Components/ValueSelector");
const OnePageAdaptableWizard_1 = require("../../../Wizard/OnePageAdaptableWizard");
const Utilities_1 = require("./Utilities");
const icons_1 = require("../../../../components/icons");
const CheckBox_1 = require("../../../../components/CheckBox");
const Helper_1 = require("../../../../Utilities/Helpers/Helper");
const ColumnLabels_1 = require("../Components/ColumnLabels");
const ArrayExtensions_1 = tslib_1.__importDefault(require("../../../../Utilities/Extensions/ArrayExtensions"));
const ColumnApiImpl_1 = require("../../../../Api/Implementation/ColumnApiImpl");
const ReorderDraggable_1 = require("../../../Components/ReorderDraggable");
const AdaptableFormControlTextClear_1 = require("../../../Components/Forms/AdaptableFormControlTextClear");
const sortColumnIdsByOrder_1 = require("../../../../layout-manager/src/sortColumnIdsByOrder");
const HelpBlock_1 = tslib_1.__importDefault(require("../../../../components/HelpBlock"));
const GeneralConstants_1 = require("../../../../Utilities/Constants/GeneralConstants");
const isPivotLayout_1 = require("../../../../Utilities/isPivotLayout");
const PropertyOrderText = (props) => (React.createElement(rebass_1.Text, { fontWeight: 600, fontSize: 2 }, props.children));
const columnTypes = {
    default: {
        defaultFlex: 1,
    },
};
const ColumnsSectionSummary = () => {
    const adaptable = (0, AdaptableContext_1.useAdaptable)();
    const { data: layout } = (0, OnePageAdaptableWizard_1.useOnePageAdaptableWizardContext)();
    const rowHeight = 40;
    const headerHeight = 40;
    const ColumnIds = layout.TableColumns || layout.PivotColumns || [];
    const tableHeight = headerHeight + (0, Helper_1.clamp)(rowHeight * ColumnIds.length, 100, 360);
    const data = React.useMemo(() => {
        return ColumnIds.map((columnId) => {
            if (adaptable.api.columnApi.isPivotResultColumn(columnId) ||
                adaptable.api.columnApi.isAutoRowGroupColumn(columnId)) {
                return null;
            }
            const friendlyName = adaptable.api.columnApi.getFriendlyNameForColumnId(columnId, layout);
            const header = layout.ColumnHeaders?.[columnId] ?? '';
            const columnWidth = layout.ColumnSizing?.[columnId]?.Width;
            const columnPinning = layout.ColumnPinning?.[columnId];
            let agg = (layout.TableAggregationColumns || []).find((agg) => agg.ColumnId === columnId)?.AggFunc;
            agg = typeof agg === 'object' ? agg.type : agg;
            const sortIndex = (layout?.ColumnSorts ?? []).findIndex((sort) => sort.ColumnId === columnId);
            const sortOrder = sortIndex != -1
                ? {
                    index: sortIndex + 1,
                    sort: layout.ColumnSorts[sortIndex]?.SortOrder ?? null,
                }
                : {};
            let grouping = layout.RowGroupedColumns?.indexOf?.(columnId);
            grouping = grouping != -1 ? grouping + 1 : null;
            const filter = layout.ColumnFilters?.find((colFilter) => colFilter.ColumnId === columnId);
            return {
                columnId,
                agg,
                friendlyName,
                header,
                columnWidth,
                columnPinning,
                sortOrder,
                grouping,
                filter,
            };
        }).filter(Boolean);
    }, [layout]);
    const columns = React.useMemo(() => {
        return {
            name: { header: 'Name', field: 'friendlyName', minWidth: 100 },
            header: { header: 'Header', field: 'header', minWidth: 120 },
            colId: { header: 'ID', field: 'columnId' },
            agg: { header: 'Agg', field: 'agg', minWidth: 70 },
            width: { header: 'Width', field: 'columnWidth', minWidth: 70 },
            pin: { header: 'Pin', field: 'columnPinning', minWidth: 80 },
            sort: {
                header: 'Sort',
                field: 'sortOrder',
                minWidth: 50,
                align: 'center',
                render: (params) => {
                    if (!params.data?.sortOrder?.sort) {
                        return React.createElement(React.Fragment, null);
                    }
                    return (React.createElement(rebass_1.Flex, null,
                        React.createElement(icons_1.Icon, { name: params.data?.sortOrder?.sort === 'Asc' ? 'arrow-up-long' : 'arrow-down-long' }),
                        ' ',
                        React.createElement(PropertyOrderText, null, params.data?.sortOrder?.index ?? '')));
                },
            },
            filter: {
                header: 'Filter',
                field: 'filter',
                align: 'center',
                minWidth: 50,
                render: (params) => {
                    if (!params.data?.filter) {
                        return React.createElement(React.Fragment, null);
                    }
                    return React.createElement(CheckBox_1.CheckBox, { checked: true });
                },
            },
            group: {
                header: 'Group',
                minWidth: 50,
                field: 'columnGroupping',
                align: 'center',
                render: (params) => {
                    if (!params.data.grouping) {
                        return React.createElement(React.Fragment, null);
                    }
                    return (React.createElement(rebass_1.Flex, null,
                        React.createElement(CheckBox_1.CheckBox, { margin: 0, mr: 1, checked: true }),
                        React.createElement(PropertyOrderText, null, params.data?.grouping)));
                },
            },
        };
    }, []);
    const tableDOMProps = {
        style: {
            height: '100%',
            minWidth: '10rem',
            minHeight: tableHeight,
        },
    };
    return (React.createElement(InfiniteTable_1.DataSource, { data: data, primaryKey: "columnId" },
        React.createElement(InfiniteTable_1.InfiniteTableGrid, { columnTypes: columnTypes, rowHeight: rowHeight, columnHeaderHeight: headerHeight, domProps: tableDOMProps, columns: columns })));
};
exports.ColumnsSectionSummary = ColumnsSectionSummary;
const ColumnRow = (props) => {
    const [isExpanded, setIsExpanded] = React.useState(false);
    const adaptable = (0, AdaptableContext_1.useAdaptable)();
    const initialHeader = adaptable.api.columnApi.getFriendlyNameForColumnId(props.column.columnId, props.layout);
    const isRowGroupColumn = adaptable.api.columnApi.isAutoRowGroupColumn(props.column.columnId);
    const customHeader = props.layout.ColumnHeaders?.[props.column.columnId] ?? initialHeader;
    // column pinning
    const columnPinning = props.layout.ColumnPinning?.[props.column.columnId] || 'None';
    const pinningOptions = [
        { value: 'None', label: 'None', onClick: () => props.onPinChange(props.column.columnId, null) },
        {
            value: 'left',
            label: 'Left',
            onClick: () => props.onPinChange(props.column.columnId, 'left'),
        },
        {
            value: 'right',
            label: 'Right',
            onClick: () => props.onPinChange(props.column.columnId, 'right'),
        },
    ];
    const { column } = props;
    // width
    const columnWidth = props.layout.ColumnSizing?.[column.columnId]?.Width;
    const columnFlex = props.layout.ColumnSizing?.[column.columnId]?.Flex;
    const minWidth = props.layout.ColumnSizing?.[column.columnId]?.MinWidth;
    const maxWidth = props.layout.ColumnSizing?.[column.columnId]?.MaxWidth;
    const resizable = column.resizable !== false;
    const visible = (!(0, isPivotLayout_1.isPivotLayout)(props.layout) &&
        props.layout.TableColumns.includes(column.columnId) &&
        props.layout.ColumnVisibility?.[column.columnId] !== false) ||
        isRowGroupColumn;
    return (React.createElement(rebass_1.Box, { "data-name": props.column.columnId, className: "ab-Layout-Wizard__ColumnRow" },
        React.createElement(rebass_1.Flex, { className: "ab-Layout-Wizard__ColumnRow__Header", mt: 1, mb: 1, onClick: () => setIsExpanded(!isExpanded) },
            React.createElement(CheckBox_1.CheckBox, { "data-name": column.columnId, onChange: (checked) => {
                    props.onColumnVisibilityChange(column.columnId, checked);
                }, disabled: column.hideable === false || isRowGroupColumn, onClick: (event) => {
                    event.stopPropagation();
                }, checked: visible }),
            React.createElement(rebass_1.Flex, { ml: 2, mr: 2, alignItems: "center", "data-name": "column-label" }, initialHeader),
            props.column.columnGroup && props.column.columnGroup.groupCount > 1 ? (React.createElement(rebass_1.Box, { className: "ab-Layout-Wizard__ColumnRow__Title", ml: 2, mr: 2, padding: 1 },
                "Column Group: ",
                props.column.columnGroup.friendlyName)) : null,
            React.createElement(rebass_1.Flex, { mr: 2 },
                React.createElement(ColumnLabels_1.ColumnLabels, { showTitle: false, sortable: props.column.sortable, filterable: props.column.filterable, pivotable: props.column.pivotable, moveable: props.column.moveable, groupable: props.column.groupable, aggregatable: props.column.aggregatable })),
            React.createElement(rebass_1.Box, { flex: 1 }),
            React.createElement(SimpleButton_1.default, { "data-name": "expand-collapse", "data-value": isExpanded ? 'expanded' : 'collapsed', ml: 10, padding: 0, iconSize: 24, variant: "text", onClick: () => setIsExpanded(!isExpanded), icon: isExpanded ? 'triangle-up' : 'triangle-down' })),
        isExpanded && (React.createElement(rebass_1.Box, { className: "ab-Layout-Wizard__ColumnRow__Expanded-Container", mb: 2, padding: 2, mt: 2 },
            React.createElement(rebass_1.Flex, { mb: 2 },
                React.createElement(FormLayout_1.default, { width: "100%", mr: 3 },
                    React.createElement(FormLayout_1.FormRow, { label: "ColumnId" },
                        React.createElement(Tag_1.Tag, null, props.column.columnId)),
                    React.createElement(FormLayout_1.FormRow, { label: "Header" },
                        React.createElement(Input_1.default, { "data-name": "column-header", className: "ab-Layout-Wizard__ColumnRow__Input", placeholder: "Custom name (optional)", onChange: () => {
                                props.onColumnNameChange(props.column.columnId, event.target.value);
                            }, value: customHeader })),
                    React.createElement(FormLayout_1.FormRow, { label: "Width" },
                        React.createElement(Input_1.default, { "data-name": "column-width", className: "ab-Layout-Wizard__ColumnRow__Input", type: "number", placeholder: "Column width", disabled: resizable === false, onChange: (event) => {
                                let value = parseFloat(event.target.value);
                                value = typeof value === 'number' && !isNaN(value) ? value : void 0;
                                props.onColumnWidthChange(props.column.columnId, value);
                            }, value: columnWidth ?? '' })),
                    React.createElement(FormLayout_1.FormRow, { label: "Flex" },
                        React.createElement(Input_1.default, { "data-name": "column-flex", className: "ab-Layout-Wizard__ColumnRow__Input", type: "number", placeholder: "Column flex", disabled: resizable === false, onChange: (event) => {
                                let value = parseFloat(event.target.value);
                                value = typeof value === 'number' && !isNaN(value) ? value : void 0;
                                props.onColumnFlexChange(props.column.columnId, value);
                            }, value: columnFlex ?? '' })),
                    React.createElement(FormLayout_1.FormRow, { label: "Min Width" },
                        React.createElement(Input_1.default, { "data-name": "column-min-width", className: "ab-Layout-Wizard__ColumnRow__Input", type: "number", placeholder: "Column min width", disabled: resizable === false, onChange: (event) => {
                                let value = parseFloat(event.target.value);
                                value = typeof value === 'number' && !isNaN(value) ? value : void 0;
                                props.onColumnMinWidthChange(props.column.columnId, value);
                            }, value: minWidth ?? '' })),
                    React.createElement(FormLayout_1.FormRow, { label: "Max Width" },
                        React.createElement(Input_1.default, { "data-name": "column-max-width", className: "ab-Layout-Wizard__ColumnRow__Input", type: "number", placeholder: "Column max width", disabled: resizable === false, onChange: (event) => {
                                let value = parseFloat(event.target.value);
                                value = typeof value === 'number' && !isNaN(value) ? value : void 0;
                                props.onColumnMaxWidthChange(props.column.columnId, value);
                            }, value: maxWidth ?? '' })),
                    React.createElement(FormLayout_1.FormRow, { label: "Pinning" },
                        React.createElement(DropdownButton_1.default, { "data-name": "column-pinning", columns: ['label'], items: pinningOptions }, pinningOptions.find((option) => option.value === columnPinning).label))))))));
};
const ColumnsSection = (props) => {
    const adaptable = (0, AdaptableContext_1.useAdaptable)();
    const { data: layout } = (0, OnePageAdaptableWizard_1.useOnePageAdaptableWizardContext)();
    const [searchInputValue, setSearchInputValue] = React.useState('');
    let hasSelectionColumn = false;
    const allColumns = adaptable.api.columnApi
        .getUIAvailableColumns()
        .filter((col) => {
        // since the "Row Groups" section of the editor can determine a change
        // which is not reflected into AG Grid until we hit finish
        // so we only rely on non-generated columns, which are the same
        return !col.isGeneratedRowGroupColumn;
    })
        // if the current Layout is a PivotLayout, then we also filter out current Pivot Result Columns
        .filter((col) => !col.isGeneratedPivotResultColumn)
        // also we need to filter out selection column
        .filter((col) => {
        const result = !col.isGeneratedSelectionColumn;
        if (!result) {
            hasSelectionColumn = true;
        }
        return result;
    });
    const onChange = (data) => {
        if (hasSelectionColumn &&
            Array.isArray(data.TableColumns) &&
            !data.TableColumns.includes(GeneralConstants_1.AG_GRID_SELECTION_COLUMN)) {
            data.TableColumns.unshift(GeneralConstants_1.AG_GRID_SELECTION_COLUMN);
        }
        props.onChange(data);
    };
    // however, changes in RowGroupedColumns done in the previous step
    // are reflected into the layout, so we use the latest layout.RowGroupedColumns
    // to create new columns
    if (layout.RowGroupedColumns) {
        if (layout.RowGroupDisplayType === 'single') {
            allColumns.unshift((0, ColumnApiImpl_1.generateAutoRowGroupSingleColumn)());
        }
        else {
            [...layout.RowGroupedColumns].reverse().forEach((col) => {
                const groupCol = (0, ColumnApiImpl_1.generateAutoRowGroupColumnForColumn)(adaptable.api.columnApi.getColumnWithColumnId(col));
                allColumns.unshift(groupCol);
            });
        }
    }
    if (adaptable.api.gridApi.isTreeDataGrid() &&
        !allColumns.find((col) => col.columnId === GeneralConstants_1.AG_GRID_GROUPED_COLUMN)) {
        allColumns.unshift((0, ColumnApiImpl_1.generateAutoTreeSingleColumn)());
    }
    const colIdToCol = allColumns.reduce((acc, col) => {
        if (col) {
            acc[col.columnId] = col;
        }
        return acc;
    }, {});
    const TableColumns = layout.TableColumns;
    const ColumnOrderAllColumns = ArrayExtensions_1.default.sortArrayWithOrder(allColumns.map((col) => col.columnId), TableColumns, { sortUnorderedItems: false }).map((colId) => colIdToCol[colId]);
    const currentOrder = searchInputValue
        ? ColumnOrderAllColumns.filter((col) => {
            return (0, Utilities_1.columnFilter)(col, searchInputValue);
        })
        : ColumnOrderAllColumns;
    const handleColumnsChange = (newColumns) => {
        if (searchInputValue) {
            // there's a search in-place
            // so the current `newColumns` does not actually contain all the columns
            // so we need to recompute it
            const newOrder = (0, sortColumnIdsByOrder_1.sortColumnIdsByOrder)(
            // given those are all the columns
            ColumnOrderAllColumns.map((col) => col.columnId), 
            // we want to sort them to have this new order
            // - this sorting will leave all ids not found in this new order untouched
            newColumns.map((col) => col.columnId));
            // so basically we now have the correct order, with all columns
            newColumns = newOrder.map((colId) => colIdToCol[colId]);
        }
        const oldColumns = ColumnOrderAllColumns;
        const columnIds = newColumns.map((col) => col.columnId);
        if (!(0, AdaptableColumn_1.isValidOrderForColumnGroups)({ oldColumns, newColumns })) {
            return;
        }
        const ColumnVisibility = { ...layout.ColumnVisibility };
        const columnOrderSet = new Set(TableColumns);
        columnIds.forEach((colId) => {
            if (!columnOrderSet.has(colId)) {
                ColumnVisibility[colId] = false;
            }
        });
        onChange({
            ...layout,
            TableColumns: columnIds,
            ColumnVisibility,
        });
    };
    const handleColumnVisibilityChange = (columnId, visible) => {
        const ColumnVisibility = { ...layout.ColumnVisibility };
        let TableColumns = [...layout.TableColumns];
        if (visible) {
            delete ColumnVisibility[columnId];
        }
        else {
            ColumnVisibility[columnId] = false;
        }
        const columnIds = ColumnOrderAllColumns.map((col) => col.columnId);
        const idsToIndexes = new Map(columnIds.map((colId, index) => [colId, index]));
        const columnOrderSet = new Set(TableColumns);
        if (!columnOrderSet.has(columnId)) {
            TableColumns = columnIds.filter((colId) => {
                const isCurrent = columnOrderSet.has(colId);
                if (isCurrent) {
                    return true;
                }
                // include all columns past the current column order
                // that reach until the index of the currently checked column
                const shouldInclude = idsToIndexes.get(colId) <= idsToIndexes.get(columnId);
                if (shouldInclude) {
                    if (colId !== columnId && visible) {
                        // this is a column that's between the current column order limit
                        // and the currently checked column
                        // so we need to include it in order
                        // but make it invisible
                        ColumnVisibility[colId] = false;
                    }
                }
                return shouldInclude;
            });
        }
        onChange({
            ...layout,
            TableColumns: TableColumns,
            ColumnVisibility,
        });
    };
    const handlePinChange = (columnId, pinning) => {
        onChange({
            ...layout,
            ColumnPinning: {
                ...layout.ColumnPinning,
                [columnId]: pinning,
            },
        });
    };
    const handleColumnNameChange = (columnId, headerName) => {
        onChange({
            ...layout,
            ColumnHeaders: {
                ...layout.ColumnHeaders,
                [columnId]: headerName,
            },
        });
    };
    const handleColumnWidthChange = (columnId, width) => {
        const ColumnSizing = { ...layout.ColumnSizing };
        const colSizingForCol = { ...ColumnSizing[columnId] };
        delete colSizingForCol.Flex;
        colSizingForCol.Width = width;
        ColumnSizing[columnId] = colSizingForCol;
        onChange({
            ...layout,
            ColumnSizing,
        });
    };
    const handleColumnFlexChange = (columnId, flex) => {
        const ColumnSizing = { ...layout.ColumnSizing };
        const colSizingForCol = { ...ColumnSizing[columnId] };
        delete colSizingForCol.Width;
        colSizingForCol.Flex = flex;
        ColumnSizing[columnId] = colSizingForCol;
        onChange({
            ...layout,
            ColumnSizing,
        });
    };
    const handleColumnMinWidthChange = (columnId, minWidth) => {
        const ColumnSizing = { ...layout.ColumnSizing };
        const colSizingForCol = { ...ColumnSizing[columnId] };
        colSizingForCol.MinWidth = minWidth;
        ColumnSizing[columnId] = colSizingForCol;
        onChange({
            ...layout,
            ColumnSizing,
        });
    };
    const handleColumnMaxWidthChange = (columnId, maxWidth) => {
        const ColumnSizing = { ...layout.ColumnSizing };
        const colSizingForCol = { ...ColumnSizing[columnId] };
        colSizingForCol.MaxWidth = maxWidth;
        ColumnSizing[columnId] = colSizingForCol;
        onChange({
            ...layout,
            ColumnSizing,
        });
    };
    const visibleIds = layout.TableColumns.filter((colId) => {
        return (layout.ColumnVisibility?.[colId] !== false &&
            adaptable.api.columnApi.isSelectionColumn(colId) === false &&
            !adaptable.api.columnApi.internalApi.isAlwaysHiddenColumn(colId));
    });
    const toLabel = (colId) => adaptable.api.columnApi.getFriendlyNameForColumnId(colId, layout);
    const toIdentifier = (colId) => colId;
    return (React.createElement(Tabs_1.Tabs, null,
        React.createElement(Tabs_1.Tabs.Tab, null, "Columns"),
        React.createElement(Tabs_1.Tabs.Content, { style: { overflow: 'hidden' } },
            React.createElement(rebass_1.Flex, { mt: 2, mb: 3 },
                React.createElement(ColumnLabels_1.ColumnLabels, { flexDirection: "row", showBoth: false, labels: {
                        Sortable: 'Sortable',
                        Filterable: 'Filterable',
                        Aggregatable: 'Aggregatable',
                        Groupable: 'Groupable',
                        Moveable: 'Moveable',
                        Pivotable: 'Pivotable',
                    }, sortable: true, filterable: true, moveable: true, pivotable: true, groupable: true, aggregatable: true })),
            React.createElement(rebass_1.Flex, { mb: 1, alignItems: "center", flexDirection: "row" },
                React.createElement(AdaptableFormControlTextClear_1.AdaptableFormControlTextClear, { value: searchInputValue, OnTextChange: setSearchInputValue, placeholder: "Type to search", style: { border: 0, margin: 3, width: '100%' } }),
                React.createElement(rebass_1.Box, { flex: 1 })),
            React.createElement(HelpBlock_1.default, { mb: 1, fontSize: 2, display: 'flex', "data-name": "column-help", alignItems: 'center' },
                React.createElement(rebass_1.Box, null,
                    React.createElement(icons_1.NaturallySizedIcon, { name: "info" })),
                React.createElement(rebass_1.Text, { ml: 1 }, "Expand each Column to set Width, Pinnning and a custom Header")),
            React.createElement(ReorderDraggable_1.ReorderDraggable, { toIdentifier: (option) => `${option.columnId}`, isOptionDraggable: (option) => {
                    return option.moveable;
                }, order: currentOrder, renderOption: (option) => {
                    return (React.createElement(ColumnRow, { onColumnNameChange: handleColumnNameChange, onColumnWidthChange: handleColumnWidthChange, onColumnFlexChange: handleColumnFlexChange, onColumnMinWidthChange: handleColumnMinWidthChange, onColumnMaxWidthChange: handleColumnMaxWidthChange, onColumnVisibilityChange: handleColumnVisibilityChange, onPinChange: handlePinChange, layout: layout, column: option }));
                }, onChange: handleColumnsChange }),
            (0, ValueSelector_1.renderSelectionSection)({
                options: visibleIds,
                value: visibleIds,
                toLabel,
                toIdentifier,
                isOptionDisabled: (colId) => adaptable.api.columnApi.isAutoRowGroupColumn(colId) ||
                    adaptable.api.columnApi.getColumnWithColumnId(colId)?.hideable === false,
                xSelectedLabel: () => {
                    return `Selected Columns:`;
                },
                noSelectionLabel: `No Columns Selected`,
                onChange: handleColumnsChange,
                onSelectAll: () => {
                    onChange({
                        ...layout,
                        ColumnVisibility: {},
                        TableColumns: ColumnOrderAllColumns.map((col) => col.columnId),
                    });
                },
                onClear: () => {
                    handleColumnsChange([]);
                },
                onClearOption: (colId) => {
                    handleColumnVisibilityChange(colId, false);
                },
            }))));
};
exports.ColumnsSection = ColumnsSection;
