import { Adt, Arr, Fun } from '@ephox/katamari';
import { Traverse } from '@ephox/sugar';
import * as DescribedHandler from './DescribedHandler';
import * as EventSource from './EventSource';
import { fromExternal, fromSource } from './SimulatedEvent';
const adt = Adt.generate([
    { stopped: [] },
    { resume: ['element'] },
    { complete: [] }
]);
const doTriggerHandler = (lookup, eventType, rawEvent, target, source, logger) => {
    const handler = lookup(eventType, target);
    const simulatedEvent = fromSource(rawEvent, source);
    return handler.fold(() => {
        // No handler, so complete.
        logger.logEventNoHandlers(eventType, target);
        return adt.complete();
    }, (handlerInfo) => {
        const descHandler = handlerInfo.descHandler;
        const eventHandler = DescribedHandler.getCurried(descHandler);
        eventHandler(simulatedEvent);
        // Now, check if the event was stopped.
        if (simulatedEvent.isStopped()) {
            logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose);
            return adt.stopped();
        }
        else if (simulatedEvent.isCut()) {
            logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose);
            return adt.complete();
        }
        else {
            return Traverse.parent(handlerInfo.element).fold(() => {
                logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose);
                // No parent, so complete.
                return adt.complete();
            }, (parent) => {
                logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose);
                // Resume at parent
                return adt.resume(parent);
            });
        }
    });
};
const doTriggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, source, logger) => doTriggerHandler(lookup, eventType, rawEvent, rawTarget, source, logger).fold(
// stopped.
Fun.always, 
// Go again.
(parent) => doTriggerOnUntilStopped(lookup, eventType, rawEvent, parent, source, logger), 
// completed
Fun.never);
const triggerHandler = (lookup, eventType, rawEvent, target, logger) => {
    const source = EventSource.derive(rawEvent, target);
    return doTriggerHandler(lookup, eventType, rawEvent, target, source, logger);
};
const broadcast = (listeners, rawEvent, _logger) => {
    const simulatedEvent = fromExternal(rawEvent);
    Arr.each(listeners, (listener) => {
        const descHandler = listener.descHandler;
        const handler = DescribedHandler.getCurried(descHandler);
        handler(simulatedEvent);
    });
    return simulatedEvent.isStopped();
};
const triggerUntilStopped = (lookup, eventType, rawEvent, logger) => triggerOnUntilStopped(lookup, eventType, rawEvent, rawEvent.target, logger);
const triggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, logger) => {
    const source = EventSource.derive(rawEvent, rawTarget);
    return doTriggerOnUntilStopped(lookup, eventType, rawEvent, rawTarget, source, logger);
};
export { triggerHandler, triggerUntilStopped, triggerOnUntilStopped, broadcast };
//# sourceMappingURL=Triggers.js.map