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

/**
 *
 * @enum {number}
 */
export const SignalHandlerFlags = {
    /**
     * Handler should be de-registered after it is executed
     */
    RemoveAfterExecution: 1
};

/**
 * Represents a handler for signals in the event system.
 *
 * Used to encapsulate callback functions along with their execution context and provide flag-based behavior control.
 * They can be organized into linked lists using the `next` property to form a chain of handlers.
 *
 * @see Signal
 */
export class SignalHandler {
    /**
     * Optional field. Used for forming linked lists of handlers
     * @type {SignalHandler|null}
     */
    next = null;

    /**
     * @private
     * @type {number|SignalHandlerFlags}
     */
    flags = 0;

    /**
     * Used to determine if the handler was added mid-dispatch
     * @type {number}
     */
    generation = -1;

    /**
     *
     * @param {function} handle
     * @param {*} [context]
     */
    constructor(handle, context) {
        assert.defined(handle, 'handle');
        assert.isFunction(handle, 'handle');

        this.handle = handle;
        this.context = context;

    }

    /**
     *
     * @param {number|SignalHandlerFlags} flag
     * @returns {void}
     */
    setFlag(flag) {
        this.flags |= flag;
    }

    /**
     *
     * @param {number|SignalHandlerFlags} flag
     * @returns {void}
     */
    clearFlag(flag) {
        this.flags &= ~flag;
    }

    /**
     *
     * @param {number|SignalHandlerFlags} flag
     * @param {boolean} value
     */
    writeFlag(flag, value) {
        if (value) {
            this.setFlag(flag);
        } else {
            this.clearFlag(flag);
        }
    }

    /**
     *
     * @param {number|SignalHandlerFlags} flag
     * @returns {boolean}
     */
    getFlag(flag) {
        return (this.flags & flag) === flag;
    }

}

/**
 * @readonly
 * @type {boolean}
 */
SignalHandler.prototype.isSignalHandler = true;
