import { DrawLineStringMode, DrawPointMode, DrawPolygonMode, EditableGeoJsonLayer, ImmutableFeatureCollection, ModifyMode, TransformMode, ViewMode, } from "@deck.gl-community/editable-layers";
import { COORDINATE_SYSTEM, CompositeLayer } from "@deck.gl/core";
import { area, length } from "../../utils/measurement";
// Custom drawing mode that deletes the selected GeoJson feature when releasing the Delete key.
class CustomModifyMode extends ModifyMode {
    handleKeyUp(event, props) {
        super.handleKeyUp(event, props);
        if (event.key === "Delete") {
            const updatedData = new ImmutableFeatureCollection(props.data)
                .deleteFeatures(props.selectedIndexes)
                .getObject();
            if (updatedData) {
                props.onEdit({
                    updatedData,
                    editType: "removeFeature",
                    editContext: {
                        featureIndexes: props.selectedIndexes,
                    },
                });
            }
        }
    }
}
function deleteEscapeKeyHandler(drawMode, event, props) {
    if (event.key === "Escape")
        drawMode.getClickSequence().pop();
    else if (event.key === "Delete")
        drawMode.resetClickSequence();
    else
        return;
    // used to set state so layer can be rerendered
    const updatedData = new ImmutableFeatureCollection(props.data).getObject();
    if (updatedData) {
        props.onEdit({
            updatedData,
            editType: "undoDrawing",
            editContext: {
                featureIndexes: props.selectedIndexes,
            },
        });
    }
}
class CustomDrawLineStringMode extends DrawLineStringMode {
    handleKeyUp(event, props) {
        super.handleKeyUp(event, props);
        deleteEscapeKeyHandler(this, event, props);
    }
}
class CustomDrawPolygonMode extends DrawPolygonMode {
    handleKeyUp(event, props) {
        super.handleKeyUp(event, props);
        deleteEscapeKeyHandler(this, event, props);
    }
}
// Mapping of mode name to mode class
const MODE_MAP = {
    view: ViewMode,
    modify: CustomModifyMode,
    transform: TransformMode,
    drawPoint: DrawPointMode,
    drawLineString: CustomDrawLineStringMode,
    drawPolygon: CustomDrawPolygonMode,
};
const UNSELECTED_LINE_COLOR = [0x50, 0x50, 0x50, 0xcc];
const SELECTED_LINE_COLOR = [0x0, 0x0, 0x0, 0xff];
const defaultProps = {
    "@@type": "DrawingLayer",
    name: "Drawing",
    id: "drawing-layer",
    pickable: true,
    visible: true,
    mode: "drawLineString",
    // Props used to get/set data in the drawing layer.
    selectedFeatureIndexes: [],
    data: {
        type: "FeatureCollection",
        features: [],
    },
};
// Composite layer that contains an EditableGeoJsonLayer from nebula.gl
// See https://nebula.gl/docs/api-reference/layers/editable-geojson-layer
export default class DrawingLayer extends CompositeLayer {
    initializeState(context) {
        super.initializeState(context);
        this.setState({
            data: this.props.data,
            selectedFeatureIndexes: this.props.selectedFeatureIndexes,
        });
    }
    // Select features when clicking on them if in view or modify modes.
    // The selection is used to set current selected drawing, and
    // is sent to the map component parent via setEditedData.
    onClick(info) {
        if (this.props.mode === "view" || this.props.mode === "modify") {
            this.setState({
                selectedFeatureIndexes: [info.index],
            });
            this.context.userData.setEditedData({
                selectedFeatureIndexes: [info.index],
            });
            return true;
        }
        return false;
    }
    // For now, use `any` for the picking types because this function should
    // recieve PickInfo<FeatureCollection>, but it recieves PickInfo<Feature>.
    getPickingInfo({ info }) {
        var _a, _b;
        if (!info.object)
            return info;
        const feature = info.object;
        let measurement;
        if (((_a = feature.geometry) === null || _a === void 0 ? void 0 : _a.type) === "LineString") {
            measurement = length(feature);
        }
        else if (((_b = feature.geometry) === null || _b === void 0 ? void 0 : _b.type) === "Polygon") {
            measurement = area(feature);
        }
        else
            return info;
        return Object.assign(Object.assign({}, info), { propertyValue: measurement });
    }
    // Callback for various editing events. Most events will update this component
    // through patches sent to the map parent. See patchLayerPropsin layerTools.ts.
    _onEdit(editAction) {
        switch (editAction.editType) {
            case "addFeature":
                this.setState({
                    data: editAction.updatedData,
                    selectedFeatureIndexes: editAction.editContext.featureIndexes,
                });
                this.context.userData.setEditedData({
                    data: editAction.updatedData,
                    selectedFeatureIndexes: editAction.editContext.featureIndexes,
                });
                break;
            case "removeFeature":
                this.setState({
                    data: editAction.updatedData,
                    selectedFeatureIndexes: [],
                });
                this.context.userData.setEditedData({
                    data: editAction.updatedData,
                    selectedFeatureIndexes: [],
                });
                break;
            case "removePosition":
            case "finishMovePosition":
                this.setState({
                    data: editAction.updatedData,
                });
                this.context.userData.setEditedData({
                    data: editAction.updatedData,
                });
                break;
            case "movePosition":
            case "undoDrawing":
                // Don't use setEditedData to avoid an expensive roundtrip,
                // since this is done on every mouse move when editing.
                this.setState({ data: editAction.updatedData });
                break;
        }
    }
    // Return the line color based on the selection status.
    // The same can be done for other features (polygons, points etc).
    _getLineColor(feature) {
        const selectedFeatureIndexes = this.state["selectedFeatureIndexes"];
        const data = this.state["data"];
        const is_feature_selected = selectedFeatureIndexes.some((i) => data.features[i] === feature);
        if (is_feature_selected) {
            return SELECTED_LINE_COLOR;
        }
        else {
            return UNSELECTED_LINE_COLOR;
        }
    }
    renderLayers() {
        if (this.props.visible == false) {
            return [];
        }
        const sub_layer_props = this.getSubLayerProps({
            data: this.state["data"],
            mode: MODE_MAP[this.props.mode],
            modeConfig: {
                viewport: this.context.viewport,
            },
            selectedFeatureIndexes: this.state["selectedFeatureIndexes"],
            coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
            onEdit: (editAction) => this._onEdit(editAction),
            _subLayerProps: {
                geojson: {
                    autoHighlight: true,
                    getLineColor: (feature) => this._getLineColor(feature),
                },
            },
        });
        return [new EditableGeoJsonLayer(sub_layer_props)];
    }
}
DrawingLayer.layerName = "DrawingLayer";
DrawingLayer.defaultProps = defaultProps;
//# sourceMappingURL=drawingLayer.js.map