import { CompositeLayer } from "@deck.gl/core";
import { isEqual } from "lodash";
import { createPropertyData, computeBoundingBox } from "../utils/layerTools";
import { PrivatePolylinesLayer } from "./privatePolylinesLayer";
const defaultProps = {
    "@@type": "PolylinesLayer",
    name: "PolylinesLayer",
    id: "polylines-layer",
    widthUnits: "pixels",
    linesWidth: 5,
    color: [0, 0, 200, 255],
    pickable: true,
    visible: true,
    depthTest: true,
    ZIncreasingDownwards: true,
};
export default class PolylinesLayer extends CompositeLayer {
    renderLayers() {
        const data = this.state["dataAttributes"];
        const _pathType = data.pathType;
        const layer = new PrivatePolylinesLayer(this.getSubLayerProps({
            id: "polylines-layer",
            widthUnits: this.props.widthUnits,
            pickable: this.props.pickable,
            billboard: true,
            jointRounded: true,
            capRounded: true,
            data,
            _pathType,
            getColor: () => this.props.color,
            getWidth: () => this.props.linesWidth,
            updateTriggers: {
                getColor: [this.props.color],
                getWidth: [this.props.linesWidth],
            },
            depthTest: this.props.depthTest,
            ZIncreasingDownwards: this.props.ZIncreasingDownwards,
        }));
        return [layer];
    }
    initializeState() {
        const dataAttributes = this.rebuildDataAttributes(true);
        this.setState({ dataAttributes });
    }
    updateState({ props, oldProps }) {
        const needs_reload = !isEqual(props.polylinePoints, oldProps.polylinePoints) ||
            !isEqual(props.startIndices, oldProps.startIndices) ||
            !isEqual(props.polylinesClosed, oldProps.polylinesClosed) ||
            !isEqual(props.ZIncreasingDownwards, oldProps.ZIncreasingDownwards);
        if (needs_reload) {
            const dataAttributes = this.rebuildDataAttributes(false);
            this.setState({ dataAttributes });
        }
    }
    rebuildDataAttributes(reportBoundingBox) {
        const dataArrays = this.loadData();
        if (typeof this.props.reportBoundingBox === "function" &&
            reportBoundingBox) {
            const boundingBox = computeBoundingBox(dataArrays.positions);
            this.props.reportBoundingBox({ layerBoundingBox: boundingBox });
        }
        return {
            length: dataArrays.linesCount,
            startIndices: dataArrays.startIndices,
            attributes: {
                getPath: {
                    value: dataArrays.positions,
                    size: 3,
                },
            },
            pathType: dataArrays.pathType,
        };
    }
    getPickingInfo({ info }) {
        var _a;
        if (!info.color) {
            return info;
        }
        const layer_properties = [];
        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));
        }
        return Object.assign(Object.assign({}, info), { properties: layer_properties });
    }
    loadData() {
        // The input arrays can be used as deck.gl binary inputs.
        // Explicit pathType prevents deck.gl from additional computations.
        if (this.props.polylinePoints instanceof Float32Array &&
            this.props.startIndices instanceof Uint32Array &&
            !this.props.polylinesClosed) {
            return {
                linesCount: this.props.startIndices.length - 1,
                positions: this.props.polylinePoints,
                startIndices: this.props.startIndices,
                pathType: "open",
            };
        }
        const data = this.closePolylines();
        return {
            linesCount: data.startIndices.length,
            positions: new Float32Array(data.polylinePoints),
            startIndices: new Uint32Array(data.startIndices),
            pathType: data.pathType,
        };
    }
    toArray(data) {
        if (Array.isArray(data)) {
            return data;
        }
        return Array.from(data);
    }
    closePolylines() {
        const points = this.toArray(this.props.polylinePoints);
        const startIndices = this.toArray(this.props.startIndices);
        this.normalizeStartIndices(startIndices, points.length / 3);
        const isClosedFunc = this.createIsClosedFunc();
        if (!isClosedFunc.func) {
            return {
                polylinePoints: points,
                startIndices: startIndices,
                pathType: isClosedFunc.pathType,
            };
        }
        let startIndexShift = 0;
        const closedPoints = [];
        const closedStartIndices = [];
        const linesCount = this.props.startIndices.length - 1;
        for (let i = 0; i < linesCount; ++i) {
            const isClosed = isClosedFunc.func(i);
            closedStartIndices.push(this.props.startIndices[i] + startIndexShift);
            if (isClosed) {
                this.closePolyline(points, startIndices, i, closedPoints);
                ++startIndexShift;
            }
            else {
                this.copyPolyline(points, startIndices, i, closedPoints);
            }
        }
        return {
            polylinePoints: closedPoints,
            startIndices: closedStartIndices,
            pathType: isClosedFunc.pathType,
        };
    }
    normalizeStartIndices(startIndices, pointsCount) {
        const lastIndex = startIndices.slice(-1)[0];
        if (lastIndex < pointsCount) {
            startIndices.push(pointsCount);
        }
    }
    copyPolyline(points, startIndices, lineIndex, outPoints) {
        const startPoint = startIndices[lineIndex];
        const endPoint = startIndices[lineIndex + 1];
        for (let idx = startPoint; idx < endPoint; ++idx) {
            outPoints.push(...this.getPolylinePoint(points, idx));
        }
    }
    closePolyline(points, startIndices, lineIndex, outPoints) {
        this.copyPolyline(points, startIndices, lineIndex, outPoints);
        const startPoint = startIndices[lineIndex];
        outPoints.push(...this.getPolylinePoint(points, startPoint));
    }
    getPolylinePoint(points, index) {
        return points.slice(3 * index, 3 * (index + 1));
    }
    createIsClosedFunc() {
        if (this.props.polylinesClosed === true) {
            return {
                func: () => true,
                pathType: "loop",
            };
        }
        if (Array.isArray(this.props.polylinesClosed)) {
            return {
                func: (lineIndex) => {
                    return this.props.polylinesClosed[lineIndex];
                },
                pathType: null,
            };
        }
        return {
            func: null,
            pathType: "open",
        };
    }
}
PolylinesLayer.layerName = "PolylinesLayer";
PolylinesLayer.defaultProps = defaultProps;
//# sourceMappingURL=polylinesLayer.js.map