import { System } from '../../../../ecs/System.js';
import Mesh, { MeshFlags } from '../../mesh/Mesh.js';
import Highlight from '../Highlight.js';
import { HighlightRenderElementSource } from "../plugin/HighlightRenderElementSource.js";
import { OutlineRenderPlugin } from "../plugin/OutlineRenderPlugin.js";
import { HighlightRenderElement } from "../renderer/HighlightRenderElement.js";
import { HighlightRenderGroup } from "../renderer/HighlightRenderGroup.js";

class Supplier extends HighlightRenderElementSource {
    /**
     *
     * @param {MeshHighlightSystem} system
     */
    constructor(system) {
        super();

        this.__system = system;

        /**
         *
         * @type {ObjectPoolFactory<HighlightRenderElement>}
         * @private
         */
        this.__pool = null;
        /**
         *
         * @type {HighlightRenderGroup}
         * @private
         */
        this.__group = null;
    }

    collect(pool, group) {

        this.__pool = pool;
        this.__group = group;

        const system = this.__system;

        /**
         *
         * @type {EntityManager}
         */
        const em = system.entityManager;

        const dataset = em.dataset;

        if (dataset === null) {
            return;
        }

        dataset.traverseEntities([Highlight, Mesh], this.__visitHighlightMeshPreRender, this);
    }

    /**
     *
     * @param {Highlight} highlight
     * @param {Mesh} model
     * @param {number} entity
     * @private
     */
    __visitHighlightMeshPreRender(highlight, model, entity) {
        if (!model.hasMesh()) {
            return;
        }

        if (!model.getFlag(MeshFlags.InView)) {
            return;
        }

        const elements = highlight.elements;

        if (elements.isEmpty()) {
            // no elements
            return;
        }

        const renderElement = this.__pool.create();

        renderElement.definitions = elements.asArray();
        renderElement.object = model.mesh;

        this.__group.elements.add(renderElement);
    }
}

class MeshHighlightSystem extends System {
    /**
     *
     * @param {Engine} engine
     * @constructor
     */
    constructor(engine) {
        super();

        /**
         *
         * @type {Engine}
         * @private
         */
        this.__engine = engine;

        this.dependencies = [Highlight, Mesh];

        this.__element_source = new Supplier(this);

        /**
         *
         * @type {Reference<OutlineRenderPlugin>}
         * @private
         */
        this.__plugin_renderer_ref = null;


    }

    /**
     *
     * @param {EntityManager} entityManager
     */
    async shutdown(entityManager) {

        if (this.__plugin_renderer_ref !== null) {

            this.__plugin_renderer_ref.getValue().removeSource(this.__element_source);

            this.__plugin_renderer_ref.release();

            this.__plugin_renderer_ref = null;
        }
    }

    /**
     *
     * @param {EntityManager} entityManager
     */
    async startup(entityManager) {
        /**
         *
         * @type {EntityManager}
         */
        this.entityManager = entityManager;

        const engine = this.__engine;

        const ref = await engine.plugins.acquire(OutlineRenderPlugin)

        this.__plugin_renderer_ref = ref;

        /**
         *
         * @type {OutlineRenderPlugin}
         */
        const plugin = ref.getValue();

        plugin.addSource(this.__element_source);

    }
}


export default MeshHighlightSystem;
