import { Fun, Optional, Singleton } from '@ephox/katamari';
import * as ComponentStructure from '../../alien/ComponentStructure';
import * as AriaControls from '../../aria/AriaControls';
import * as MaxWidth from '../../positioning/layout/MaxWidth';
import * as Dismissal from '../../sandbox/Dismissal';
import * as Reposition from '../../sandbox/Reposition';
import * as FloatingToolbarButtonSchema from '../../ui/schema/FloatingToolbarButtonSchema';
import * as Behaviour from '../behaviour/Behaviour';
import { Coupling } from '../behaviour/Coupling';
import { Focusing } from '../behaviour/Focusing';
import { Keying } from '../behaviour/Keying';
import { Positioning } from '../behaviour/Positioning';
import { Receiving } from '../behaviour/Receiving';
import { Sandboxing } from '../behaviour/Sandboxing';
import { Toggling } from '../behaviour/Toggling';
import { SketchBehaviours } from '../component/SketchBehaviours';
import { Button } from './Button';
import * as Sketcher from './Sketcher';
import { Toolbar } from './Toolbar';
const shouldSkipFocus = Singleton.value();
const toggleWithoutFocusing = (button, externals) => {
    shouldSkipFocus.set(true);
    toggle(button, externals);
    shouldSkipFocus.clear();
};
const toggle = (button, externals) => {
    const toolbarSandbox = Coupling.getCoupled(button, 'toolbarSandbox');
    if (Sandboxing.isOpen(toolbarSandbox)) {
        Sandboxing.close(toolbarSandbox);
    }
    else {
        Sandboxing.open(toolbarSandbox, externals.toolbar());
    }
};
const position = (button, toolbar, detail, layouts) => {
    const bounds = detail.getBounds.map((bounder) => bounder());
    const sink = detail.lazySink(button).getOrDie();
    Positioning.positionWithinBounds(sink, toolbar, {
        anchor: {
            type: 'hotspot',
            hotspot: button,
            layouts,
            overrides: {
                maxWidthFunction: MaxWidth.expandable()
            }
        }
    }, bounds);
};
const setGroups = (button, toolbar, detail, layouts, groups) => {
    Toolbar.setGroups(toolbar, groups);
    position(button, toolbar, detail, layouts);
    Toggling.on(button);
};
const makeSandbox = (button, spec, detail) => {
    const ariaControls = AriaControls.manager();
    const onOpen = (sandbox, toolbar) => {
        const skipFocus = shouldSkipFocus.get().getOr(false);
        detail.fetch().get((groups) => {
            setGroups(button, toolbar, detail, spec.layouts, groups);
            ariaControls.link(button.element);
            if (!skipFocus) {
                Keying.focusIn(toolbar);
            }
        });
    };
    const onClose = () => {
        // Toggle and focus the button
        Toggling.off(button);
        if (!shouldSkipFocus.get().getOr(false)) {
            Focusing.focus(button);
        }
        ariaControls.unlink(button.element);
    };
    return {
        dom: {
            tag: 'div',
            attributes: {
                id: ariaControls.id
            }
        },
        behaviours: Behaviour.derive([
            Keying.config({
                mode: 'special',
                onEscape: (comp) => {
                    Sandboxing.close(comp);
                    return Optional.some(true);
                }
            }),
            Sandboxing.config({
                onOpen,
                onClose,
                isPartOf: (container, data, queryElem) => {
                    return ComponentStructure.isPartOf(data, queryElem) || ComponentStructure.isPartOf(button, queryElem);
                },
                getAttachPoint: () => {
                    return detail.lazySink(button).getOrDie();
                }
            }),
            Receiving.config({
                channels: {
                    ...Dismissal.receivingChannel({
                        isExtraPart: Fun.never,
                        ...detail.fireDismissalEventInstead.map((fe) => ({ fireEventInstead: { event: fe.event } })).getOr({})
                    }),
                    ...Reposition.receivingChannel({
                        doReposition: () => {
                            Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each((toolbar) => {
                                position(button, toolbar, detail, spec.layouts);
                            });
                        }
                    })
                }
            })
        ])
    };
};
const factory = (detail, components, spec, externals) => ({
    ...Button.sketch({
        ...externals.button(),
        action: (button) => {
            toggle(button, externals);
        },
        buttonBehaviours: SketchBehaviours.augment({ dump: externals.button().buttonBehaviours }, [
            Coupling.config({
                others: {
                    toolbarSandbox: (button) => {
                        return makeSandbox(button, spec, detail);
                    }
                }
            })
        ])
    }),
    apis: {
        setGroups: (button, groups) => {
            Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each((toolbar) => {
                setGroups(button, toolbar, detail, spec.layouts, groups);
            });
        },
        reposition: (button) => {
            Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each((toolbar) => {
                position(button, toolbar, detail, spec.layouts);
            });
        },
        toggle: (button) => {
            toggle(button, externals);
        },
        toggleWithoutFocusing: (button) => {
            toggleWithoutFocusing(button, externals);
        },
        getToolbar: (button) => {
            return Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox'));
        },
        isOpen: (button) => {
            return Sandboxing.isOpen(Coupling.getCoupled(button, 'toolbarSandbox'));
        }
    }
});
const FloatingToolbarButton = Sketcher.composite({
    name: 'FloatingToolbarButton',
    factory,
    configFields: FloatingToolbarButtonSchema.schema(),
    partFields: FloatingToolbarButtonSchema.parts(),
    apis: {
        setGroups: (apis, button, groups) => {
            apis.setGroups(button, groups);
        },
        reposition: (apis, button) => {
            apis.reposition(button);
        },
        toggle: (apis, button) => {
            apis.toggle(button);
        },
        toggleWithoutFocusing: (apis, button) => {
            apis.toggleWithoutFocusing(button);
        },
        getToolbar: (apis, button) => apis.getToolbar(button),
        isOpen: (apis, button) => apis.isOpen(button)
    }
});
export { FloatingToolbarButton };
//# sourceMappingURL=FloatingToolbarButton.js.map