"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnchorPointSegmenter = void 0;
const ModuleContainerToken_1 = require("../../../../../ioc/ModuleContainerToken");
const Di_1 = require("../../../../ioc/Di");
// 100 meters radius, 8 points polygon
const SEGMENTED_POSITION_RADIUS_IN_KM = 0.1;
// 200 meters radius, 16 points polygon
const DEFAULT_POSITION_RADIUS_IN_KM = 0.2;
class AnchorPointSegmenter {
    constructor(anchorPoints, currentPosition) {
        this.geoHelper = Di_1.VPContainer.resolve(ModuleContainerToken_1.ModuleContainerToken.GeoMeasurementHelper);
        this.anchorPoints = anchorPoints;
        this.anchorPointSegments = this.computeAnchorPointSegments(anchorPoints);
        this.currentPosition = currentPosition;
    }
    /**
     * Returns closest anchor point to current position
     *  if lastStopSequence is provided, only anchor points from that segment are considered
     */
    getClosesPoint(lastStopSequence) {
        const ptsInRadius = this.getAnchorPointsInRadius(lastStopSequence);
        if (ptsInRadius.length === 0) {
            return null;
        }
        let closestPoint = null;
        let closestDistance = Infinity;
        for (const point of ptsInRadius) {
            const distance = this.geoHelper.getDistanceInKilometers(this.currentPosition.geometry.coordinates, point.coordinates);
            if (distance < closestDistance) {
                closestPoint = point;
                closestDistance = distance;
            }
        }
        return closestPoint;
    }
    /**
     * Returns all anchor points in radius of current position
     *   if lastStopSequence is provided, only anchor points from that segment are returned
     */
    getAnchorPointsInRadius(lastStopSequence) {
        const positionCoordinates = this.currentPosition.geometry.coordinates;
        const anchorPoints = lastStopSequence ? this.anchorPointSegments.get(lastStopSequence) ?? [] : this.anchorPoints;
        const radiusInKm = lastStopSequence ? SEGMENTED_POSITION_RADIUS_IN_KM : DEFAULT_POSITION_RADIUS_IN_KM;
        const boundingBox = this.geoHelper.getBufferedBBoxInKilometers(positionCoordinates, radiusInKm);
        let ptsInRadius = [];
        for (const anchorPoint of anchorPoints) {
            // Ignore anchor points outside bbox to avoid unnecessary distance calculations
            if (!this.geoHelper.isPointInBBox(anchorPoint.coordinates, boundingBox)) {
                continue;
            }
            const distanceInKm = this.geoHelper.getDistanceInKilometers(anchorPoint.coordinates, positionCoordinates);
            // Ignore anchor points on the periphery of the bbox
            if (distanceInKm > radiusInKm) {
                continue;
            }
            ptsInRadius.push(anchorPoint);
        }
        // Edge case - if no points found, try again with all points
        // (vehicle may be too far ahead - e.g. when the vehicle/data provider stopped sending data for a while)
        // (we want to find at least one point on track so that the vehicle is not immediately considered off_track)
        if (lastStopSequence && ptsInRadius.flat().length === 0) {
            return this.getAnchorPointsInRadius(null);
        }
        return ptsInRadius;
    }
    /** Divides anchor points into segments by last stop sequence and this stop sequence if at stop */
    computeAnchorPointSegments(anchorPoints) {
        let segments = new Map();
        for (const anchorPoint of anchorPoints) {
            let currentSegment = this.getSegment(segments, anchorPoint.last_stop_sequence);
            // Add anchor point to segment
            currentSegment.push(anchorPoint);
            // If at stop, also add anchor point to previous segment (except if first stop since there is no previous segment)
            if (anchorPoint.at_stop && anchorPoint.last_stop_sequence !== 1) {
                const previousSegment = this.getSegment(segments, anchorPoint.last_stop_sequence - 1);
                previousSegment.push(anchorPoint);
            }
        }
        return segments;
    }
    getSegment(segments, segmentIndex) {
        let segment = segments.get(segmentIndex);
        if (!segment) {
            segment = [];
            segments.set(segmentIndex, segment);
        }
        return segment;
    }
}
exports.AnchorPointSegmenter = AnchorPointSegmenter;
//# sourceMappingURL=AnchorPointSegmenter.js.map