import { ImmutableObjectPool } from "../../../../../core/model/object/ImmutableObjectPool.js";


export class RenderResourceManager {


    /**
     *
     * @type {IFrameGraphContext|null}
     */
    #ctx = null;

    /**
     *
     * @type {Map<*, ResourceDescriptor>}
     */
    #resource_descriptors = new Map();

    /**
     *
     * @type {ImmutableObjectPool<ResourceDescriptor, *>}
     */
    #cache = new ImmutableObjectPool();

    attach(ctx) {
        this.#ctx = ctx;
    }

    constructor() {
        this.#cache.onRemoved.add((descriptor, resource) => {

            this.#ctx.destroyResource(resource, descriptor);

        });
    }

    /**
     * @template T
     * @param {ResourceDescriptor<T>} descriptor
     * @returns {T}
     */
    get(descriptor) {
        let resource = this.#cache.get(descriptor);

        if (resource === undefined) {
            // nothing in cache, create a new one
            resource = this.#ctx.createResource(descriptor);
        }

        const existing_descriptor = this.#resource_descriptors.get(resource);

        if (existing_descriptor !== undefined) {
            throw new Error(`Resource is already associated with a live descriptor`);
        }

        this.#resource_descriptors.set(resource, descriptor);

        return resource;
    }

    /**
     * @template T
     * @param {T} resource
     */
    release(resource) {

        const descriptor = this.#resource_descriptors.get(resource);

        if (descriptor === undefined) {
            throw new Error(`Resource is not managed`);
        }

        this.#resource_descriptors.delete(resource);

        this.#cache.add(descriptor, resource);

    }

    /**
     * Release all held resources including ones issues in cache and held externally
     * All resources issues by the manager are affected
     */
    destroy() {
        this.#cache.clear()

        // release all held resources
        for (const resource of this.#resource_descriptors.keys()) {

            const descriptor = this.#resource_descriptors.get(resource);

            this.#ctx.destroyResource(resource, descriptor);

        }

        this.#resource_descriptors.clear();
    }
}