import { Arr, Cell, Obj, Optional, Optionals, Singleton } from '@ephox/katamari';
import * as MenuPathing from './MenuPathing';
const init = () => {
    const expansions = Cell({});
    const menus = Cell({});
    const paths = Cell({});
    const primary = Singleton.value();
    // Probably think of a better way to store this information.
    const directory = Cell({});
    const clear = () => {
        expansions.set({});
        menus.set({});
        paths.set({});
        primary.clear();
    };
    const isClear = () => primary.get().isNone();
    const setMenuBuilt = (menuName, built) => {
        menus.set({
            ...menus.get(),
            [menuName]: {
                type: 'prepared',
                menu: built
            }
        });
    };
    const setContents = (sPrimary, sMenus, sExpansions, dir) => {
        primary.set(sPrimary);
        expansions.set(sExpansions);
        menus.set(sMenus);
        directory.set(dir);
        const sPaths = MenuPathing.generate(dir, sExpansions);
        paths.set(sPaths);
    };
    const getTriggeringItem = (menuValue) => Obj.find(expansions.get(), (v, _k) => v === menuValue);
    const getTriggerData = (menuValue, getItemByValue, path) => getPreparedMenu(menuValue).bind((menu) => getTriggeringItem(menuValue).bind((triggeringItemValue) => getItemByValue(triggeringItemValue).map((triggeredItem) => ({
        triggeredMenu: menu,
        triggeringItem: triggeredItem,
        triggeringPath: path
    }))));
    const getTriggeringPath = (itemValue, getItemByValue) => {
        // Get the path up to the last item
        const extraPath = Arr.filter(lookupItem(itemValue).toArray(), (menuValue) => getPreparedMenu(menuValue).isSome());
        return Obj.get(paths.get(), itemValue).bind((path) => {
            // remember the path is [ most-recent-menu, next-most-recent-menu ]
            // convert each menu identifier into { triggeringItem: comp, menu: comp }
            // could combine into a fold ... probably a left to reverse ... but we'll take the
            // straightforward version when prototyping
            const revPath = Arr.reverse(extraPath.concat(path));
            const triggers = Arr.bind(revPath, (menuValue, menuIndex) => 
            // finding menuValue, it should match the trigger
            getTriggerData(menuValue, getItemByValue, revPath.slice(0, menuIndex + 1)).fold(() => Optionals.is(primary.get(), menuValue) ? [] : [Optional.none()], (data) => [Optional.some(data)]));
            // Convert List<Optional<X>> to Optional<List<X>> if ALL are Some
            return Optionals.sequence(triggers);
        });
    };
    // Given an item, return a list of all menus including the one that it triggered (if there is one)
    const expand = (itemValue) => Obj.get(expansions.get(), itemValue).map((menu) => {
        const current = Obj.get(paths.get(), itemValue).getOr([]);
        return [menu].concat(current);
    });
    const collapse = (itemValue) => 
    // Look up which key has the itemValue
    Obj.get(paths.get(), itemValue).bind((path) => path.length > 1 ? Optional.some(path.slice(1)) : Optional.none());
    const refresh = (itemValue) => Obj.get(paths.get(), itemValue);
    const getPreparedMenu = (menuValue) => lookupMenu(menuValue).bind(extractPreparedMenu);
    const lookupMenu = (menuValue) => Obj.get(menus.get(), menuValue);
    const lookupItem = (itemValue) => Obj.get(expansions.get(), itemValue);
    const otherMenus = (path) => {
        const menuValues = directory.get();
        return Arr.difference(Obj.keys(menuValues), path);
    };
    const getPrimary = () => primary.get().bind(getPreparedMenu);
    const getMenus = () => menus.get();
    return {
        setMenuBuilt,
        setContents,
        expand,
        refresh,
        collapse,
        lookupMenu,
        lookupItem,
        otherMenus,
        getPrimary,
        getMenus,
        clear,
        isClear,
        getTriggeringPath
    };
};
const extractPreparedMenu = (prep) => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none();
export const LayeredState = {
    init,
    extractPreparedMenu
};
//# sourceMappingURL=LayeredState.js.map