import { AbstractTextureAtlas } from "./AbstractTextureAtlas.js";
import { Reference } from "../../../reference/v2/Reference.js";

export class ReferencedTextureAtlas extends AbstractTextureAtlas {
    /**
     *
     * @param {AbstractTextureAtlas} atlas
     */
    constructor(atlas) {
        super();

        this.__atlas = atlas;

        /**
         *
         * @type {Map<Sampler2D, AtlasPatch>}
         * @private
         */
        this.__patches = new Map();
        /**
         *
         * @type {Map<AtlasPatch, number>}
         * @private
         */
        this.__ref_counts = new Map();

    }

    update() {
        this.__atlas.update();
    }

    /**
     *
     * @param {Reference} ref
     * @param {AtlasPatch} patch
     * @private
     */
    __handle_ref_release(ref, patch) {
        const ref_counts = this.__ref_counts;

        const ref_count = ref_counts.get(patch);
        ref_counts.set(patch, ref_count - 1);

        if (ref_count === 1) {
            // last reference removed, clear patch
            this.__atlas.remove(patch);
            ref_counts.delete(patch);
            this.__patches.delete(patch.sampler);
        }
    }


    /**
     *
     * @param {Sampler2D} sampler
     * @returns {Reference<AtlasPatch>}
     */
    acquire(sampler) {

        let patch = this.__patches.get(sampler);

        const ref_counts = this.__ref_counts;

        const atlas = this.__atlas;

        if (patch === undefined) {
            patch = atlas.add(sampler);
            ref_counts.set(patch, 1)

            this.__patches.set(sampler, patch);
        } else {
            ref_counts.set(patch, ref_counts.get(patch) + 1);
        }

        const ref = new Reference();
        ref.bind(patch);

        ref.onReleased.add(this.__handle_ref_release, this);

        return ref;
    }
}
