/*!
 * Custom elements for Nanopore-Digital Web applications
 */
'use strict';

var index = require('./index-DGttnXif.js');
var renderer = require('./renderer-jVpDRMfV.js');

const ResizeObserve = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.nanoResizeStateChange = index.createEvent(this, "nanoResizeStateChange", 7);
        this.nanoResizeObserverReady = index.createEvent(this, "nanoResizeObserverReady", 7);
        this.nanoResizeContentFitChange = index.createEvent(this, "nanoResizeContentFitChange", 7);
        this.nanoResize = index.createEvent(this, "nanoResize", 7);
    }
    ro;
    appliedStates;
    isReady = false;
    get host() { return index.getElement(this); }
    currentWidth;
    currentHeight;
    classNames = [];
    contentFitX = null;
    contentFitY = null;
    classNameChange() {
        this.host.className = this.classNames.join(' ');
        if (!this.isReady && this.classNames.includes('is-ready')) {
            this.isReady = true;
            this.nanoResizeObserverReady.emit();
        }
    }
    /** Fire `nanoResizeContentFitChange` events notifying
     * whether content currently fits or does not on the x, y or both axis'.
     * Also makes the `content-fit-...` slots available */
    notifyContentFit;
    /** string list of sizes and optional class-names.
     * Adds class-names and fires nanoResizeStateChange events. Upon hitting breakpoints.
     * Format: `states="800w, 300h class1 class2"` */
    states;
    newStatesProp() {
        this.statesChanged();
    }
    /** A resize break point is switched on or off */
    nanoResizeStateChange;
    /** Fires after the initial loading and assessment */
    nanoResizeObserverReady;
    /** Fires when the content either begins or stops fitting.
     * Will only work when `notifyContentFit` is set. */
    nanoResizeContentFitChange;
    /** Fires after any resizing */
    nanoResize;
    dimensionChanged() {
        this.assessChanges();
    }
    statesChanged() {
        if (!this.states)
            return;
        const toBpDir = (bpDir) => {
            const bpDirSpl = bpDir.split(/(\d+)/).filter((bs) => bs.length);
            return { bp: parseInt(bpDirSpl[0]), dir: bpDirSpl[1] };
        };
        this.appliedStates = { h: new Map(), w: new Map() };
        // parse state string
        this.states.split(',').map((st) => {
            st = st.trim();
            if (st.includes(' ')) {
                const [key, ...classes] = st.split(' ');
                const { bp, dir } = toBpDir(key);
                this.appliedStates[dir].set(bp, {
                    states: classes,
                    applied: false,
                });
            }
            else {
                const { bp, dir } = toBpDir(st);
                this.appliedStates[dir].set(bp, { applied: false });
            }
        });
    }
    assesContentFit() {
        if (!this.notifyContentFit)
            return;
        const findNonContentsEle = (ele) => {
            if (window.getComputedStyle(ele).display !== 'contents')
                return ele;
            const recurse = (e) => {
                return Array.from(e.children).find((cEle) => {
                    if (window.getComputedStyle(cEle).display !== 'contents')
                        return cEle;
                    recurse(cEle);
                });
            };
            return recurse(ele);
        };
        const measureEle = findNonContentsEle(this.host.firstElementChild);
        if (!measureEle)
            return;
        let didChange = false;
        const { width, height } = this.host.getBoundingClientRect();
        if (this.notifyContentFit && this.notifyContentFit.includes('x')) {
            if (width < measureEle.scrollWidth && this.contentFitX !== false) {
                didChange = true;
                this.contentFitX = false;
            }
            else if (width >= measureEle.scrollWidth && this.contentFitX !== true) {
                didChange = true;
                this.contentFitX = true;
            }
        }
        if (this.notifyContentFit && this.notifyContentFit.includes('y')) {
            if (height < measureEle.scrollHeight && this.contentFitY !== false) {
                didChange = true;
                this.contentFitY = false;
            }
            else if (height >= measureEle.scrollHeight &&
                this.contentFitY !== true) {
                didChange = true;
                this.contentFitY = true;
            }
        }
        if (didChange) {
            this.nanoResizeContentFitChange.emit({
                x: this.contentFitX,
                y: this.contentFitY,
            });
        }
    }
    assessChanges = () => {
        if (!this.currentWidth && !this.currentHeight)
            return;
        index.readTask(() => this.assesContentFit());
        if (!this.states || !this.appliedStates)
            return;
        const changedStates = { h: new Map(), w: new Map() };
        let hasChanged = false;
        Object.keys(this.appliedStates).forEach((dimType) => {
            let dim;
            if (dimType === 'h')
                dim = this.currentHeight;
            else
                dim = this.currentWidth;
            this.appliedStates[dimType].forEach((state, bp) => {
                if (dim >= bp && state.applied === false) {
                    state.applied = true;
                    changedStates[dimType].set(bp, state);
                    hasChanged = true;
                }
                else if (dim < bp && state.applied === true) {
                    state.applied = false;
                    changedStates[dimType].set(bp, state);
                    hasChanged = true;
                }
            });
        });
        if (hasChanged)
            this.applyChanges(changedStates);
        else if (!this.classNames.includes('is-ready'))
            this.classNames = [...this.classNames, 'is-ready'];
    };
    applyChanges(changes) {
        if (!this.states)
            return;
        let classNames = [...this.classNames];
        Object.keys(changes).forEach((dimType) => {
            changes[dimType].forEach((state) => {
                if (!state.states)
                    return;
                state.states.map((st) => {
                    if (state.applied) {
                        classNames.push(st);
                        classNames = classNames.filter((cl) => cl !== 'not-' + st);
                    }
                    else {
                        classNames.push('not-' + st);
                        classNames = classNames.filter((cl) => cl !== st);
                    }
                });
            });
        });
        this.classNames = [...new Set(['is-ready', ...classNames])];
        this.nanoResizeStateChange.emit(this.toSimpleObj(changes));
    }
    toSimpleObj(stateMaps) {
        const retObj = {};
        Object.keys(stateMaps).forEach((dimType) => {
            stateMaps[dimType].forEach((state, bp) => {
                retObj[bp + dimType] = state.applied;
            });
        });
        return retObj;
    }
    attachRO() {
        if (!window['ResizeObserver'])
            return;
        this.ro = new ResizeObserver((ro) => {
            const { width, height } = this.host.getBoundingClientRect();
            this.currentWidth = Math.ceil(width);
            this.currentHeight = Math.ceil(height);
            this.nanoResize.emit(ro);
        });
        this.ro.observe(this.host);
    }
    componentWillLoad() {
        this.classNames = Array.from(this.host.classList);
        this.statesChanged();
        // set all class as 'not-' by deafult
        this.applyChanges(this.appliedStates);
        if (!this.currentWidth && !this.currentHeight) {
            index.readTask(() => {
                const { width, height } = this.host.getBoundingClientRect();
                this.currentWidth = Math.ceil(width);
                this.currentHeight = Math.ceil(height);
            });
        }
        else {
            this.assessChanges();
        }
    }
    connectedCallback() {
        if (!this.ro)
            this.attachRO();
    }
    disconnectedCallback() {
        if (this.ro) {
            this.ro.disconnect();
            this.ro = undefined;
        }
    }
    render() {
        return (renderer.h(index.Host, { key: 'a2c57218f65a9af2297e6662c29d3a7c853092df', class: {
                'nano-resize-observe': true,
                'content-fit-x': this.contentFitX,
                'content-fit-y': this.contentFitY,
                'content-nofit-x': this.contentFitX === false,
                'content-nofit-y': this.contentFitY === false,
            } }, renderer.h("slot", { key: 'cf0faa31f7c1daa08238555a46699c1b731e13b8' }), !!this.notifyContentFit &&
            (this.contentFitX !== null || this.contentFitY !== null) && [
            this.contentFitX ? (renderer.h("slot", { name: "content-fit-x" })) : (renderer.h("slot", { name: "content-nofit-x" })),
            this.contentFitY ? (renderer.h("slot", { name: "content-fit-y" })) : (renderer.h("slot", { name: "content-nofit-y" })),
        ]));
    }
    static get watchers() { return {
        "classNames": ["classNameChange"],
        "states": ["newStatesProp", "statesChanged"],
        "currentHeight": ["dimensionChanged"],
        "currentWidth": ["dimensionChanged"]
    }; }
};
ResizeObserve.style = ":host { display: block }";

exports.nano_resize_observe = ResizeObserve;
