001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.gpx;
003
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.Collections;
007import java.util.HashMap;
008import java.util.List;
009import java.util.Map;
010
011import org.openstreetmap.josm.data.Bounds;
012
013/**
014 * Immutable GPX track.
015 * @since 2907
016 */
017public class ImmutableGpxTrack extends WithAttributes implements GpxTrack {
018
019    private final Collection<GpxTrackSegment> segments;
020    private final double length;
021    private final Bounds bounds;
022
023    /**
024     * Constructs a new {@code ImmutableGpxTrack}.
025     * @param trackSegs track segments
026     * @param attributes track attributes
027     */
028    public ImmutableGpxTrack(Collection<Collection<WayPoint>> trackSegs, Map<String, Object> attributes) {
029        List<GpxTrackSegment> newSegments = new ArrayList<>();
030        for (Collection<WayPoint> trackSeg: trackSegs) {
031            if (trackSeg != null && !trackSeg.isEmpty()) {
032                newSegments.add(new ImmutableGpxTrackSegment(trackSeg));
033            }
034        }
035        this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
036        this.segments = Collections.unmodifiableCollection(newSegments);
037        this.length = calculateLength();
038        this.bounds = calculateBounds();
039    }
040
041    private double calculateLength() {
042        double result = 0.0; // in meters
043
044        for (GpxTrackSegment trkseg : segments) {
045            result += trkseg.length();
046        }
047        return result;
048    }
049
050    private Bounds calculateBounds() {
051        Bounds result = null;
052        for (GpxTrackSegment segment: segments) {
053            Bounds segBounds = segment.getBounds();
054            if (segBounds != null) {
055                if (result == null) {
056                    result = new Bounds(segBounds);
057                } else {
058                    result.extend(segBounds);
059                }
060            }
061        }
062        return result;
063    }
064
065    @Override
066    public Map<String, Object> getAttributes() {
067        return attr;
068    }
069
070    @Override
071    public Bounds getBounds() {
072        if (bounds == null)
073            return null;
074        else
075            return new Bounds(bounds);
076    }
077
078    @Override
079    public double length() {
080        return length;
081    }
082
083    @Override
084    public Collection<GpxTrackSegment> getSegments() {
085        return segments;
086    }
087
088    @Override
089    public int getUpdateCount() {
090        return 0;
091    }
092}