import { refineProps, guid, parseBusinessHours, createEventUi, identity, parseClassNames, EventImpl, Splitter, parseFieldSpecs, BaseComponent, memoizeObjArg, ViewContextType, ContentContainer, formatDayString, memoize, NowTimer, TableDateCell, TableDowCell, computeFallbackHeaderFormat, mapHash, flexibleCompare, compareByFieldSpecs } from '@fullcalendar/core/internal.js';
import { createElement, Fragment } from '@fullcalendar/core/preact.js';

const PRIVATE_ID_PREFIX = '_fc:';
const RESOURCE_REFINERS = {
    id: String,
    parentId: String,
    children: identity,
    title: String,
    businessHours: identity,
    extendedProps: identity,
    // event-ui
    eventEditable: Boolean,
    eventStartEditable: Boolean,
    eventDurationEditable: Boolean,
    eventConstraint: identity,
    eventOverlap: Boolean,
    eventAllow: identity,
    eventClassNames: parseClassNames,
    eventBackgroundColor: String,
    eventBorderColor: String,
    eventTextColor: String,
    eventColor: String,
};
/*
needs a full store so that it can populate children too
*/
function parseResource(raw, parentId = '', store, context) {
    let { refined, extra } = refineProps(raw, RESOURCE_REFINERS);
    let resource = {
        id: refined.id || (PRIVATE_ID_PREFIX + guid()),
        parentId: refined.parentId || parentId,
        title: refined.title || '',
        businessHours: refined.businessHours ? parseBusinessHours(refined.businessHours, context) : null,
        ui: createEventUi({
            editable: refined.eventEditable,
            startEditable: refined.eventStartEditable,
            durationEditable: refined.eventDurationEditable,
            constraint: refined.eventConstraint,
            overlap: refined.eventOverlap,
            allow: refined.eventAllow,
            classNames: refined.eventClassNames,
            backgroundColor: refined.eventBackgroundColor,
            borderColor: refined.eventBorderColor,
            textColor: refined.eventTextColor,
            color: refined.eventColor,
        }, context),
        extendedProps: Object.assign(Object.assign({}, extra), refined.extendedProps),
    };
    // help out ResourceApi from having user modify props
    Object.freeze(resource.ui.classNames);
    Object.freeze(resource.extendedProps);
    if (store[resource.id]) ;
    else {
        store[resource.id] = resource;
        if (refined.children) {
            for (let childInput of refined.children) {
                parseResource(childInput, resource.id, store, context);
            }
        }
    }
    return resource;
}
/*
TODO: use this in more places
*/
function getPublicId(id) {
    if (id.indexOf(PRIVATE_ID_PREFIX) === 0) {
        return '';
    }
    return id;
}

class ResourceApi {
    constructor(_context, _resource) {
        this._context = _context;
        this._resource = _resource;
    }
    setProp(name, value) {
        let oldResource = this._resource;
        this._context.dispatch({
            type: 'SET_RESOURCE_PROP',
            resourceId: oldResource.id,
            propName: name,
            propValue: value,
        });
        this.sync(oldResource);
    }
    setExtendedProp(name, value) {
        let oldResource = this._resource;
        this._context.dispatch({
            type: 'SET_RESOURCE_EXTENDED_PROP',
            resourceId: oldResource.id,
            propName: name,
            propValue: value,
        });
        this.sync(oldResource);
    }
    sync(oldResource) {
        let context = this._context;
        let resourceId = oldResource.id;
        // TODO: what if dispatch didn't complete synchronously?
        this._resource = context.getCurrentData().resourceStore[resourceId];
        context.emitter.trigger('resourceChange', {
            oldResource: new ResourceApi(context, oldResource),
            resource: this,
            revert() {
                context.dispatch({
                    type: 'ADD_RESOURCE',
                    resourceHash: {
                        [resourceId]: oldResource,
                    },
                });
            },
        });
    }
    remove() {
        let context = this._context;
        let internalResource = this._resource;
        let resourceId = internalResource.id;
        context.dispatch({
            type: 'REMOVE_RESOURCE',
            resourceId,
        });
        context.emitter.trigger('resourceRemove', {
            resource: this,
            revert() {
                context.dispatch({
                    type: 'ADD_RESOURCE',
                    resourceHash: {
                        [resourceId]: internalResource,
                    },
                });
            },
        });
    }
    getParent() {
        let context = this._context;
        let parentId = this._resource.parentId;
        if (parentId) {
            return new ResourceApi(context, context.getCurrentData().resourceStore[parentId]);
        }
        return null;
    }
    getChildren() {
        let thisResourceId = this._resource.id;
        let context = this._context;
        let { resourceStore } = context.getCurrentData();
        let childApis = [];
        for (let resourceId in resourceStore) {
            if (resourceStore[resourceId].parentId === thisResourceId) {
                childApis.push(new ResourceApi(context, resourceStore[resourceId]));
            }
        }
        return childApis;
    }
    /*
    this is really inefficient!
    TODO: make EventApi::resourceIds a hash or keep an index in the Calendar's state
    */
    getEvents() {
        let thisResourceId = this._resource.id;
        let context = this._context;
        let { defs, instances } = context.getCurrentData().eventStore;
        let eventApis = [];
        for (let instanceId in instances) {
            let instance = instances[instanceId];
            let def = defs[instance.defId];
            if (def.resourceIds.indexOf(thisResourceId) !== -1) { // inefficient!!!
                eventApis.push(new EventImpl(context, def, instance));
            }
        }
        return eventApis;
    }
    get id() { return getPublicId(this._resource.id); }
    get title() { return this._resource.title; }
    get eventConstraint() { return this._resource.ui.constraints[0] || null; } // TODO: better type
    get eventOverlap() { return this._resource.ui.overlap; }
    get eventAllow() { return this._resource.ui.allows[0] || null; } // TODO: better type
    get eventBackgroundColor() { return this._resource.ui.backgroundColor; }
    get eventBorderColor() { return this._resource.ui.borderColor; }
    get eventTextColor() { return this._resource.ui.textColor; }
    // NOTE: user can't modify these because Object.freeze was called in event-def parsing
    get eventClassNames() { return this._resource.ui.classNames; }
    get extendedProps() { return this._resource.extendedProps; }
    toPlainObject(settings = {}) {
        let internal = this._resource;
        let { ui } = internal;
        let publicId = this.id;
        let res = {};
        if (publicId) {
            res.id = publicId;
        }
        if (internal.title) {
            res.title = internal.title;
        }
        if (settings.collapseEventColor && ui.backgroundColor && ui.backgroundColor === ui.borderColor) {
            res.eventColor = ui.backgroundColor;
        }
        else {
            if (ui.backgroundColor) {
                res.eventBackgroundColor = ui.backgroundColor;
            }
            if (ui.borderColor) {
                res.eventBorderColor = ui.borderColor;
            }
        }
        if (ui.textColor) {
            res.eventTextColor = ui.textColor;
        }
        if (ui.classNames.length) {
            res.eventClassNames = ui.classNames;
        }
        if (Object.keys(internal.extendedProps).length) {
            if (settings.collapseExtendedProps) {
                Object.assign(res, internal.extendedProps);
            }
            else {
                res.extendedProps = internal.extendedProps;
            }
        }
        return res;
    }
    toJSON() {
        return this.toPlainObject();
    }
}
function buildResourceApis(resourceStore, context) {
    let resourceApis = [];
    for (let resourceId in resourceStore) {
        resourceApis.push(new ResourceApi(context, resourceStore[resourceId]));
    }
    return resourceApis;
}

/*
splits things BASED OFF OF which resources they are associated with.
creates a '' entry which is when something has NO resource.
*/
class ResourceSplitter extends Splitter {
    getKeyInfo(props) {
        return Object.assign({ '': {} }, props.resourceStore);
    }
    getKeysForDateSpan(dateSpan) {
        return [dateSpan.resourceId || ''];
    }
    getKeysForEventDef(eventDef) {
        let resourceIds = eventDef.resourceIds;
        if (!resourceIds.length) {
            return [''];
        }
        return resourceIds;
    }
}

const DEFAULT_RESOURCE_ORDER = parseFieldSpecs('id,title');
function handleResourceStore(resourceStore, calendarData) {
    let { emitter } = calendarData;
    if (emitter.hasHandlers('resourcesSet')) {
        emitter.trigger('resourcesSet', buildResourceApis(resourceStore, calendarData));
    }
}

function refineRenderProps$1(input) {
    return {
        resource: new ResourceApi(input.context, input.resource),
    };
}

// TODO: not used for Spreadsheet. START USING. difficult because of col-specific rendering props
class ResourceLabelContainer extends BaseComponent {
    constructor() {
        super(...arguments);
        this.refineRenderProps = memoizeObjArg(refineRenderProps);
    }
    render() {
        const { props } = this;
        return (createElement(ViewContextType.Consumer, null, (context) => {
            let { options } = context;
            let renderProps = this.refineRenderProps({
                resource: props.resource,
                date: props.date,
                context,
            });
            return (createElement(ContentContainer, { elRef: props.elRef, elTag: props.elTag, elAttrs: Object.assign(Object.assign({}, props.elAttrs), { 'data-resource-id': props.resource.id, 'data-date': props.date ? formatDayString(props.date) : undefined }), elClasses: props.elClasses, elStyle: props.elStyle, renderProps: renderProps, generatorName: "resourceLabelContent", customGenerator: options.resourceLabelContent, defaultGenerator: renderInnerContent, classNameGenerator: options.resourceLabelClassNames, didMount: options.resourceLabelDidMount, willUnmount: options.resourceLabelWillUnmount }, props.children));
        }));
    }
}
function renderInnerContent(props) {
    return props.resource.title || props.resource.id;
}
function refineRenderProps(input) {
    return {
        resource: new ResourceApi(input.context, input.resource),
        date: input.date ? input.context.dateEnv.toDate(input.date) : null,
        view: input.context.viewApi,
    };
}

class ResourceCell extends BaseComponent {
    render() {
        let { props } = this;
        return (createElement(ResourceLabelContainer, { elTag: "th", elClasses: ['fc-col-header-cell', 'fc-resource'], elAttrs: {
                role: 'columnheader',
                colSpan: props.colSpan,
            }, resource: props.resource, date: props.date }, (InnerContent) => (createElement("div", { className: "fc-scrollgrid-sync-inner" },
            createElement(InnerContent, { elTag: "span", elClasses: [
                    'fc-col-header-cell-cushion',
                    props.isSticky && 'fc-sticky',
                ] })))));
    }
}

class ResourceDayHeader extends BaseComponent {
    constructor() {
        super(...arguments);
        this.buildDateFormat = memoize(buildDateFormat);
    }
    render() {
        let { props, context } = this;
        let dateFormat = this.buildDateFormat(context.options.dayHeaderFormat, props.datesRepDistinctDays, props.dates.length);
        return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => {
            if (props.dates.length === 1) {
                return this.renderResourceRow(props.resources, props.dates[0]);
            }
            if (context.options.datesAboveResources) {
                return this.renderDayAndResourceRows(props.dates, dateFormat, todayRange, props.resources);
            }
            return this.renderResourceAndDayRows(props.resources, props.dates, dateFormat, todayRange);
        }));
    }
    renderResourceRow(resources, date) {
        let resourceCells = resources.map((resource) => (createElement(ResourceCell, { key: resource.id, resource: resource, colSpan: 1, date: date })));
        return this.buildTr(resourceCells, 'resources');
    }
    renderDayAndResourceRows(dates, dateFormat, todayRange, resources) {
        let dateCells = [];
        let resourceCells = [];
        for (let date of dates) {
            dateCells.push(this.renderDateCell(date, dateFormat, todayRange, resources.length, null, true));
            for (let resource of resources) {
                resourceCells.push(createElement(ResourceCell, { key: resource.id + ':' + date.toISOString(), resource: resource, colSpan: 1, date: date }));
            }
        }
        return (createElement(Fragment, null,
            this.buildTr(dateCells, 'day'),
            this.buildTr(resourceCells, 'resources')));
    }
    renderResourceAndDayRows(resources, dates, dateFormat, todayRange) {
        let resourceCells = [];
        let dateCells = [];
        for (let resource of resources) {
            resourceCells.push(createElement(ResourceCell, { key: resource.id, resource: resource, colSpan: dates.length, isSticky: true }));
            for (let date of dates) {
                dateCells.push(this.renderDateCell(date, dateFormat, todayRange, 1, resource));
            }
        }
        return (createElement(Fragment, null,
            this.buildTr(resourceCells, 'resources'),
            this.buildTr(dateCells, 'day')));
    }
    // a cell with date text. might have a resource associated with it
    renderDateCell(date, dateFormat, todayRange, colSpan, resource, isSticky) {
        let { props } = this;
        let keyPostfix = resource ? `:${resource.id}` : '';
        let extraRenderProps = resource ? { resource: new ResourceApi(this.context, resource) } : {};
        let extraDataAttrs = resource ? { 'data-resource-id': resource.id } : {};
        return props.datesRepDistinctDays ? (createElement(TableDateCell, { key: date.toISOString() + keyPostfix, date: date, dateProfile: props.dateProfile, todayRange: todayRange, colCnt: props.dates.length * props.resources.length, dayHeaderFormat: dateFormat, colSpan: colSpan, isSticky: isSticky, extraRenderProps: extraRenderProps, extraDataAttrs: extraDataAttrs })) : (createElement(TableDowCell // we can't leverage the pure-componentness becausae the extra* props are new every time :(
        , { key: date.getUTCDay() + keyPostfix, dow: date.getUTCDay(), dayHeaderFormat: dateFormat, colSpan: colSpan, isSticky: isSticky, extraRenderProps: extraRenderProps, extraDataAttrs: extraDataAttrs }));
    }
    buildTr(cells, key) {
        let { renderIntro } = this.props;
        if (!cells.length) {
            cells = [createElement("td", { key: 0 }, "\u00A0")];
        }
        return (createElement("tr", { key: key, role: "row" },
            renderIntro && renderIntro(key),
            cells));
    }
}
function buildDateFormat(dayHeaderFormat, datesRepDistinctDays, dayCnt) {
    return dayHeaderFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt);
}

class ResourceIndex {
    constructor(resources) {
        let indicesById = {};
        let ids = [];
        for (let i = 0; i < resources.length; i += 1) {
            let id = resources[i].id;
            ids.push(id);
            indicesById[id] = i;
        }
        this.ids = ids;
        this.indicesById = indicesById;
        this.length = resources.length;
    }
}

class AbstractResourceDayTableModel {
    constructor(dayTableModel, resources, context) {
        this.dayTableModel = dayTableModel;
        this.resources = resources;
        this.context = context;
        this.resourceIndex = new ResourceIndex(resources);
        this.rowCnt = dayTableModel.rowCnt;
        this.colCnt = dayTableModel.colCnt * resources.length;
        this.cells = this.buildCells();
    }
    buildCells() {
        let { rowCnt, dayTableModel, resources } = this;
        let rows = [];
        for (let row = 0; row < rowCnt; row += 1) {
            let rowCells = [];
            for (let dateCol = 0; dateCol < dayTableModel.colCnt; dateCol += 1) {
                for (let resourceCol = 0; resourceCol < resources.length; resourceCol += 1) {
                    let resource = resources[resourceCol];
                    let extraRenderProps = { resource: new ResourceApi(this.context, resource) };
                    let extraDataAttrs = { 'data-resource-id': resource.id };
                    let extraClassNames = ['fc-resource'];
                    let extraDateSpan = { resourceId: resource.id };
                    let date = dayTableModel.cells[row][dateCol].date;
                    rowCells[this.computeCol(dateCol, resourceCol)] = {
                        key: resource.id + ':' + date.toISOString(),
                        date,
                        extraRenderProps,
                        extraDataAttrs,
                        extraClassNames,
                        extraDateSpan,
                    };
                }
            }
            rows.push(rowCells);
        }
        return rows;
    }
}

/*
resources over dates
*/
class ResourceDayTableModel extends AbstractResourceDayTableModel {
    computeCol(dateI, resourceI) {
        return resourceI * this.dayTableModel.colCnt + dateI;
    }
    /*
    all date ranges are intact
    */
    computeColRanges(dateStartI, dateEndI, resourceI) {
        return [
            {
                firstCol: this.computeCol(dateStartI, resourceI),
                lastCol: this.computeCol(dateEndI, resourceI),
                isStart: true,
                isEnd: true,
            },
        ];
    }
}

/*
dates over resources
*/
class DayResourceTableModel extends AbstractResourceDayTableModel {
    computeCol(dateI, resourceI) {
        return dateI * this.resources.length + resourceI;
    }
    /*
    every single day is broken up
    */
    computeColRanges(dateStartI, dateEndI, resourceI) {
        let segs = [];
        for (let i = dateStartI; i <= dateEndI; i += 1) {
            let col = this.computeCol(i, resourceI);
            segs.push({
                firstCol: col,
                lastCol: col,
                isStart: i === dateStartI,
                isEnd: i === dateEndI,
            });
        }
        return segs;
    }
}

const NO_SEGS = []; // for memoizing
class VResourceJoiner {
    constructor() {
        this.joinDateSelection = memoize(this.joinSegs);
        this.joinBusinessHours = memoize(this.joinSegs);
        this.joinFgEvents = memoize(this.joinSegs);
        this.joinBgEvents = memoize(this.joinSegs);
        this.joinEventDrags = memoize(this.joinInteractions);
        this.joinEventResizes = memoize(this.joinInteractions);
    }
    /*
    propSets also has a '' key for things with no resource
    */
    joinProps(propSets, resourceDayTable) {
        let dateSelectionSets = [];
        let businessHoursSets = [];
        let fgEventSets = [];
        let bgEventSets = [];
        let eventDrags = [];
        let eventResizes = [];
        let eventSelection = '';
        let keys = resourceDayTable.resourceIndex.ids.concat(['']); // add in the all-resource key
        for (let key of keys) {
            let props = propSets[key];
            dateSelectionSets.push(props.dateSelectionSegs);
            businessHoursSets.push(key ? props.businessHourSegs : NO_SEGS); // don't include redundant all-resource businesshours
            fgEventSets.push(key ? props.fgEventSegs : NO_SEGS); // don't include fg all-resource segs
            bgEventSets.push(props.bgEventSegs);
            eventDrags.push(props.eventDrag);
            eventResizes.push(props.eventResize);
            eventSelection = eventSelection || props.eventSelection;
        }
        return {
            dateSelectionSegs: this.joinDateSelection(resourceDayTable, ...dateSelectionSets),
            businessHourSegs: this.joinBusinessHours(resourceDayTable, ...businessHoursSets),
            fgEventSegs: this.joinFgEvents(resourceDayTable, ...fgEventSets),
            bgEventSegs: this.joinBgEvents(resourceDayTable, ...bgEventSets),
            eventDrag: this.joinEventDrags(resourceDayTable, ...eventDrags),
            eventResize: this.joinEventResizes(resourceDayTable, ...eventResizes),
            eventSelection,
        };
    }
    joinSegs(resourceDayTable, ...segGroups) {
        let resourceCnt = resourceDayTable.resources.length;
        let transformedSegs = [];
        for (let i = 0; i < resourceCnt; i += 1) {
            for (let seg of segGroups[i]) {
                transformedSegs.push(...this.transformSeg(seg, resourceDayTable, i));
            }
            for (let seg of segGroups[resourceCnt]) { // one beyond. the all-resource
                transformedSegs.push(...this.transformSeg(seg, resourceDayTable, i));
            }
        }
        return transformedSegs;
    }
    /*
    for expanding non-resource segs to all resources.
    only for public use.
    no memoizing.
    */
    expandSegs(resourceDayTable, segs) {
        let resourceCnt = resourceDayTable.resources.length;
        let transformedSegs = [];
        for (let i = 0; i < resourceCnt; i += 1) {
            for (let seg of segs) {
                transformedSegs.push(...this.transformSeg(seg, resourceDayTable, i));
            }
        }
        return transformedSegs;
    }
    joinInteractions(resourceDayTable, ...interactions) {
        let resourceCnt = resourceDayTable.resources.length;
        let affectedInstances = {};
        let transformedSegs = [];
        let anyInteractions = false;
        let isEvent = false;
        for (let i = 0; i < resourceCnt; i += 1) {
            let interaction = interactions[i];
            if (interaction) {
                anyInteractions = true;
                for (let seg of interaction.segs) {
                    transformedSegs.push(...this.transformSeg(seg, resourceDayTable, i));
                }
                Object.assign(affectedInstances, interaction.affectedInstances);
                isEvent = isEvent || interaction.isEvent;
            }
            if (interactions[resourceCnt]) { // one beyond. the all-resource
                for (let seg of interactions[resourceCnt].segs) {
                    transformedSegs.push(...this.transformSeg(seg, resourceDayTable, i));
                }
            }
        }
        if (anyInteractions) {
            return {
                affectedInstances,
                segs: transformedSegs,
                isEvent,
            };
        }
        return null;
    }
}

/*
TODO: just use ResourceHash somehow? could then use the generic ResourceSplitter
*/
class VResourceSplitter extends Splitter {
    getKeyInfo(props) {
        let { resourceDayTableModel } = props;
        let hash = mapHash(resourceDayTableModel.resourceIndex.indicesById, (i) => resourceDayTableModel.resources[i]); // :(
        hash[''] = {};
        return hash;
    }
    getKeysForDateSpan(dateSpan) {
        return [dateSpan.resourceId || ''];
    }
    getKeysForEventDef(eventDef) {
        let resourceIds = eventDef.resourceIds;
        if (!resourceIds.length) {
            return [''];
        }
        return resourceIds;
    }
}

/*
doesn't accept grouping
*/
function flattenResources(resourceStore, orderSpecs) {
    return buildRowNodes(resourceStore, [], orderSpecs, false, {}, true)
        .map((node) => node.resource);
}
function buildRowNodes(resourceStore, groupSpecs, orderSpecs, isVGrouping, expansions, expansionDefault) {
    let complexNodes = buildHierarchy(resourceStore, isVGrouping ? -1 : 1, groupSpecs, orderSpecs);
    let flatNodes = [];
    flattenNodes(complexNodes, flatNodes, isVGrouping, [], 0, expansions, expansionDefault);
    return flatNodes;
}
function flattenNodes(complexNodes, res, isVGrouping, rowSpans, depth, expansions, expansionDefault) {
    for (let i = 0; i < complexNodes.length; i += 1) {
        let complexNode = complexNodes[i];
        let group = complexNode.group;
        if (group) {
            if (isVGrouping) {
                let firstRowIndex = res.length;
                let rowSpanIndex = rowSpans.length;
                flattenNodes(complexNode.children, res, isVGrouping, rowSpans.concat(0), depth, expansions, expansionDefault);
                if (firstRowIndex < res.length) {
                    let firstRow = res[firstRowIndex];
                    let firstRowSpans = firstRow.rowSpans = firstRow.rowSpans.slice();
                    firstRowSpans[rowSpanIndex] = res.length - firstRowIndex;
                }
            }
            else {
                let id = group.spec.field + ':' + group.value;
                let isExpanded = expansions[id] != null ? expansions[id] : expansionDefault;
                res.push({ id, group, isExpanded });
                if (isExpanded) {
                    flattenNodes(complexNode.children, res, isVGrouping, rowSpans, depth + 1, expansions, expansionDefault);
                }
            }
        }
        else if (complexNode.resource) {
            let id = complexNode.resource.id;
            let isExpanded = expansions[id] != null ? expansions[id] : expansionDefault;
            res.push({
                id,
                rowSpans,
                depth,
                isExpanded,
                hasChildren: Boolean(complexNode.children.length),
                resource: complexNode.resource,
                resourceFields: complexNode.resourceFields,
            });
            if (isExpanded) {
                flattenNodes(complexNode.children, res, isVGrouping, rowSpans, depth + 1, expansions, expansionDefault);
            }
        }
    }
}
function buildHierarchy(resourceStore, maxDepth, groupSpecs, orderSpecs) {
    let resourceNodes = buildResourceNodes(resourceStore, orderSpecs);
    let builtNodes = [];
    for (let resourceId in resourceNodes) {
        let resourceNode = resourceNodes[resourceId];
        if (!resourceNode.resource.parentId) {
            insertResourceNode(resourceNode, builtNodes, groupSpecs, 0, maxDepth, orderSpecs);
        }
    }
    return builtNodes;
}
function buildResourceNodes(resourceStore, orderSpecs) {
    let nodeHash = {};
    for (let resourceId in resourceStore) {
        let resource = resourceStore[resourceId];
        nodeHash[resourceId] = {
            resource,
            resourceFields: buildResourceFields(resource),
            children: [],
        };
    }
    for (let resourceId in resourceStore) {
        let resource = resourceStore[resourceId];
        if (resource.parentId) {
            let parentNode = nodeHash[resource.parentId];
            if (parentNode) {
                insertResourceNodeInSiblings(nodeHash[resourceId], parentNode.children, orderSpecs);
            }
        }
    }
    return nodeHash;
}
function insertResourceNode(resourceNode, nodes, groupSpecs, depth, maxDepth, orderSpecs) {
    if (groupSpecs.length && (maxDepth === -1 || depth <= maxDepth)) {
        let groupNode = ensureGroupNodes(resourceNode, nodes, groupSpecs[0]);
        insertResourceNode(resourceNode, groupNode.children, groupSpecs.slice(1), depth + 1, maxDepth, orderSpecs);
    }
    else {
        insertResourceNodeInSiblings(resourceNode, nodes, orderSpecs);
    }
}
function ensureGroupNodes(resourceNode, nodes, groupSpec) {
    let groupValue = resourceNode.resourceFields[groupSpec.field];
    let groupNode;
    let newGroupIndex;
    // find an existing group that matches, or determine the position for a new group
    if (groupSpec.order) {
        for (newGroupIndex = 0; newGroupIndex < nodes.length; newGroupIndex += 1) {
            let node = nodes[newGroupIndex];
            if (node.group) {
                let cmp = flexibleCompare(groupValue, node.group.value) * groupSpec.order;
                if (cmp === 0) {
                    groupNode = node;
                    break;
                }
                else if (cmp < 0) {
                    break;
                }
            }
        }
    }
    else { // the groups are unordered
        for (newGroupIndex = 0; newGroupIndex < nodes.length; newGroupIndex += 1) {
            let node = nodes[newGroupIndex];
            if (node.group && groupValue === node.group.value) {
                groupNode = node;
                break;
            }
        }
    }
    if (!groupNode) {
        groupNode = {
            group: {
                value: groupValue,
                spec: groupSpec,
            },
            children: [],
        };
        nodes.splice(newGroupIndex, 0, groupNode);
    }
    return groupNode;
}
function insertResourceNodeInSiblings(resourceNode, siblings, orderSpecs) {
    let i;
    for (i = 0; i < siblings.length; i += 1) {
        let cmp = compareByFieldSpecs(siblings[i].resourceFields, resourceNode.resourceFields, orderSpecs); // TODO: pass in ResourceApi?
        if (cmp > 0) { // went 1 past. insert at i
            break;
        }
    }
    siblings.splice(i, 0, resourceNode);
}
function buildResourceFields(resource) {
    let obj = Object.assign(Object.assign(Object.assign({}, resource.extendedProps), resource.ui), resource);
    delete obj.ui;
    delete obj.extendedProps;
    return obj;
}
function isGroupsEqual(group0, group1) {
    return group0.spec === group1.spec && group0.value === group1.value;
}

export { AbstractResourceDayTableModel as A, DEFAULT_RESOURCE_ORDER as D, ResourceApi as R, VResourceJoiner as V, ResourceSplitter as a, ResourceDayHeader as b, ResourceDayTableModel as c, DayResourceTableModel as d, VResourceSplitter as e, flattenResources as f, getPublicId as g, handleResourceStore as h, isGroupsEqual as i, buildRowNodes as j, buildResourceFields as k, ResourceLabelContainer as l, parseResource as p, refineRenderProps$1 as r };
