import List from "../../../../core/collection/list/List.js";
import { CameraView } from "./CameraView.js";
import { CameraViewFlags } from "./CameraViewFlags.js";
import { VisibilityComputer } from "../visibility/VisibilityComputer.js";
import Signal from "../../../../core/events/signal/Signal.js";

export class CameraViewManager {
    constructor() {
        /**
         *
         * @type {List<CameraView>}
         * @private
         */
        this.__data = new List();

        /**
         *
         * @type {VisibilityComputer}
         * @private
         */
        this.__visibility_computer = new VisibilityComputer();

        this.on = {
            preViewBuild: new Signal(),
            postViewBuild: new Signal()
        };
    }

    /**
     *
     * @return {List<CameraView>}
     */
    get elements() {
        return this.__data;
    }

    /**
     *
     * @return {CameraView}
     */
    create() {
        const r = new CameraView();

        this.__data.add(r);

        return r;
    }

    /**
     *
     * @param {CameraView} v
     * @return {boolean}
     */
    add(v) {
        if (this.__data.contains(v)) {
            return false;
        }

        this.__data.add(v);

        return true;
    }

    /**
     *
     * @param {CameraView} v
     * @return {boolean}
     */
    remove(v) {
        return this.__data.removeOneOf(v);
    }

    /**
     *
     * @param {RenderLayerManager} layers
     */
    build_visibility(layers) {
        // initialize visibility for each layer
        layers.traverse(l => {
            if (l.managed) {
                return;
            }

            l.visibleSet.initializeUpdate();
        });

        const data = this.__data;
        const n = data.length;

        for (let i = 0; i < n; i++) {
            const view = data.get(i);

            if (!view.getFlag(CameraViewFlags.Active)) {
                // view inactive, skip

                view.visible_objects.clear();

                continue;
            }

            this.on.preViewBuild.send1(view);

            view.build_visibility(layers, this.__visibility_computer);

            this.on.postViewBuild.send1(view);
        }

        layers.traverse(l => {
            if (l.managed) {
                return;
            }

            l.visibleSet.finalizeUpdate();
        });
    }
}
