"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventTargetImpl = void 0;
const DOMException_1 = require("./DOMException");
const util_1 = require("../util");
const algorithm_1 = require("../algorithm");
/**
 * Represents a target to which an event can be dispatched.
 */
class EventTargetImpl {
    __eventListenerList;
    get _eventListenerList() {
        return this.__eventListenerList || (this.__eventListenerList = []);
    }
    __eventHandlerMap;
    get _eventHandlerMap() {
        return this.__eventHandlerMap || (this.__eventHandlerMap = {});
    }
    /**
     * Initializes a new instance of `EventTarget`.
     */
    constructor() { }
    /** @inheritdoc */
    addEventListener(type, callback, options = { passive: false, once: false, capture: false }) {
        /**
         * 1. Let capture, passive, and once be the result of flattening more options.
         */
        const [capture, passive, once] = (0, algorithm_1.eventTarget_flattenMore)(options);
        // convert callback function to EventListener, return if null
        let listenerCallback;
        if (!callback) {
            return;
        }
        else if (util_1.Guard.isEventListener(callback)) {
            listenerCallback = callback;
        }
        else {
            listenerCallback = { handleEvent: callback };
        }
        /**
         * 2. Add an event listener with the context object and an event listener
         * whose type is type, callback is callback, capture is capture, passive is
         * passive, and once is once.
         */
        (0, algorithm_1.eventTarget_addEventListener)(this, {
            type: type,
            callback: listenerCallback,
            capture: capture,
            passive: passive,
            once: once,
            removed: false
        });
    }
    /** @inheritdoc */
    removeEventListener(type, callback, options = { capture: false }) {
        /**
         * TODO: Implement realms
         * 1. If the context object’s relevant global object is a
         * ServiceWorkerGlobalScope object and its associated service worker’s
         * script resource’s has ever been evaluated flag is set, then throw
         * a TypeError. [SERVICE-WORKERS]
         */
        /**
         * 2. Let capture be the result of flattening options.
         */
        const capture = (0, algorithm_1.eventTarget_flatten)(options);
        if (!callback)
            return;
        /**
         * 3. If the context object’s event listener list contains an event listener
         * whose type is type, callback is callback, and capture is capture, then
         * remove an event listener with the context object and that event listener.
         */
        for (let i = 0; i < this._eventListenerList.length; i++) {
            const entry = this._eventListenerList[i];
            if (entry.type !== type || entry.capture !== capture)
                continue;
            if (util_1.Guard.isEventListener(callback) && entry.callback === callback) {
                (0, algorithm_1.eventTarget_removeEventListener)(this, entry, i);
                break;
            }
            else if (callback && entry.callback.handleEvent === callback) {
                (0, algorithm_1.eventTarget_removeEventListener)(this, entry, i);
                break;
            }
        }
    }
    /** @inheritdoc */
    dispatchEvent(event) {
        /**
         * 1. If event’s dispatch flag is set, or if its initialized flag is not
         * set, then throw an "InvalidStateError" DOMException.
         * 2. Initialize event’s isTrusted attribute to false.
         * 3. Return the result of dispatching event to the context object.
         */
        if (event._dispatchFlag || !event._initializedFlag) {
            throw new DOMException_1.InvalidStateError();
        }
        event._isTrusted = false;
        return (0, algorithm_1.event_dispatch)(event, this);
    }
    /** @inheritdoc */
    _getTheParent(event) {
        return null;
    }
}
exports.EventTargetImpl = EventTargetImpl;
//# sourceMappingURL=EventTargetImpl.js.map