import { layersDefaultProps } from "../layersDefaultProps";
import { rgbValues } from "@emerson-eps/color-tables/";
import { Layer } from "@deck.gl/core";
import GL from "@luma.gl/constants";
import { Model, Geometry } from "@luma.gl/core";
import { picking, project, phongLighting } from "deck.gl";
import fragmentShader from "./fragment.glsl";
import vertexShader from "./vertex.glsl";
import fragmentShaderLines from "./fragment_lines.glsl";
import vertexShaderLines from "./vertex_lines.glsl";
function getColorMapColors(colorMapName, colorTables) {
    const colors = [];
    for (let i = 0; i < 256; i++) {
        const value = i / 255.0;
        const rgb = rgbValues(value, colorMapName, colorTables);
        let color = [0, 0, 0];
        if (rgb != undefined) {
            if (Array.isArray(rgb)) {
                color = [rgb[0], rgb[1], rgb[2]];
            }
            else {
                color = [rgb.r, rgb.g, rgb.b];
            }
        }
        colors.push(color);
    }
    return colors;
}
export default class GridLayer extends Layer {
    initializeState(context) {
        const { gl } = context;
        const updateTimeStep = () => {
            const a_context = { context };
            this.updateState(a_context); // LayerProps, LayerContext
        };
        // set intial state.
        this.setState(Object.assign(Object.assign({}, this._getModels(gl, 0)), { ti: 0 }));
        // For now just cycle over the timesteps.
        setInterval(updateTimeStep, 500);
    }
    shouldUpdateState({ props, oldProps, context, changeFlags, }) {
        return (super.shouldUpdateState({
            props,
            oldProps,
            context,
            changeFlags,
        }) || changeFlags.propsOrDataChanged);
    }
    updateState({ context }) {
        var _a, _b;
        const { gl } = context;
        // Wrap around timestep if necessary.
        const data = this.props.data;
        const do_reset_ti = this.state.ti >= ((_b = (_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.vs.length) !== null && _b !== void 0 ? _b : 1) - 1;
        const timeStep = do_reset_ti ? 0 : this.state.ti + 1;
        this.setState(Object.assign(Object.assign({}, this._getModels(gl, timeStep)), { ti: timeStep }));
    }
    //eslint-disable-next-line
    _getModels(gl, timeStep) {
        const colors = getColorMapColors(this.props.colorMapName, this.context.userData.colorTables);
        const data = this.props.data;
        if (!data || data.length === 0) {
            return [];
        }
        const [triangle_vertexs, triangle_colors, cell_lines, cell_index] = makeVertexesAndColorArrays(data, timeStep, colors, this.props.valueRange, this.props.colorMapRange);
        if (triangle_vertexs.length === 0) {
            return [];
        }
        // CELL TRIANGLE MODEL.
        const triangles_model = new Model(gl, {
            id: `${this.props.id}-triangles`,
            vs: vertexShader,
            fs: fragmentShader,
            geometry: new Geometry({
                drawMode: GL.TRIANGLES,
                attributes: {
                    positions: new Float32Array(triangle_vertexs),
                    color: {
                        size: 3,
                        value: new Float32Array(triangle_colors),
                    },
                    cell_index: {
                        size: 1,
                        integer: true,
                        type: GL.INT,
                        value: new Int32Array(cell_index),
                    },
                },
                vertexCount: triangle_vertexs.length / 3,
            }),
            modules: [project, picking, phongLighting],
            isInstanced: false, // This only works when set to false.
        });
        // CELL LINE MODEL.
        const triangle_lines_model = new Model(gl, {
            id: `${this.props.id}-triangle_lines`,
            vs: vertexShaderLines,
            fs: fragmentShaderLines,
            geometry: new Geometry({
                drawMode: GL.LINES,
                attributes: {
                    positions: {
                        size: 3,
                        value: new Float32Array(cell_lines),
                    },
                },
                vertexCount: cell_lines.length / 3,
            }),
            modules: [project, picking],
            isInstanced: false, // This only works when set to false.
        });
        return {
            models: [triangles_model, triangle_lines_model],
        };
    }
    // Signature from the base class, eslint doesn't like the any type.
    // eslint-disable-next-line
    draw({ context }) {
        const { gl } = context;
        if (this.state.models) {
            gl.enable(gl.POLYGON_OFFSET_FILL);
            gl.polygonOffset(1, 1);
            this.state.models[0].draw(); // triangles
            gl.disable(gl.POLYGON_OFFSET_FILL);
            this.state.models[1].draw(); // triangle lines
        }
    }
    // KEEP
    // decodePickingColor(): number {
    //     return 0;
    // }
    decodePickingColor() {
        return this.nullPickingColor();
    }
    encodePickingColor() {
        return this.nullPickingColor();
    }
    // For now, use `any` for the picking types.
    //eslint-disable-next-line
    getPickingInfo({ info }) {
        if (!info.color) {
            return info;
        }
        // Note these colors are in the  0-255 range.
        const r = info.color[0];
        const g = info.color[1];
        const b = info.color[2];
        if (r === 255) {
            // We are picking a line between cells.
            return info;
        }
        const index = 256 * 256 * r + 256 * g + b; // index into data array.
        const data = this.props.data;
        if (!data || data.length === 0) {
            return info;
        }
        const colors = getColorMapColors(this.props.colorMapName, this.context.userData.colorTables);
        const timeStep = this.state.ti;
        const cell = data[index];
        const propertyValue = cell.vs[timeStep];
        const color = getColor(propertyValue, colors, this.props.valueRange, this.props.colorMapRange);
        return Object.assign(Object.assign({}, info), { properties: [
                { name: "i", value: cell.i },
                { name: "j", value: cell.j },
                { name: "depth:", value: cell.z },
                { name: "value:", value: propertyValue, color },
            ] });
    }
}
GridLayer.layerName = "GridLayer";
GridLayer.defaultProps = layersDefaultProps["GridLayer"];
//================= Local help functions. ==================
function getColor(propertyValue, colors, valueRange, colorMapRange) {
    var _a, _b, _c, _d;
    const valueRangeMin = (_a = valueRange[0]) !== null && _a !== void 0 ? _a : 0.0;
    const valueRangeMax = (_b = valueRange[1]) !== null && _b !== void 0 ? _b : 1.0;
    // If specified, color map will extend from colorMapRangeMin to colorMapRangeMax.
    // Otherwise it will extend from valueRangeMin to valueRangeMax.
    const colorMapRangeMin = (_c = colorMapRange === null || colorMapRange === void 0 ? void 0 : colorMapRange[0]) !== null && _c !== void 0 ? _c : valueRangeMin;
    const colorMapRangeMax = (_d = colorMapRange === null || colorMapRange === void 0 ? void 0 : colorMapRange[1]) !== null && _d !== void 0 ? _d : valueRangeMax;
    let x = propertyValue * (valueRangeMax - valueRangeMin) + valueRangeMin;
    x = (x - colorMapRangeMin) / (colorMapRangeMax - colorMapRangeMin);
    x = Math.max(0.0, x);
    x = Math.min(1.0, x);
    const color = colors[Math.floor(x * 255.0)];
    return color;
}
function makeVertexesAndColorArrays(data, ti, colors, valueRange, colorMapRange) {
    const triangle_vertexs = [];
    const triangle_colors = [];
    const cell_lines = [];
    const cell_index = [];
    for (let i = 0; i < data.length; i++) {
        const cell = data[i];
        const propertyValue = cell.vs[ti];
        let color = getColor(propertyValue, colors, valueRange, colorMapRange);
        // Normalize color.
        color = [color[0] / 255.0, color[1] / 255.0, color[2] / 255.0];
        // Note. Equal color for all of a triangle vertxes gives constant color in
        //       a cell which is correct for this layer.
        // Triangle 1.
        triangle_vertexs.push(...cell.cs[0], ...cell.cs[1], ...cell.cs[2]);
        triangle_colors.push(color[0], color[1], color[2]);
        triangle_colors.push(color[0], color[1], color[2]);
        triangle_colors.push(color[0], color[1], color[2]);
        // Cell index. One for each triangle vertex.
        for (let j = 0; j < 3; j++) {
            //cell_index.push(2 * i);
            cell_index.push(i);
        }
        // Triangle 2.
        triangle_vertexs.push(...cell.cs[0], ...cell.cs[2], ...cell.cs[3]);
        triangle_colors.push(color[0], color[1], color[2]);
        triangle_colors.push(color[0], color[1], color[2]);
        triangle_colors.push(color[0], color[1], color[2]);
        // Cell index.
        for (let j = 0; j < 3; j++) {
            // one for each triangle vertex.
            //cell_index.push(2 * i + 1);
            cell_index.push(i);
        }
        // Cell lines.
        cell_lines.push(...cell.cs[0], ...cell.cs[1]);
        cell_lines.push(...cell.cs[1], ...cell.cs[2]);
        cell_lines.push(...cell.cs[2], ...cell.cs[3]);
        cell_lines.push(...cell.cs[3], ...cell.cs[0]);
    }
    return [triangle_vertexs, triangle_colors, cell_lines, cell_index];
}
//# sourceMappingURL=gridLayer.js.map