import { COORDINATE_SYSTEM, Layer, picking, project32 } from "@deck.gl/core";
import { Geometry, Model } from "@luma.gl/engine";
import { lighting } from "@luma.gl/shadertools";
import { decodeIndexFromRGB, utilities } from "../shader_modules";
import { phongMaterial } from "../shader_modules/phong-lighting/phong-material";
import { precisionForTests } from "../shader_modules/test-precision/precisionForTests";
import { createPropertyData } from "../utils/layerTools";
import { createColormapTexture, } from "../utils/colormapTools";
import linearFragmentShader from "./nodeProperty.fs.glsl";
import linearVertexShader from "./nodeProperty.vs.glsl";
import flatFragmentShader from "./cellProperty.fs.glsl";
import flatVertexShader from "./cellProperty.vs.glsl";
import fsLineShader from "./line.fs.glsl";
import vsLineShader from "./line.vs.glsl";
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
import { isDiscreteProperty, isGeometricProperty, } from "./grid3dLayer";
const defaultProps = {
    colormapName: "",
    colormapClampColor: [200, 200, 200],
    coloringMode: 0,
    coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
    propertyValueRange: [0.0, 1.0],
    depthTest: true,
    ZIncreasingDownwards: true,
    enableLighting: true,
};
// This is a private layer used only by the composite Grid3DLayer
export default class PrivateLayer extends Layer {
    get isLoaded() {
        var _a;
        return (_a = this.state["isLoaded"]) !== null && _a !== void 0 ? _a : false;
    }
    setShaderModuleProps(args) {
        super.setShaderModuleProps(Object.assign(Object.assign({}, args), { lighting: Object.assign(Object.assign({}, args["lighting"]), { enabled: this.props.enableLighting }) }));
    }
    initializeState(context) {
        const [model_mesh, mesh_lines_model] = this._getModels(context);
        this.setState({
            models: [model_mesh, mesh_lines_model],
            isLoaded: false,
        });
    }
    shouldUpdateState({ props, oldProps, context, changeFlags, }) {
        return (super.shouldUpdateState({
            props,
            oldProps,
            context,
            changeFlags,
        }) || changeFlags.propsOrDataChanged);
    }
    updateState({ context }) {
        this.initializeState(context);
    }
    //eslint-disable-next-line
    _getModels(context) {
        var _a, _b;
        const geometricShading = isGeometricProperty(this.props.coloringMode);
        const uniforms = this.getUniforms();
        const colormap = createColormapTexture((_a = this.props.colormapFunction) !== null && _a !== void 0 ? _a : {
            colormapName: this.props.colormapName,
            colorTables: this.context.userData
                .colorTables,
        }, context, this.getColoringHints());
        const mesh_model = new Model(context.device, Object.assign(Object.assign({ id: `${this.props.id}-mesh` }, super.getShaders({
            vs: geometricShading ? linearVertexShader : flatVertexShader,
            fs: geometricShading
                ? linearFragmentShader
                : flatFragmentShader,
            modules: [
                project32,
                picking,
                lighting,
                phongMaterial,
                utilities,
                gridUniforms,
                precisionForTests,
            ],
        })), { geometry: new Geometry({
                topology: (_b = this.props.mesh.drawMode) !== null && _b !== void 0 ? _b : "triangle-list",
                attributes: Object.assign({ positions: this.props.mesh.attributes.positions, normals: this.props.mesh.attributes.normals }, (geometricShading
                    ? {}
                    : {
                        properties: this.props.mesh.attributes.properties,
                    })),
                vertexCount: this.props.mesh.vertexCount,
            }), bufferLayout: this.getAttributeManager().getBufferLayouts(), bindings: {
                colormap,
            }, isInstanced: false }));
        mesh_model.shaderInputs.setProps({
            grid: Object.assign({}, uniforms),
        });
        const mesh_lines_model = new Model(context.device, Object.assign(Object.assign({ id: `${this.props.id}-lines` }, super.getShaders({
            vs: vsLineShader,
            fs: fsLineShader,
            modules: [project32, picking, gridUniforms, precisionForTests],
        })), { geometry: new Geometry(this.props.meshLines), bufferLayout: this.getAttributeManager().getBufferLayouts(), isInstanced: false }));
        mesh_lines_model.shaderInputs.setProps({
            grid: Object.assign({}, uniforms),
        });
        return [mesh_model, mesh_lines_model];
    }
    draw(args) {
        if (!this.state["models"]) {
            return;
        }
        const { context } = args;
        const { gl } = context;
        const [model_mesh, mesh_lines_model] = this.state["models"];
        gl.enable(gl.POLYGON_OFFSET_FILL);
        gl.polygonOffset(1, 1);
        if (!this.props.depthTest) {
            gl.disable(gl.DEPTH_TEST);
        }
        model_mesh.draw(context.renderPass);
        gl.disable(gl.POLYGON_OFFSET_FILL);
        if (this.props.gridLines) {
            mesh_lines_model.draw(context.renderPass);
        }
        if (!this.props.depthTest) {
            gl.enable(gl.DEPTH_TEST);
        }
        if (!this.state["isLoaded"]) {
            this.setState(Object.assign(Object.assign({}, this.state), { isLoaded: true }));
        }
    }
    decodePickingColor() {
        return this.nullPickingColor();
    }
    encodePickingColor() {
        return this.nullPickingColor();
    }
    getPickingInfo({ info }) {
        var _a, _b;
        if (!info.color) {
            return info;
        }
        const layer_properties = [];
        // Note these colors are in the 0-255 range.
        const [r, g, b] = info.color;
        const vertexIndex = decodeIndexFromRGB([r, g, b]);
        const zScale = this.props.modelMatrix ? this.props.modelMatrix[10] : 1;
        if (typeof ((_a = info.coordinate) === null || _a === void 0 ? void 0 : _a[2]) !== "undefined") {
            const depth = (this.props.ZIncreasingDownwards
                ? -info.coordinate[2]
                : info.coordinate[2]) / Math.max(0.001, zScale);
            layer_properties.push(createPropertyData("Depth", depth));
        }
        const properties = (_b = this.props.mesh.attributes.properties) === null || _b === void 0 ? void 0 : _b.value;
        const propertyIndex = properties === null || properties === void 0 ? void 0 : properties[vertexIndex];
        if (propertyIndex != undefined && Number.isFinite(propertyIndex)) {
            const propertyText = this.getPropertyText(propertyIndex);
            if (propertyText) {
                layer_properties.push(createPropertyData("Property", propertyText.text));
                layer_properties.push(createPropertyData("Value", propertyText.value));
            }
            else {
                layer_properties.push(createPropertyData("Property", propertyIndex));
            }
        }
        return Object.assign(Object.assign({}, info), { properties: layer_properties });
    }
    getPropertyText(index) {
        if (!this.props.discretePropertyValueNames) {
            return undefined;
        }
        if (index < 0 ||
            index >= this.props.discretePropertyValueNames.length) {
            return undefined;
        }
        const valueName = this.props.discretePropertyValueNames[index];
        return {
            text: valueName.name,
            value: valueName.value,
        };
    }
    getColoringHints() {
        var _a, _b;
        if (this.props.colormapFunction instanceof Uint8Array) {
            return {
                discreteData: true,
                colormapSize: this.props.colormapFunction.length / 3,
            };
        }
        if (isDiscreteProperty(this.props.coloringMode)) {
            // It is expected that the property values are integers ranging from 0 to N.
            // Thus this.props.propertyValueRange?.[0] should be 0
            // and this.props.propertyValueRange?.[1] should be N
            return {
                discreteData: true,
                colormapSize: ((_b = (_a = this.props.propertyValueRange) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : 0.0) + 1,
            };
        }
        return {
            discreteData: false,
            colormapSize: 256,
        };
    }
    getUniforms() {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        const valueRangeMin = (_b = (_a = this.props.propertyValueRange) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 0.0;
        const valueRangeMax = (_d = (_c = this.props.propertyValueRange) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : 1.0;
        // If specified color map will extend from colormapRangeMin to colormapRangeMax.
        // Otherwise it will extend from valueRangeMin to valueRangeMax.
        const colormapRangeMin = (_f = (_e = this.props.colormapRange) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : valueRangeMin;
        const colormapRangeMax = (_h = (_g = this.props.colormapRange) === null || _g === void 0 ? void 0 : _g[1]) !== null && _h !== void 0 ? _h : valueRangeMax;
        const isColormapClampColorTransparent = this.props.colormapClampColor === false;
        const hasClampColor = this.props.colormapClampColor !== undefined &&
            this.props.colormapClampColor !== true &&
            this.props.colormapClampColor !== false;
        let colormapClampColor = (hasClampColor ? this.props.colormapClampColor : [0, 0, 0, 255]);
        if (isColormapClampColorTransparent) {
            colormapClampColor = [0, 0, 0, 0];
        }
        if (colormapClampColor.length === 3) {
            colormapClampColor = [...colormapClampColor, 255];
        }
        const isClampColor = hasClampColor || isColormapClampColorTransparent;
        // Normalize to [0,1] range.
        const colormapClampColorUniform = colormapClampColor.map((x) => (x !== null && x !== void 0 ? x : 0) / 255);
        if (isColormapClampColorTransparent) {
            colormapClampColor[3] = 0;
        }
        const undefinedPropertyColorUniform = this.props.undefinedPropertyColor.map((x) => (x !== null && x !== void 0 ? x : 0) / 255);
        const coloringHints = this.getColoringHints();
        return {
            ZIncreasingDownwards: this.props.ZIncreasingDownwards,
            valueRangeMin,
            valueRangeMax,
            colormapRangeMin: colormapRangeMin,
            colormapRangeMax: colormapRangeMax,
            colormapClampColor: Array.from(colormapClampColorUniform),
            isClampColor,
            coloringMode: this.props.coloringMode,
            undefinedPropertyColor: undefinedPropertyColorUniform,
            isColoringDiscrete: coloringHints.discreteData,
            colormapSize: coloringHints.colormapSize,
        };
    }
}
PrivateLayer.layerName = "PrivateLayer";
PrivateLayer.defaultProps = defaultProps;
// local shader module for the uniforms
const gridUniformsBlock = /*glsl*/ `\
uniform gridUniforms {
    bool ZIncreasingDownwards;
    float valueRangeMin;
    float valueRangeMax;
    float colormapRangeMin;
    float colormapRangeMax;
    vec4 colormapClampColor;
    bool isClampColor;
    float coloringMode;
    vec3 undefinedPropertyColor;
    bool isColoringDiscrete;
    float colormapSize;
} grid;
`;
const gridUniforms = {
    name: "grid",
    vs: gridUniformsBlock,
    fs: gridUniformsBlock,
    uniformTypes: {
        ZIncreasingDownwards: "u32",
        valueRangeMin: "f32",
        valueRangeMax: "f32",
        colormapRangeMin: "f32",
        colormapRangeMax: "f32",
        colormapClampColor: "vec4<f32>",
        isClampColor: "u32",
        coloringMode: "f32",
        undefinedPropertyColor: "vec3<f32>",
        isColoringDiscrete: "u32",
        colormapSize: "f32",
    },
};
//# sourceMappingURL=privateGrid3dLayer.js.map