import { hasOwnProperty as hasOwnProperty$1, isObject as isObject$1, merge } from 'smob';
import { hasInjectionContext, inject, unref, isRef, isReadonly, mergeProps } from 'vue';

var StoreName;
(function(StoreName) {
    StoreName["DEFAULT"] = "default";
})(StoreName || (StoreName = {}));

class Store {
    /**
     * Set options for all groups.
     *
     * @param items
     */ setAll(items) {
        const keys = Object.keys(items);
        for(let i = 0; i < keys.length; i++){
            this.setOptions(keys[i], items[keys[i]]);
        }
    }
    /**
     * Set options for a specific group.
     *
     * @param group
     * @param options
     */ setOptions(group, options) {
        if (typeof this.data[group] === 'undefined') {
            this.data[group] = {};
        }
        this.data[group] = options;
    }
    hasOptions(group) {
        return hasOwnProperty$1(this.data, group);
    }
    getOptions(group) {
        if (typeof this.data[group] !== 'undefined') {
            return this.data[group];
        }
        return {};
    }
    hasOption(group, option) {
        return typeof this.data[group] !== 'undefined' && hasOwnProperty$1(this.data[group], option);
    }
    getOption(group, option) {
        if (typeof this.data[group] === 'undefined') {
            return undefined;
        }
        return this.data[group][option];
    }
    constructor(){
        this.data = {};
    }
}

class StoreManager {
    keys() {
        return Object.keys(this.instances);
    }
    use(key) {
        if (typeof this.instances[key] !== 'undefined') {
            return this.instances[key];
        }
        this.instances[key] = new Store();
        return this.instances[key];
    }
    constructor(){
        this.instances = {};
    }
}

function applyStoreManagerOptions(manager, options) {
    if (options.presets) {
        const presetKeys = Object.keys(options.presets);
        for(let i = 0; i < presetKeys.length; i++){
            const store = manager.use(presetKeys[i]);
            store.setAll(options.presets[presetKeys[i]]);
        }
    }
    if (options.defaults) {
        const store = manager.use(StoreName.DEFAULT);
        store.setAll(options.defaults);
    }
}

function getSymbol(key) {
    if (typeof key === 'string') {
        return Symbol.for(`VCStoreManager#${key}`);
    }
    return Symbol.for('VCStoreManager');
}
function installStoreManager(instance, key) {
    let manager;
    const symbol = getSymbol(key);
    if (instance._context && instance._context.provides && instance._context.provides[symbol]) {
        return instance._context.provides[symbol];
    }
    if (hasInjectionContext()) {
        manager = inject(symbol, undefined);
        if (manager) {
            return manager;
        }
    }
    manager = new StoreManager();
    instance.provide(symbol, manager);
    return manager;
}
function injectStoreManager(key) {
    const symbol = getSymbol(key);
    const manager = inject(symbol);
    if (!manager) {
        throw new Error('The store manager has not been setup.');
    }
    return manager;
}

// eslint-disable-next-line @typescript-eslint/ban-types
function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}

function evaluateFnOrValue(input, ...args) {
    if (typeof input === 'function') {
        return input(...args);
    }
    return input;
}

function isObject(input) {
    return typeof input === 'object' && input !== null && !Array.isArray(input) && !!input;
}

/**
 * Returns true if either scoped or unscoped named slot exists
 *
 * @returns bool
 *
 * @param name
 * @param $slots
 */ function hasNormalizedSlot(name, $slots = {}) {
    return hasOwnProperty($slots, name);
}
/**
 * Returns VNodes for named slot either scoped or unscoped
 *
 * @param name
 * @param scope
 * @param $slots
 *
 * @returns {Array} VNodes
 */ function normalizeSlot(name, scope = {}, $slots = {}) {
    if (hasOwnProperty($slots, name)) {
        return $slots[name](scope);
    }
    return [];
}

function isPromise(p) {
    return isObject(p) && (p instanceof Promise || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    typeof p.then === 'function');
}

function unrefWithDefault(value, alt) {
    const raw = unref(value);
    if (typeof raw === 'undefined') {
        return alt;
    }
    return raw;
}
function setMaybeRefValue(input, value) {
    if (isRef(input)) {
        if (!isReadonly(input)) {
            input.value = value;
        }
    }
}
function pushMaybeRefArrayValue(input, value) {
    if (isRef(input)) {
        input.value.push(value);
    } else {
        input.push(value);
    }
    return value;
}
function spliceMaybeRefArray(input, index, amount) {
    if (isRef(input)) {
        input.value.splice(index, amount);
    } else {
        input.splice(index, amount);
    }
    return input;
}
function getMaybeRefArrayValue(input, index) {
    if (isRef(input)) {
        return input.value[index];
    }
    return input[index];
}
function extendMaybeRefArrayValue(input, index, value) {
    if (!isObject$1(value) && !Array.isArray(value)) {
        return input;
    }
    const item = getMaybeRefArrayValue(input, index);
    if (isObject$1(item) || Array.isArray(item)) {
        if (isRef(input)) {
            input.value[index] = merge(value, item);
        } else {
            input[index] = merge(value, item);
        }
    }
    return input;
}
function findIndexOfMaybeRefArray(input, filterFn) {
    if (isRef(input)) {
        return input.value.findIndex(filterFn);
    }
    return input.findIndex(filterFn);
}

function isVNodeClassOption(name) {
    return name.toLowerCase().indexOf('class') !== -1;
}
function isVNodeStyleOption(name) {
    return name.toLowerCase().indexOf('style') !== -1;
}
function isVNodeListenerOption(name) {
    return name.startsWith('on');
}
function isVNodePropsOption(name) {
    return name.toLowerCase().indexOf('props') !== -1;
}
function isVNodeOption(name) {
    return isVNodeClassOption(name) || isVNodeStyleOption(name) || isVNodeListenerOption(name) || isVNodePropsOption(name);
}
function mergeVNodeOption(key, target, source) {
    if (typeof target === 'undefined') {
        return source;
    }
    if (typeof source === 'undefined') {
        return target;
    }
    if (isVNodeClassOption(key)) {
        const { class: clazz } = mergeProps({
            class: target
        }, {
            class: source
        });
        return clazz;
    }
    if (isVNodeStyleOption(key)) {
        const { style } = mergeProps({
            style: target
        }, {
            style: source
        });
        return style;
    }
    if (isVNodeListenerOption(key)) {
        const { [key]: listener } = mergeProps({
            [key]: target
        }, {
            [key]: source
        });
        return listener;
    }
    if (isVNodePropsOption(key)) {
        return mergeProps(target, source);
    }
    return target ?? source;
}

function mergeOption(key, target, source) {
    if (isVNodeOption(key)) {
        return mergeVNodeOption(key, target, source);
    }
    if (isObject$1(target) && isObject$1(source)) {
        return merge(target, source);
    }
    return target ?? source;
}

function isComponentOptionInputConfigWithPresets(input) {
    if (!isObject$1(input)) {
        return false;
    }
    const { presets } = input;
    if (!isObject$1(presets)) {
        return false;
    }
    const keys = Object.keys(presets);
    for(let i = 0; i < keys.length; i++){
        if (!hasOwnProperty(presets, keys[i]) || typeof presets[keys[i]] !== 'boolean') {
            return false;
        }
    }
    return true;
}
function isComponentOptionInputConfigWithDefaults(input) {
    if (!isObject$1(input)) {
        return false;
    }
    const { defaults } = input;
    return typeof defaults === 'boolean';
}
function isComponentOptionInputConfig(value) {
    return isComponentOptionInputConfigWithPresets(value) || isComponentOptionInputConfigWithDefaults(value);
}

class ComponentOptionsManager {
    // ---------------------------------------------------------
    build(context) {
        let value;
        const presetConfig = {};
        if (isComponentOptionInputConfigWithPresets(context.value)) {
            const keys = Object.keys(context.value.presets);
            for(let i = 0; i < keys.length; i++){
                presetConfig[keys[i]] = context.value.presets[keys[i]];
            }
            if (typeof context.value.value !== 'undefined') {
                value = context.value.value;
            }
        }
        if (!isComponentOptionInputConfig(context.value)) {
            value = context.value;
        }
        if (typeof value === 'undefined') {
            if (!isComponentOptionInputConfigWithDefaults(context.value) || context.value.defaults) {
                const store = this.storeManager.use(StoreName.DEFAULT);
                if (store.hasOption(this.component, context.key)) {
                    value = store.getOption(this.component, context.key);
                }
            }
        }
        const keys = this.storeManager.keys();
        for(let i = 0; i < keys.length; i++){
            if (keys[i] === StoreName.DEFAULT) {
                continue;
            }
            if (hasOwnProperty(presetConfig, keys[i]) && !presetConfig[keys[i]]) {
                continue;
            }
            const presetStore = this.storeManager.use(keys[i]);
            if (presetStore.hasOption(this.component, context.key)) {
                value = mergeOption(context.key, value, presetStore.getOption(this.component, context.key));
            }
        }
        if (typeof value === 'undefined') {
            return context.alt;
        }
        return value;
    }
    buildOrFail(context) {
        const target = this.build(context);
        if (typeof target === 'undefined' && !hasOwnProperty(context, 'alt')) {
            throw new Error(`A value for option ${context.key} of component ${this.component} is required.`);
        }
        return target;
    }
    // ---------------------------------------------------------
    constructor(context){
        this.component = context.name;
        this.storeManager = context.storeManager || injectStoreManager(context.storeManagerKey);
    }
}

function createComponentOptionsManager(component) {
    return new ComponentOptionsManager(component);
}

export { Store, StoreManager, StoreName, applyStoreManagerOptions, createComponentOptionsManager, evaluateFnOrValue, extendMaybeRefArrayValue, findIndexOfMaybeRefArray, getMaybeRefArrayValue, hasNormalizedSlot, hasOwnProperty, injectStoreManager, installStoreManager, isComponentOptionInputConfig, isComponentOptionInputConfigWithDefaults, isComponentOptionInputConfigWithPresets, isObject, isPromise, isVNodeClassOption, isVNodeListenerOption, isVNodeOption, isVNodePropsOption, isVNodeStyleOption, mergeOption, mergeVNodeOption, normalizeSlot, pushMaybeRefArrayValue, setMaybeRefValue, spliceMaybeRefArray, unrefWithDefault };
//# sourceMappingURL=index.mjs.map
