import { assert } from "../../assert.js";
import { SignalHandlerFlags } from "./SignalHandler.js";

/**
 * Common dispatch stack
 * @readonly
 * @type {SignalHandler[]}
 */
const dispatch_stack = [];
let dispatch_stack_top = 0;

/**
 *
 * @param {function} f
 * @param {*} context
 * @param {Array} args
 */
function dispatchCallback(f, context, args) {
    assert.isFunction(f, 'f');

    try {
        f.apply(context, args)
    } catch (e) {
        console.error("Failed to dispatch handler", f, e);
    }
}

/**
 *
 * @param {SignalHandler[]} handlers
 * @param {Array} [args]
 */
export function dispatchViaProxy(handlers, args) {
    const length = handlers.length;

    const stack_pointer = dispatch_stack_top;
    const stack_frame_end = stack_pointer + length;
    dispatch_stack_top = stack_frame_end;

    let i, h;
    for (i = 0; i < length; i++) {
        //copy to proxy
        dispatch_stack[stack_pointer + i] = handlers[length - (i + 1)];
    }

    for (i = stack_frame_end - 1; i >= stack_pointer; i--) {
        h = dispatch_stack[i];

        if (h.getFlag(SignalHandlerFlags.RemoveAfterExecution)) {
            //handler should be cut
            const p = handlers.indexOf(h);
            handlers.splice(p, 1);
        }

        dispatchCallback(h.handle, h.context, args);
    }

    //drop stack frame
    dispatch_stack_top = stack_pointer;
}