@Override
    public Optional<Track<T>> clean(Track<T> track) {

        TreeSet<Point<T>> points = new TreeSet<>(track.points());

        Optional<Point<T>> firstNonNull = firstPointWithAltitude(points);
        if (!firstNonNull.isPresent()) {
            return Optional.empty();
        }

        SortedSet<Point<T>> pointsMissingAltitude = points.headSet(firstNonNull.get());
        TreeSet<Point<T>> fixedPoints = extrapolateAltitudes(pointsMissingAltitude, firstNonNull.get());
        pointsMissingAltitude.clear();
        points.addAll(fixedPoints);


        Optional<Point<T>> gapStart;
        Optional<Point<T>> gapEnd = firstNonNull;

        while (gapEnd.isPresent()) {

            gapStart = firstPointWithoutAltitude(points.tailSet(gapEnd.get()));

            if (!gapStart.isPresent()) {
                break;
            }
            gapEnd = firstPointWithAltitude(points.tailSet(gapStart.get()));

            if (!gapEnd.isPresent()) {

                pointsMissingAltitude = points.tailSet(gapStart.get());
                fixedPoints = extrapolateAltitudes(pointsMissingAltitude, points.lower(gapStart.get()));
                pointsMissingAltitude.clear();
                points.addAll(fixedPoints);

//                extrapolateAltitudes(points.tailSet(gapStart.get()), points.lower(gapStart.get()));
            } else {
                pointsMissingAltitude = points.subSet(gapStart.get(), gapEnd.get());
                fixedPoints = interpolateAltitudes(pointsMissingAltitude, points.lower(gapStart.get()), gapEnd.get());
                pointsMissingAltitude.clear();
                points.addAll(fixedPoints);

//                interpolateAltitudes(points.subSet(gapStart.get(), gapEnd.get()), points.lower(gapStart.get()), gapEnd.get());
            }
        }

        return Optional.of(Track.of(points));
    }
@Test
    public void testFillingFinalAltitudes() {
        Track<NoRawData> testTrack = trackWithNoFinalAltitudes();
        Track<NoRawData> cleanedTrack = (new FillMissingAltitudes<NoRawData>()).clean(testTrack).get();
        ArrayList<Point<NoRawData>> points = new ArrayList<>(cleanedTrack.points());

        assertTrue(
            points.get(3).altitude().equals(points.get(1).altitude()) &&
                points.get(2).altitude().equals(points.get(1).altitude()),
            "The last points should have their altitudes filled"
        );
    }