import ClassMethodBinder from '../../utilities/ClassMethodBinder.js';
import * as PropertySymbol from '../../PropertySymbol.js';
/**
 * NodeList.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList
 */
class NodeList {
    [PropertySymbol.items];
    [PropertySymbol.proxy];
    /**
     * Constructor.
     *
     * @param illegalConstructorSymbol Illegal constructor symbol.
     * @param items Items.
     */
    constructor(illegalConstructorSymbol, items) {
        if (illegalConstructorSymbol !== PropertySymbol.illegalConstructor) {
            throw new TypeError('Illegal constructor');
        }
        this[PropertySymbol.items] = items;
        const methodBinder = new ClassMethodBinder(this, this.constructor !== NodeList ? [this.constructor, NodeList] : [NodeList]);
        const proxy = new Proxy(this, {
            get: (target, property) => {
                if (property === 'length') {
                    return items.length;
                }
                if (property in target || typeof property === 'symbol') {
                    methodBinder.bind(property);
                    return target[property];
                }
                if (property === '') {
                    return undefined;
                }
                const index = Number(property);
                if (!isNaN(index)) {
                    return items[index];
                }
            },
            set(target, property, newValue) {
                methodBinder.bind(property);
                if (typeof property === 'symbol') {
                    target[property] = newValue;
                    return true;
                }
                const index = Number(property);
                if (isNaN(index)) {
                    target[property] = newValue;
                }
                return true;
            },
            deleteProperty(target, property) {
                if (typeof property === 'symbol') {
                    delete target[property];
                    return true;
                }
                const index = Number(property);
                if (isNaN(index)) {
                    delete target[property];
                }
                return true;
            },
            ownKeys() {
                return Object.keys(items);
            },
            has(target, property) {
                if (property in target) {
                    return true;
                }
                if (typeof property === 'symbol') {
                    return false;
                }
                const index = Number(property);
                return !isNaN(index) && index >= 0 && index < items.length;
            },
            defineProperty(target, property, descriptor) {
                methodBinder.preventBinding(property);
                if (property in target) {
                    Object.defineProperty(target, property, descriptor);
                    return true;
                }
                return false;
            },
            getOwnPropertyDescriptor(target, property) {
                if (property in target || typeof property === 'symbol') {
                    return;
                }
                const index = Number(property);
                if (!isNaN(index) && items[index]) {
                    return {
                        value: items[index],
                        writable: false,
                        enumerable: true,
                        configurable: true
                    };
                }
            }
        });
        this[PropertySymbol.proxy] = proxy;
        return proxy;
    }
    /**
     * Returns length.
     *
     * @returns Length.
     */
    get length() {
        return this[PropertySymbol.items].length;
    }
    /**
     * Returns `Symbol.toStringTag`.
     *
     * @returns `Symbol.toStringTag`.
     */
    get [Symbol.toStringTag]() {
        return 'NodeList';
    }
    /**
     * Returns `[object NodeList]`.
     *
     * @returns `[object NodeList]`.
     */
    toLocaleString() {
        return '[object NodeList]';
    }
    /**
     * Returns `[object NodeList]`.
     *
     * @returns `[object NodeList]`.
     */
    toString() {
        return '[object NodeList]';
    }
    /**
     * Returns item by index.
     *
     * @param index Index.
     */
    item(index) {
        const nodes = this[PropertySymbol.items];
        return index >= 0 && nodes[index] ? nodes[index] : null;
    }
    /**
     * Returns an iterator, allowing you to go through all values of the key/value pairs contained in this object.
     *
     * @returns Iterator.
     */
    [Symbol.iterator]() {
        const items = this[PropertySymbol.items];
        return items[Symbol.iterator]();
    }
    /**
     * Returns an iterator, allowing you to go through all values of the key/value pairs contained in this object.
     *
     * @returns Iterator.
     */
    values() {
        return this[PropertySymbol.items].values();
    }
    /**
     * Returns an iterator, allowing you to go through all key/value pairs contained in this object.
     *
     * @returns Iterator.
     */
    entries() {
        return this[PropertySymbol.items].entries();
    }
    /**
     * Executes a provided callback function once for each DOMTokenList element.
     *
     * @param callback Function.
     * @param thisArg thisArg.
     */
    forEach(callback, thisArg) {
        const items = this[PropertySymbol.items];
        const proxy = this[PropertySymbol.proxy] ?? this;
        for (let i = 0, max = items.length; i < max; i++) {
            const item = items[i];
            callback.call(thisArg ?? item[PropertySymbol.window], item, i, proxy);
        }
    }
    /**
     * Returns an iterator, allowing you to go through all keys of the key/value pairs contained in this object.
     *
     * @returns Iterator.
     */
    keys() {
        return this[PropertySymbol.items].keys();
    }
}
export default NodeList;
//# sourceMappingURL=NodeList.js.map