import { Disposable } from '@zephyr3d/base';
import { getDevice } from '../app/api.js';

class RenderBundleWrapper extends Disposable {
    _renderBundles;
    static _drawableContainer = new WeakMap();
    static _materialContainer = new WeakMap();
    static _primitiveContainer = new WeakMap();
    /** @internal */ static addDrawable(drawable, material, primitive, wrapper, hash) {
        let renderBundles = this._drawableContainer.get(drawable);
        if (!renderBundles) {
            renderBundles = [];
            this._drawableContainer.set(drawable, renderBundles);
        }
        const index = renderBundles.findIndex((rb)=>rb.wrapper === wrapper);
        if (index < 0) {
            renderBundles.push({
                wrapper: wrapper,
                hashes: [
                    hash
                ]
            });
        } else {
            if (!renderBundles[index].hashes.includes(hash)) {
                renderBundles[index].hashes.push(hash);
            }
        }
        if (material) {
            let ownDrawables = this._materialContainer.get(material);
            if (!ownDrawables) {
                ownDrawables = new Set();
                this._materialContainer.set(material, ownDrawables);
            }
            ownDrawables.add(drawable);
        }
        if (primitive) {
            let ownDrawables = this._primitiveContainer.get(primitive);
            if (!ownDrawables) {
                ownDrawables = new Set();
                this._primitiveContainer.set(primitive, ownDrawables);
            }
            ownDrawables.add(drawable);
        }
    }
    /** @internal */ static drawableChanged(drawable) {
        const renderBundles = this._drawableContainer.get(drawable);
        if (renderBundles) {
            for(let i = renderBundles.length - 1; i >= 0; i--){
                const renderBundle = renderBundles[i].wrapper;
                if (renderBundle.disposed) {
                    renderBundles.splice(i, 1);
                } else {
                    for (const hash of renderBundles[i].hashes){
                        renderBundles[i].wrapper.invalidate(hash);
                    }
                }
            }
        }
    }
    /** @internal */ static primitiveChanged(primitive) {
        const ownDrawables = this._primitiveContainer.get(primitive);
        if (ownDrawables) {
            for (const drawable of ownDrawables){
                this.drawableChanged(drawable);
            }
        }
    }
    /** @internal */ static primitiveAttached(primitive, drawable) {
        if (this._drawableContainer.has(drawable)) {
            const ownDrawables = this._primitiveContainer.get(primitive);
            if (!ownDrawables) {
                this._primitiveContainer.set(primitive, new Set([
                    drawable
                ]));
            } else {
                ownDrawables.add(drawable);
            }
            this.drawableChanged(drawable);
        }
    }
    /** @internal */ static primitiveDetached(primitive, drawable) {
        const ownDrawables = this._primitiveContainer.get(primitive);
        if (ownDrawables && ownDrawables.has(drawable)) {
            ownDrawables.delete(drawable);
            this.drawableChanged(drawable);
        }
    }
    /** @internal */ static materialChanged(material) {
        const ownDrawables = this._materialContainer.get(material);
        if (ownDrawables) {
            for (const drawable of ownDrawables){
                this.drawableChanged(drawable);
            }
        }
    }
    /** @internal */ static materialUniformsChanged(material) {
        const ownDrawables = this._materialContainer.get(material);
        if (ownDrawables) {
            for (const drawable of ownDrawables){
                if (drawable.isBatchable()) {
                    drawable.applyMaterialUniformsAll();
                }
            }
        }
    }
    /** @internal */ static materialAttached(material, drawable) {
        if (this._drawableContainer.has(drawable)) {
            const ownDrawables = this._materialContainer.get(material);
            if (!ownDrawables) {
                this._materialContainer.set(material, new Set([
                    drawable
                ]));
            } else {
                ownDrawables.add(drawable);
            }
            this.drawableChanged(drawable);
        }
    }
    /** @internal */ static materialDetached(material, drawable) {
        const ownDrawables = this._materialContainer.get(material);
        if (ownDrawables && ownDrawables.has(drawable)) {
            ownDrawables.delete(drawable);
            this.drawableChanged(drawable);
        }
    }
    constructor(){
        super();
        this._renderBundles = {};
    }
    getRenderBundle(hash) {
        return this._renderBundles[hash] ?? null;
    }
    beginRenderBundle() {
        getDevice().beginCapture();
    }
    endRenderBundle(hash) {
        this._renderBundles[hash] = getDevice().endCapture();
    }
    invalidate(hash) {
        this._renderBundles[hash] = undefined;
    }
    onDispose() {
        super.onDispose();
        this._renderBundles = {};
    }
}

export { RenderBundleWrapper };
//# sourceMappingURL=renderbundle_wrapper.js.map
