import { CompositeLayer } from "@deck.gl/core";
import { DataFilterExtension, PathStyleExtension } from "@deck.gl/extensions";
import { PathLayer } from "@deck.gl/layers";
import { SectionViewport } from "../../viewports";
import { createPropertyData } from "../utils/layerTools";
import _ from "lodash";
const DEFAULT_GROUP_STYLE = {
    color: [0, 128, 255, 255],
    width: 2,
    dashArray: [0, 0],
};
// ---------------------------------------------------------------------------
// Default props
// ---------------------------------------------------------------------------
const defaultProps = {
    "@@type": "PolylineGroupLayer",
    name: "PolylineGroupLayer",
    id: "polyline-group-layer",
    pickable: false,
    visible: true,
    depthTest: true,
    ZIncreasingDownwards: true,
    defaultGroupStyle: DEFAULT_GROUP_STYLE,
    widthUnits: "meters",
    widthScale: 1,
    widthMinPixels: 0,
    widthMaxPixels: Number.MAX_SAFE_INTEGER,
    jointRounded: false,
    capRounded: false,
    miterLimit: 4,
    billboard: true,
    getGroupPolylines: (g) => g.polylines,
    getPolylinePath: (p) => p.path,
};
// ---------------------------------------------------------------------------
// Resolution helpers
// ---------------------------------------------------------------------------
function resolveColor(polyline, group, props) {
    var _a, _b, _c, _d;
    const fromPolylineAccessor = (_a = props.getPolylineColor) === null || _a === void 0 ? void 0 : _a.call(props, polyline, group);
    if (fromPolylineAccessor != null)
        return fromPolylineAccessor;
    if (polyline.color != null)
        return polyline.color;
    const fromGroupAccessor = (_b = props.getGroupColor) === null || _b === void 0 ? void 0 : _b.call(props, group);
    if (fromGroupAccessor != null)
        return fromGroupAccessor;
    if (group.color != null)
        return group.color;
    return (_d = (_c = props.defaultGroupStyle) === null || _c === void 0 ? void 0 : _c.color) !== null && _d !== void 0 ? _d : DEFAULT_GROUP_STYLE.color;
}
function resolveWidth(polyline, group, props) {
    var _a, _b, _c, _d;
    const fromPolylineAccessor = (_a = props.getPolylineWidth) === null || _a === void 0 ? void 0 : _a.call(props, polyline, group);
    if (fromPolylineAccessor != null)
        return fromPolylineAccessor;
    if (polyline.width != null)
        return polyline.width;
    const fromGroupAccessor = (_b = props.getGroupWidth) === null || _b === void 0 ? void 0 : _b.call(props, group);
    if (fromGroupAccessor != null)
        return fromGroupAccessor;
    if (group.width != null)
        return group.width;
    return (_d = (_c = props.defaultGroupStyle) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : DEFAULT_GROUP_STYLE.width;
}
// ---------------------------------------------------------------------------
// Flatten
// ---------------------------------------------------------------------------
function isBinaryPolylines(p) {
    return !Array.isArray(p) && "positions" in p;
}
function resolveDashArray(polyline, group, props) {
    var _a, _b, _c, _d;
    const fromPolylineAccessor = (_a = props.getPolylineDashArray) === null || _a === void 0 ? void 0 : _a.call(props, polyline, group);
    if (fromPolylineAccessor != null)
        return fromPolylineAccessor;
    if (polyline.dashArray != null)
        return polyline.dashArray;
    const fromGroupAccessor = (_b = props.getGroupDashArray) === null || _b === void 0 ? void 0 : _b.call(props, group);
    if (fromGroupAccessor != null)
        return fromGroupAccessor;
    if (group.dashArray != null)
        return group.dashArray;
    return (_d = (_c = props.defaultGroupStyle) === null || _c === void 0 ? void 0 : _c.dashArray) !== null && _d !== void 0 ? _d : DEFAULT_GROUP_STYLE.dashArray;
}
// ---------------------------------------------------------------------------
// Segment resolution helpers (used when polyline.path is a PolylineGroup)
// ---------------------------------------------------------------------------
// Cascade: accessor(segment) -> segment field -> subGroup field -> parent polyline
// resolution (which itself cascades through accessor -> field -> outerGroup -> default).
function resolveSegmentColor(segment, subGroup, parentPolyline, outerGroup, props) {
    var _a;
    const fromAccessor = (_a = props.getPolylineColor) === null || _a === void 0 ? void 0 : _a.call(props, segment, outerGroup);
    if (fromAccessor != null)
        return fromAccessor;
    if (segment.color != null)
        return segment.color;
    if (subGroup.color != null)
        return subGroup.color;
    return resolveColor(parentPolyline, outerGroup, props);
}
function resolveSegmentWidth(segment, subGroup, parentPolyline, outerGroup, props) {
    var _a;
    const fromAccessor = (_a = props.getPolylineWidth) === null || _a === void 0 ? void 0 : _a.call(props, segment, outerGroup);
    if (fromAccessor != null)
        return fromAccessor;
    if (segment.width != null)
        return segment.width;
    if (subGroup.width != null)
        return subGroup.width;
    return resolveWidth(parentPolyline, outerGroup, props);
}
function resolveSegmentDashArray(segment, subGroup, parentPolyline, outerGroup, props) {
    var _a;
    const fromAccessor = (_a = props.getPolylineDashArray) === null || _a === void 0 ? void 0 : _a.call(props, segment, outerGroup);
    if (fromAccessor != null)
        return fromAccessor;
    if (segment.dashArray != null)
        return segment.dashArray;
    if (subGroup.dashArray != null)
        return subGroup.dashArray;
    return resolveDashArray(parentPolyline, outerGroup, props);
}
/**
 * Expands a polyline whose `path` is a {@link PolylineGroup} (i.e. a
 * discontinuous polyline made of disjoint segments) into one {@link FlatEntry}
 * per segment. Returns an empty array and emits a warning if the sub-group
 * contains {@link BinaryPolylines}, which are not supported at the segment level.
 */
function flattenSubGroupPolyline(polyline, subGroup, group, getPath, props) {
    const segPolylines = subGroup.polylines;
    if (isBinaryPolylines(segPolylines)) {
        console.warn("PolylineGroupLayer: BinaryPolylines inside a sub-group path is not supported. Skipping.");
        return [];
    }
    return segPolylines.flatMap((segment) => {
        if (!Array.isArray(segment.path)) {
            console.warn("PolylineGroupLayer: nested PolylineGroup paths inside segment polylines are not supported. Skipping segment.");
            return [];
        }
        return [
            {
                path: getPath(segment, group),
                color: resolveSegmentColor(segment, subGroup, polyline, group, props),
                width: resolveSegmentWidth(segment, subGroup, polyline, group, props),
                dashArray: resolveSegmentDashArray(segment, subGroup, polyline, group, props),
                _polyline: polyline, // root polyline — for picking & hiddenPolylines
                _group: group,
            },
        ];
    });
}
/**
 * Allocates combined typed-array buffers and fills them from all raw binary
 * groups. Positions and indices are concatenated; color/width are replicated
 * per vertex so the GPU can read them without per-vertex JS work.
 *
 * @remarks * `polylines` is a sanitized copy of group.polylines with invalid
 * colors/widths buffers stripped out; do not read from group.polylines directly.
 */
function buildBinaryData(binaryRaw, totalVerts, totalPaths, ZIncreasingDownwards, props) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
    const positions = new Float32Array(totalVerts * 3);
    const colors = new Uint8Array(totalVerts * 4);
    const widths = new Float32Array(totalVerts);
    const vertexGroupIndex = new Uint32Array(totalVerts);
    const startIndices = new Uint32Array(totalPaths + 1);
    const pathGroup = new Array(totalPaths);
    const groups = binaryRaw.map((b) => b.group);
    let vOffset = 0;
    let pOffset = 0;
    for (let gIdx = 0; gIdx < binaryRaw.length; gIdx++) {
        const { group, polylines } = binaryRaw[gIdx];
        const src = polylines.positions;
        // Ensure positions buffer length is a multiple of 3; if not, ignore
        // trailing vertices.
        if (src.length % 3 !== 0) {
            console.warn(`PolylineGroupLayer: BinaryPolylines group (id=` +
                `${(_a = group.id) !== null && _a !== void 0 ? _a : "unknown"}) has a positions buffer whose` +
                `length (${src.length}) is not a multiple of 3. Trailing ` +
                `incomplete vertex will be ignored.`);
        }
        const srcVerts = Math.floor(src.length / 3);
        // Copy positions (optionally flipping Z)
        const base = vOffset * 3;
        const srcLen = srcVerts * 3;
        if (ZIncreasingDownwards) {
            for (let i = 0; i < srcLen; i += 3) {
                positions[base + i] = src[i];
                positions[base + i + 1] = src[i + 1];
                positions[base + i + 2] = -src[i + 2];
            }
        }
        else {
            // Slice to srcLen to exclude any trailing incomplete vertex.
            positions.set(srcLen < src.length ? src.subarray(0, srcLen) : src, base);
        }
        if (polylines.colors) {
            colors.set(polylines.colors, vOffset * 4);
        }
        else {
            const color = (_f = (_d = (_c = (_b = props.getGroupColor) === null || _b === void 0 ? void 0 : _b.call(props, group)) !== null && _c !== void 0 ? _c : group.color) !== null && _d !== void 0 ? _d : (_e = props.defaultGroupStyle) === null || _e === void 0 ? void 0 : _e.color) !== null && _f !== void 0 ? _f : [0, 128, 255, 255];
            // Flood-fill the group color across all vertices efficiently:
            // 1. Write the first RGBA (4 × Uint8) into the combined Uint8Array
            //    at byte offset vOffset*4.
            // 2. Reinterpret the same ArrayBuffer as Uint32 (1 element = 4 bytes
            //    = one RGBA pixel). Index vOffset in the Uint32 view therefore
            //    aliases the four bytes we just wrote.
            // 3. Use TypedArray.fill to copy that single 32-bit value into every
            //    remaining vertex slot in one call — no per-channel bit-shifting.
            colors.set([color[0], color[1], color[2], (_g = color[3]) !== null && _g !== void 0 ? _g : 255], vOffset * 4);
            new Uint32Array(colors.buffer).fill(new Uint32Array(colors.buffer)[vOffset], vOffset + 1, vOffset + srcVerts);
        }
        if (polylines.widths) {
            widths.set(polylines.widths, vOffset);
        }
        else {
            widths.fill((_m = (_k = (_j = (_h = props.getGroupWidth) === null || _h === void 0 ? void 0 : _h.call(props, group)) !== null && _j !== void 0 ? _j : group.width) !== null && _k !== void 0 ? _k : (_l = props.defaultGroupStyle) === null || _l === void 0 ? void 0 : _l.width) !== null && _m !== void 0 ? _m : 2, vOffset, vOffset + srcVerts);
        }
        for (let v = 0; v < srcVerts; v++) {
            vertexGroupIndex[vOffset + v] = gIdx;
        }
        // Offset and copy startIndices into the combined buffer.
        const srcIdx = polylines.startIndices;
        for (let p = 0; p < srcIdx.length; p++) {
            startIndices[pOffset + p] = srcIdx[p] + vOffset;
            pathGroup[pOffset + p] = group;
        }
        vOffset += srcVerts;
        pOffset += srcIdx.length;
    }
    startIndices[totalPaths] = totalVerts; // terminal entry
    return {
        positions,
        startIndices,
        colors,
        widths,
        pathGroup,
        vertexGroupIndex,
        groups,
    };
}
/**
 * Builds the per-vertex GPU filter buffer for the binary sub-layer.
 * Each vertex gets 1.0 if its group is visible, 0.0 if it is hidden.
 * This is a plain typed-array allocation (O(vertices)); separated so it can
 * be re-run cheaply when only `hiddenGroups` changes, without rebuilding the
 * full `BinaryData`.
 */
function buildFilterValues(binaryData, hiddenGroups) {
    const filterValues = new Float32Array(binaryData.vertexGroupIndex.length);
    for (let i = 0; i < filterValues.length; i++) {
        const g = binaryData.groups[binaryData.vertexGroupIndex[i]];
        filterValues[i] = g.id != null && (hiddenGroups === null || hiddenGroups === void 0 ? void 0 : hiddenGroups.has(g.id)) ? 0 : 1;
    }
    return filterValues;
}
/**
 * Assembles the `data` object passed to the binary PathLayer sub-layer.
 * Thin wrapper around the cached typed arrays; cheap to call, but creating a
 * new object reference signals deck.gl to re-examine attribute buffers.
 */
function buildBinaryLayerData(binaryData, filterValues) {
    return {
        length: binaryData.startIndices.length - 1,
        startIndices: binaryData.startIndices,
        attributes: {
            getPath: { value: binaryData.positions, size: 3 },
            getFilterValue: { value: filterValues, size: 1 },
            getColor: { value: binaryData.colors, size: 4, normalized: true },
            getWidth: { value: binaryData.widths, size: 1 },
        },
    };
}
function flattenGroupData(data, props) {
    var _a, _b, _c, _d, _e, _f, _g;
    const getPolylines = (_a = props.getGroupPolylines) !== null && _a !== void 0 ? _a : ((g) => g.polylines);
    const getPath = (_b = props.getPolylinePath) !== null && _b !== void 0 ? _b : ((p) => p.path);
    const flatData = [];
    const ZIncreasingDownwards = (_c = props.ZIncreasingDownwards) !== null && _c !== void 0 ? _c : true;
    // First pass over binary groups: collect groups + sum sizes so we can
    // allocate combined typed arrays once.
    const binaryRaw = [];
    let totalVerts = 0;
    let totalPaths = 0;
    for (const group of data) {
        const polylines = getPolylines(group);
        if (isBinaryPolylines(polylines)) {
            if (group.dashArray != null ||
                ((_d = props.getGroupDashArray) === null || _d === void 0 ? void 0 : _d.call(props, group)) != null) {
                console.warn("PolylineGroupLayer: dashArray is not supported on BinaryPolylines groups; ignoring.");
            }
            if (polylines.positions.length % 3 !== 0) {
                console.warn(`PolylineGroupLayer: BinaryPolylines group (id=${(_e = group.id) !== null && _e !== void 0 ? _e : "unknown"}) has a positions buffer whose length (${polylines.positions.length}) is not a multiple of 3. Trailing incomplete vertex will be ignored.`);
            }
            const srcVerts = Math.floor(polylines.positions.length / 3);
            let colors = polylines.colors;
            if (colors && colors.length !== srcVerts * 4) {
                console.warn(`PolylineGroupLayer: BinaryPolylines group (id=${(_f = group.id) !== null && _f !== void 0 ? _f : "unknown"}) has a colors buffer with wrong length (expected ${srcVerts * 4}, got ${colors.length}). Ignoring colors.`);
                colors = undefined;
            }
            let widths = polylines.widths;
            if (widths && widths.length !== srcVerts) {
                console.warn(`PolylineGroupLayer: BinaryPolylines group (id=${(_g = group.id) !== null && _g !== void 0 ? _g : "unknown"}) has a widths buffer with wrong length (expected ${srcVerts}, got ${widths.length}). Ignoring widths.`);
                widths = undefined;
            }
            binaryRaw.push({
                group,
                polylines: Object.assign(Object.assign({}, polylines), { colors, widths }),
            });
            totalVerts += srcVerts;
            totalPaths += polylines.startIndices.length;
        }
        else {
            for (const polyline of polylines) {
                if (!Array.isArray(polyline.path)) {
                    flatData.push(...flattenSubGroupPolyline(polyline, polyline.path, group, getPath, props));
                }
                else {
                    flatData.push({
                        path: getPath(polyline, group),
                        color: resolveColor(polyline, group, props),
                        width: resolveWidth(polyline, group, props),
                        dashArray: resolveDashArray(polyline, group, props),
                        _polyline: polyline,
                        _group: group,
                    });
                }
            }
        }
    }
    if (binaryRaw.length === 0) {
        return { flatData, binaryData: null };
    }
    return {
        flatData,
        binaryData: buildBinaryData(binaryRaw, totalVerts, totalPaths, ZIncreasingDownwards, props),
    };
}
function buildSectionIndex(path) {
    const cumDist = [0];
    for (let i = 1; i < path.length; i++) {
        const dx = path[i][0] - path[i - 1][0];
        const dy = path[i][1] - path[i - 1][1];
        cumDist.push(cumDist[i - 1] + Math.sqrt(dx * dx + dy * dy));
    }
    return { cumDist, path };
}
/** Return the (x, y) world position on the fence at the given cumulative distance. */
function projectAbscissa(abscissa, idx) {
    const { cumDist, path } = idx;
    if (path.length === 0)
        return [0, 0];
    if (abscissa <= cumDist[0])
        return [path[0][0], path[0][1]];
    const last = cumDist.length - 1;
    if (abscissa >= cumDist[last])
        return [path[last][0], path[last][1]];
    let lo = 0, hi = last;
    while (hi - lo > 1) {
        const mid = (lo + hi) >> 1;
        if (cumDist[mid] <= abscissa)
            lo = mid;
        else
            hi = mid;
    }
    const t = (abscissa - cumDist[lo]) / (cumDist[hi] - cumDist[lo]);
    return [
        path[lo][0] + t * (path[hi][0] - path[lo][0]),
        path[lo][1] + t * (path[hi][1] - path[lo][1]),
    ];
}
// ---------------------------------------------------------------------------
// Layer class
// ---------------------------------------------------------------------------
/**
 * A deck.gl {@link CompositeLayer} that renders collections of polylines
 * organised into named groups.
 *
 * **Data formats**
 *
 * Each {@link PolylineGroup} holds one or more polylines. Two formats are
 * supported for `PolylineGroup.polylines`:
 * - `Polyline[]` — per-object format; supports `id`, and per-polyline `color`,
 *   `width`, and `dashArray` overrides.
 * - {@link BinaryPolylines} — flat typed-array format; more efficient for
 *   large datasets loaded from binary sources. Group-level styling only.
 *
 * **Discontinuous polylines**
 *
 * A `Polyline.path` may be a nested {@link PolylineGroup}, making one logical
 * polyline consist of disjoint segments (e.g. a seismic horizon cut by faults).
 * All segments share the root `Polyline.id` for picking and visibility filtering.
 *
 * **Styling cascade**
 *
 * Color, width, and dash pattern are resolved per-path in this order:
 * polyline accessor → `Polyline` field → group accessor → `PolylineGroup` field
 * → layer default prop.
 *
 * **Section-view projection**
 *
 * When {@link PolylineGroupLayerProps.sectionPath} is provided, path coordinates
 * are interpreted as `[abscissa, depth]`. The layer renders two sub-layers:
 * one in abscissa/depth space for {@link SectionViewport}s, and one with
 * abscissa values projected back to world XY for 3-D viewports.
 *
 * **GPU-side visibility**
 *
 * {@link PolylineGroupLayerProps.hiddenGroups} and
 * {@link PolylineGroupLayerProps.hiddenPolylines} use `DataFilterExtension`.
 * Changing these sets triggers only a GPU attribute update; the flattened
 * data buffer is never rebuilt.
 */
export class PolylineGroupLayer extends CompositeLayer {
    /** @override Builds the initial flat data buffer and section index from `props.data`. */
    initializeState() {
        const { data, sectionPath, hiddenGroups } = this.props;
        const { flatData, binaryData } = flattenGroupData(data, this.props);
        const binaryLayerData = binaryData
            ? buildBinaryLayerData(binaryData, buildFilterValues(binaryData, hiddenGroups))
            : null;
        this.setState({
            flatData,
            binaryData,
            binaryLayerData,
            sectionIndex: sectionPath ? buildSectionIndex(sectionPath) : null,
        });
    }
    /**
     * @override
     * Rebuilds the flat data buffer when `data` or any accessor/default prop changes.
     * Rebuilds the section index when `sectionPath` changes.
     */
    updateState({ props, oldProps, }) {
        const needsRebuild = props.data !== oldProps.data ||
            props.getGroupColor !== oldProps.getGroupColor ||
            props.getGroupWidth !== oldProps.getGroupWidth ||
            props.getGroupDashArray !== oldProps.getGroupDashArray ||
            props.getPolylineColor !== oldProps.getPolylineColor ||
            props.getPolylineWidth !== oldProps.getPolylineWidth ||
            props.getPolylineDashArray !== oldProps.getPolylineDashArray ||
            props.getGroupPolylines !== oldProps.getGroupPolylines ||
            props.getPolylinePath !== oldProps.getPolylinePath ||
            !_.isEqual(props.defaultGroupStyle, oldProps.defaultGroupStyle) ||
            props.ZIncreasingDownwards !== oldProps.ZIncreasingDownwards;
        if (needsRebuild) {
            const { flatData, binaryData } = flattenGroupData(props.data, props);
            const binaryLayerData = binaryData
                ? buildBinaryLayerData(binaryData, buildFilterValues(binaryData, props.hiddenGroups))
                : null;
            this.setState({ flatData, binaryData, binaryLayerData });
        }
        else if (props.hiddenGroups !== oldProps.hiddenGroups) {
            // Only the per-vertex filter buffer needs rebuilding; the large
            // position/color/width buffers are untouched.
            const binaryData = this.state["binaryData"];
            if (binaryData) {
                this.setState({
                    binaryLayerData: buildBinaryLayerData(binaryData, buildFilterValues(binaryData, props.hiddenGroups)),
                });
            }
        }
        if (props.sectionPath !== oldProps.sectionPath) {
            this.setState({
                sectionIndex: props.sectionPath
                    ? buildSectionIndex(props.sectionPath)
                    : null,
            });
        }
    }
    /**
     * @override
     * Routes the `paths-section` sub-layer to {@link SectionViewport}s and
     * the `paths-3d` sub-layer to all other viewports.
     * Only active when `sectionPath` is set; otherwise the single `paths` sub-layer
     * is always visible.
     */
    filterSubLayer({ layer, viewport }) {
        const isSV = viewport.constructor === SectionViewport;
        if (layer.id.endsWith("-paths-section"))
            return isSV;
        if (layer.id.endsWith("-paths-3d"))
            return !isSV;
        return true;
    }
    /**
     * @override
     * Returns one or more `PathLayer` sub-layers.
     * - Without `sectionPath`: a single `paths` sub-layer for non-binary groups,
     *   plus a single `paths-binary` sub-layer that merges all binary groups into
     *   combined typed-array buffers and passes them straight to the GPU.
     * - With `sectionPath`: a `paths-section` sub-layer (abscissa/depth space)
     *   and a `paths-3d` sub-layer (world XY space), routed by {@link filterSubLayer}.
     *   Binary groups are not supported in section mode and are skipped with a warning.
     */
    renderLayers() {
        const flatData = this.state["flatData"];
        const binaryData = this.state["binaryData"];
        const sectionIndex = this.state["sectionIndex"];
        const { widthUnits, widthScale, widthMinPixels, widthMaxPixels, jointRounded, capRounded, miterLimit, billboard, pickable, depthTest, ZIncreasingDownwards, hiddenGroups, hiddenPolylines, highPrecisionDash, } = this.props;
        // Shared props for all sub-layers
        const sharedProps = {
            data: flatData,
            pickable,
            billboard,
            widthUnits,
            widthScale,
            widthMinPixels,
            widthMaxPixels,
            jointRounded,
            capRounded,
            miterLimit,
            parameters: { depthTest },
            extensions: [
                new DataFilterExtension({ filterSize: 1 }),
                new PathStyleExtension({
                    dash: true,
                    highPrecisionDash: highPrecisionDash !== null && highPrecisionDash !== void 0 ? highPrecisionDash : false,
                }),
            ],
            getFilterValue: (d) => {
                var _a;
                if (d._group.id != null && (hiddenGroups === null || hiddenGroups === void 0 ? void 0 : hiddenGroups.has(d._group.id)))
                    return 0;
                if (((_a = d._polyline) === null || _a === void 0 ? void 0 : _a.id) != null &&
                    (hiddenPolylines === null || hiddenPolylines === void 0 ? void 0 : hiddenPolylines.has(d._polyline.id)))
                    return 0;
                return 1;
            },
            filterRange: [1, 1],
            getColor: (d) => d.color,
            getWidth: (d) => d.width,
            getDashArray: (d) => d.dashArray,
        };
        const updateTriggers = {
            getFilterValue: [hiddenGroups, hiddenPolylines],
            getColor: [flatData],
            getWidth: [flatData],
            getDashArray: [flatData],
            getPath: [ZIncreasingDownwards],
        };
        const layers = [];
        if (sectionIndex) {
            if (binaryData) {
                console.warn("PolylineGroupLayer: BinaryPolylines are not supported when sectionPath is set; skipping binary groups.");
            }
            // Two separate sub-layers — one per coordinate system — so each has
            // its own GPU attribute buffer. filterSubLayer() routes each to the
            // appropriate viewport type (SectionViewport vs. 3D).
            const sectionUpdateTriggers = Object.assign(Object.assign({}, updateTriggers), { getPath: [...updateTriggers.getPath, sectionIndex] });
            layers.push(new PathLayer(this.getSubLayerProps(Object.assign(Object.assign({}, sharedProps), { id: "paths-section", getPath: (d) => d.path.map((pt) => {
                    const z = ZIncreasingDownwards ? -pt[1] : pt[1];
                    return [pt[0], z, 0];
                }), updateTriggers: sectionUpdateTriggers }))), new PathLayer(this.getSubLayerProps(Object.assign(Object.assign({}, sharedProps), { id: "paths-3d", getPath: (d) => d.path.map((pt) => {
                    const z = ZIncreasingDownwards ? -pt[1] : pt[1];
                    const [wx, wy] = projectAbscissa(pt[0], sectionIndex);
                    return [wx, wy, z];
                }), updateTriggers: sectionUpdateTriggers }))));
            return layers;
        }
        if (flatData.length > 0) {
            layers.push(new PathLayer(this.getSubLayerProps(Object.assign(Object.assign({}, sharedProps), { id: "paths", getPath: (d) => {
                    if (!ZIncreasingDownwards)
                        return d.path;
                    return d.path.map(([x, y, z]) => [x, y, -(z !== null && z !== void 0 ? z : 0)]);
                }, updateTriggers }))));
        }
        const binaryLayerData = this.state["binaryLayerData"];
        if (binaryLayerData) {
            layers.push(new PathLayer(this.getSubLayerProps(Object.assign(Object.assign({ id: "paths-binary" }, sharedProps), { extensions: [
                    new DataFilterExtension({ filterSize: 1 }),
                ], data: binaryLayerData, 
                // Experimental deck.gl prop: tells PathLayer the paths
                // are open (not closed rings), skipping the closure
                // check. Safe here since BinaryPolylines are never
                // closed. Re-evaluate if deck.gl removes/renames this.
                _pathType: "open", getColor: undefined, getWidth: undefined, getFilterValue: undefined, getDashArray: undefined }))));
        }
        return layers;
    }
    /**
     * @override
     * Enriches the pick result with the originating {@link PolylineGroup} (`info.group`),
     * the root {@link Polyline} (`info.object`), and layer properties for display
     * (group name, polyline id, depth at the picked coordinate).
     */
    getPickingInfo({ info }) {
        var _a, _b;
        if (info.index < 0)
            return info;
        // Resolve the source group/polyline. For Polyline[] groups the picked
        // FlatEntry carries them directly. For BinaryPolylines the sub-layer id
        // (`paths-binary`) is used to look up the source group; the polyline
        // is unavailable.
        let pickedGroup;
        let pickedPolyline;
        let pickedSource;
        const entry = info.object;
        if (entry && entry._group) {
            pickedGroup = entry._group;
            pickedPolyline = entry._polyline;
            pickedSource = entry;
        }
        else {
            const sourceId = (_a = info.sourceLayer) === null || _a === void 0 ? void 0 : _a.id;
            // Robust check: deck.gl may prefix/suffix the sub-layer id.
            if (sourceId && sourceId.indexOf("paths-binary") !== -1) {
                const binaryData = this.state["binaryData"];
                const group = binaryData === null || binaryData === void 0 ? void 0 : binaryData.pathGroup[info.index];
                if (group) {
                    pickedGroup = group;
                    pickedSource = group;
                }
            }
        }
        if (!pickedSource)
            return info;
        const layerProperties = [];
        if (pickedGroup === null || pickedGroup === void 0 ? void 0 : pickedGroup.name) {
            layerProperties.push(createPropertyData("Group", pickedGroup.name));
        }
        if ((pickedPolyline === null || pickedPolyline === void 0 ? void 0 : pickedPolyline.id) != null) {
            layerProperties.push(createPropertyData("Polyline", String(pickedPolyline.id)));
        }
        const zScale = this.props.modelMatrix ? this.props.modelMatrix[10] : 1;
        // Omit Depth property when the pick originated from a SectionView.
        const viewport = info
            .viewport;
        const isSectionView = (viewport === null || viewport === void 0 ? void 0 : viewport.constructor) === SectionViewport;
        if (!isSectionView && typeof ((_b = info.coordinate) === null || _b === void 0 ? void 0 : _b[2]) !== "undefined") {
            const depth = (this.props.ZIncreasingDownwards
                ? -info.coordinate[2]
                : info.coordinate[2]) / Math.max(0.001, zScale);
            layerProperties.push(createPropertyData("Depth", depth));
        }
        return Object.assign(Object.assign({}, info), { 
            // Expose the original polyline (when available) and group for
            // onHover/onClick handlers. For binary groups `object` falls back
            // to the BinaryGroupEntry so consumers always receive something stable.
            object: pickedPolyline !== null && pickedPolyline !== void 0 ? pickedPolyline : pickedSource, 
            // @ts-expect-error -- deck.gl PickingInfo doesn't type extra fields; consumers can cast
            group: pickedGroup, properties: layerProperties });
    }
}
PolylineGroupLayer.layerName = "PolylineGroupLayer";
PolylineGroupLayer.defaultProps = defaultProps;
//# sourceMappingURL=polylineGroupLayer.js.map