/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { getRenderingRef, getElement, h, Fragment } from "@stencil/core";
import { getStore } from "./table.store";
import { CSSNAMESPACE } from "./table.constants";
import { getNestedProperty } from "./table.property-utils";
// Re-export for convenience
export { getNestedProperty };
/**
 * Get a model object for custom cell / property renderers.
 * @param rowIndex - the current row index being rendered
 * @param colIndex - the current column index being rendered
 * @returns a model object which will be passed to custom renderers
 */
export function colDataModel(rowIndex, colIndex) {
    const store = fetchStores();
    const columns = store.config.state.columns;
    const rows = store.data.state.rows;
    const column = columns[colIndex];
    const prop = column?.prop;
    const rowModel = rows[rowIndex];
    const cellModel = rowModel
        ? getNestedProperty(rowModel, columns[colIndex].prop)
        : '';
    return {
        prop,
        cellModel,
        column,
        rowIndex,
        rowModel,
    };
}
/**
 * Get a model object for custom row renderers.
 * @param rowIndex
 * @returns a model object passed to custom row renderers
 */
export function rowDataModel(rowIndex) {
    const store = fetchStores();
    const rows = store.data.state.rows;
    const rowModel = rows[rowIndex];
    return {
        rowModel,
        rowIndex,
    };
}
/**
 * Merges 2 objects of properties together
 * @param current - property object
 * @param extra - additional object property
 * @returns - merged properties that can be applied to a node
 */
export function mergeProperties(current, extra) {
    if (!extra)
        return current;
    // top level merge
    const props = { ...extra, ...current };
    // deeper merge
    // merge classes maps or strings
    if (extra.class) {
        if (typeof extra.class === 'object' && typeof props.class === 'object') {
            props.class = { ...extra.class, ...props.class };
        }
        else if (typeof extra.class === 'string' &&
            typeof props.class === 'object') {
            props.class[extra.class] = true;
        }
        else if (typeof props.class === 'string' &&
            typeof extra.class === 'string') {
            props.class += ' ' + extra.class;
        }
    }
    // merge style
    if (extra.style) {
        props.style = { ...extra.style, ...props.style };
    }
    return props;
}
/**
 * Returns the current nano-data-table's stores.
 * @returns the current nano-data-table stores
 */
export function fetchStores() {
    return getStore(getElement(getRenderingRef()));
}
/**
 * Merges any defined cell properties with properties
 * required by `nano-data-table` functionality
 * @param rowIndex - the current row index being rendered
 * @param colIndex = the current column index being rendered
 * @param defaultProps - default properties required by `nano-data-table`
 * @returns - the merged properties that will be applied to a node
 */
export function mergeCellProperties(rowIndex, colIndex, defaultProps) {
    const props = { ...defaultProps };
    const extraPropsFunc = fetchStores().config.state.columns[colIndex]?.cellProperties;
    if (!extraPropsFunc)
        return props;
    const data = colDataModel(rowIndex, colIndex);
    const extra = extraPropsFunc(data);
    if (!extra)
        return props;
    return mergeProperties(props, extra);
}
/**
 * Renders a table header (within a thead) using a custom template if set.
 * @param col - the current column config object
 * @returns - a JSX node
 */
export function colheadFootRender(col) {
    const tpl = col?.columnTemplate;
    return tpl ? tpl(h, col) : (h(Fragment, null, col.title));
}
export function headerPinClasses(type, vPinned, toString = false) {
    const classes = {
        [`${CSSNAMESPACE}__${type}`]: true,
        [`${CSSNAMESPACE}__pin`]: !!vPinned,
        [`${CSSNAMESPACE}__pin--top`]: vPinned === 'top',
        [`${CSSNAMESPACE}__pin--bottom`]: vPinned === 'bottom',
    };
    if (toString)
        return classListToStr(classes);
    return classes;
}
/**
 * Turns a class map {'string': boolean} to class string
 * @param classes - the class map to convert
 * @returns a class string
 */
export function classListToStr(classes) {
    let classString = '';
    Object.entries(classes).forEach(([className, on]) => {
        if (on)
            classString += className + ' ';
    });
    return classString;
}
