# src/explorer/Models.js

    import {Controller} from "../Controller.js";
    import {XKTLoaderPlugin} from "@xeokit/xeokit-sdk/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js";
    import {math} from "@xeokit/xeokit-sdk/src/viewer/scene/math/math.js";
    import {IFCObjectDefaults} from "../IFCObjectDefaults/IFCObjectDefaults.js";

    const tempVec3 = math.vec3();

    /** @private */
    class Models extends Controller {

        constructor(parent, cfg) {

            super(parent, cfg);

            if (!cfg.modelsTabElement) {
                throw "Missing config: modelsTabElement";
            }

            if (!cfg.unloadModelsButtonElement) {
                throw "Missing config: unloadModelsButtonElement";
            }

            if (!cfg.modelsElement) {
                throw "Missing config: modelsElement";
            }

            this._modelsTabElement = cfg.modelsTabElement;
            this._unloadModelsButtonElement = cfg.unloadModelsButtonElement;
            this._modelsElement = cfg.modelsElement;
            this._modelsTabButtonElement = this._modelsTabElement.querySelector(".xeokit-tab-btn");

            if (!this._modelsTabButtonElement) {
                throw "Missing DOM element: ,xeokit-tab-btn";
            }

            this._xktLoader = new XKTLoaderPlugin(this.viewer, {
                // objectDefaults: IFCObjectDefaults
            });
            this._modelsInfo = {};
            this._numModelsLoaded = 0;
            this._projectId = null;
        }

        _loadProject(projectId, done, error) {
            const params = {};
            this.server.getProject(projectId, (projectInfo) => {
                this._projectId = projectId;
                var html = "";
                const modelsInfo = projectInfo.models || [];
                this._modelsInfo = {};
                for (let i = 0, len = modelsInfo.length; i < len; i++) {
                    const modelInfo = modelsInfo[i];
                    this._modelsInfo[modelInfo.id] = modelInfo;
                    html += "<div class='xeokit-form-check'>";
                    html += "<input id='" + modelInfo.id + "' type='checkbox' value=''>" + modelInfo.name;
                    html += "</div>";
                }
                this._modelsElement.innerHTML = html;
                for (let i = 0, len = modelsInfo.length; i < len; i++) {
                    const modelInfo = modelsInfo[i];
                    const modelId = modelInfo.id;
                    const checkBox = document.getElementById("" + modelId);
                    checkBox.addEventListener("click", () => {
                        if (checkBox.checked) {
                            this._loadModel(modelId);
                        } else {
                            this._unloadModel(modelInfo.id);
                        }
                    });
                    if (modelInfo.default) {
                        checkBox.checked = true;
                        this._loadModel(modelId, done, error); // TODO: buffer and load at end
                    }
                }
            }, (errMsg) => {
                this.error(errMsg);
                if (error) {
                    error(errMsg);
                }
            });
        }

        _loadModel(modelId, done, error) {
            const modelInfo = this._modelsInfo[modelId];
            if (!modelInfo) {
                if (error) {
                    error("Model not in current project");
                }
                return;
            }
            this.viewerUI._controllers.busyModal.show("Loading " + modelInfo.name);
            this.server.getMetadata(this._projectId, modelId,
                (json) => {
                    this.server.getGeometry(this._projectId, modelId,
                        (arraybuffer) => {
                            const model = this._xktLoader.load({
                                id: modelId,
                                metaModelData: json,
                                xkt: arraybuffer,
                                excludeUnclassifiedObjects: true,
                                edges: true,
                                position: modelInfo.position,
                                scale: modelInfo.scale,
                                rotation: modelInfo.rotation,
                                matrix: modelInfo.matrix
                            });
                            model.on("loaded", () => {
                                const scene = this.viewer.scene;
                                const aabb = scene.getAABB(scene.visibleObjectIds);
                                this._numModelsLoaded++;
                                this._unloadModelsButtonElement.classList.remove("disabled");
                                if (this._numModelsLoaded === 1) { // Jump camera when only one model
                                    this.viewer.cameraFlight.jumpTo({
                                        aabb: aabb
                                    });
                                    this.viewer.cameraControl.pivotPos = math.getAABB3Center(aabb, tempVec3);
                                    this.fire("modelLoaded", modelId);
                                    this.viewerUI._controllers.busyModal.hide();
                                    if (done) {
                                        done();
                                    }
                                } else { // Fly camera when multiple models
                                    this.viewer.cameraFlight.flyTo({
                                        aabb: aabb
                                    }, () => {
                                        this.viewer.cameraControl.pivotPos = math.getAABB3Center(aabb, tempVec3);
                                        this.fire("modelLoaded", modelId);
                                        this.viewerUI._controllers.busyModal.hide();
                                        if (done) {
                                            done();
                                        }
                                    });
                                }
                            });
                        },
                        (errMsg) => {
                            this.error(errMsg);
                            this.viewerUI._controllers.busyModal.hide();
                        });
                },
                (errMsg) => {
                    this.error(errMsg);
                    this.viewerUI._controllers.busyModal.hide();
                });
        }

        _unloadModel(modelId) {
            const model = this.viewer.scene.models[modelId];
            if (!model) {
                this.error("Model not loaded: " + modelId);
                return;
            }
            model.destroy();
            const scene = this.viewer.scene;
            const aabb = scene.getAABB(scene.visibleObjectIds);
            document.getElementById("" + modelId).checked = false;
            this._numModelsLoaded--;
            if (this._numModelsLoaded > 0) {
                this._unloadModelsButtonElement.classList.remove("disabled");
            } else {
                this._unloadModelsButtonElement.classList.add("disabled");
            }
            this.viewer.cameraFlight.flyTo({
                aabb: aabb
            }, () => {
                this.viewer.cameraControl.pivotPos = math.getAABB3Center(aabb, tempVec3);
                this.fire("modelUnloaded", modelId);
            });
        }

        _unloadModels() {
            const models = this.viewer.scene.models;
            const modelIds = Object.keys(models);
            for (var i = 0, len = modelIds.length; i < len; i++) {
                const modelId = modelIds[i];
                this._unloadModel(modelId);
            }
        }

        getNumModelsLoaded() {
            return this._numModelsLoaded;
        }

        getModelsInfo() {
            return this._modelsInfo;
        }

        getModelInfo(modelId) {
            return this._modelsInfo[modelId];
        }

        setEnabled(enabled) {
            if (!enabled) {
                this._modelsTabButtonElement.classList.add("disabled");
                this._unloadModelsButtonElement.classList.add("disabled");
            } else {
                this._modelsTabButtonElement.classList.remove("disabled");
                this._unloadModelsButtonElement.classList.remove("disabled");
            }
        }

        /** @private */
        destroy() {
            super.destroy();
            this._xktLoader.destroy();
        }
    }

    export {Models};