@Test
  public void testExceedHistoryBackward() throws OrekitException, IOException {
    final double period = 900.0;

    // the raw detector should trigger one event at each 900s period
    final DateDetector raw =
        new DateDetector(orbit.getDate().shiftedBy(+0.5 * period))
            .withMaxCheck(period / 3)
            .withHandler(new ContinueOnEvent<DateDetector>());
    for (int i = 0; i < 300; ++i) {
      raw.addEventDate(orbit.getDate().shiftedBy(-(i + 0.5) * period));
    }

    // in fact, we will filter out half of these events, so we get only one event every 2 periods
    final EventEnablingPredicateFilter<DateDetector> filtered =
        new EventEnablingPredicateFilter<DateDetector>(
            raw,
            new EnablingPredicate<DateDetector>() {
              public boolean eventIsEnabled(
                  SpacecraftState state, DateDetector eventDetector, double g) {
                double nbPeriod = orbit.getDate().durationFrom(state.getDate()) / period;
                return ((int) FastMath.floor(nbPeriod)) % 2 == 1;
              }
            });
    Propagator propagator = new KeplerianPropagator(orbit);
    EventsLogger logger = new EventsLogger();
    propagator.addEventDetector(logger.monitorDetector(filtered));
    propagator.propagate(orbit.getDate().shiftedBy(-301 * period));
    List<LoggedEvent> events = logger.getLoggedEvents();

    // 300 periods, 150 events as half of them are filtered out
    Assert.assertEquals(150, events.size());

    // as we have encountered a lot of enabling status changes, we exceeded the internal history
    // if we try to display again the filtered g function for dates far in the future,
    // we will not see the zero crossings anymore, they have been lost
    propagator.clearEventsDetectors();
    for (double dt = -5000.0; dt > -10000.0; dt -= 3.0) {
      double filteredG = filtered.g(propagator.propagate(orbit.getDate().shiftedBy(dt)));
      Assert.assertTrue(filteredG < 0.0);
    }

    // on the other hand, if we try to display again the filtered g function for future dates
    // that are still inside the history, we still see the zero crossings
    for (double dt = -195400.0; dt > -196200.0; dt -= 3.0) {
      double filteredG = filtered.g(propagator.propagate(orbit.getDate().shiftedBy(dt)));
      if (dt < -195750) {
        Assert.assertTrue(filteredG < 0.0);
      } else {
        Assert.assertTrue(filteredG > 0.0);
      }
    }
  }
  private void doElevationTest(
      final double minElevation,
      final AbsoluteDate start,
      final AbsoluteDate end,
      final int expectedEvents,
      final boolean sameSign)
      throws OrekitException {

    final ElevationExtremumDetector raw =
        new ElevationExtremumDetector(0.001, 1.e-6, new TopocentricFrame(earth, gp, "test"))
            .withHandler(new ContinueOnEvent<ElevationExtremumDetector>());
    final EventEnablingPredicateFilter<ElevationExtremumDetector> aboveGroundElevationDetector =
        new EventEnablingPredicateFilter<ElevationExtremumDetector>(
                raw,
                new EnablingPredicate<ElevationExtremumDetector>() {
                  public boolean eventIsEnabled(
                      final SpacecraftState state,
                      final ElevationExtremumDetector eventDetector,
                      final double g)
                      throws OrekitException {
                    return eventDetector.getElevation(state) > minElevation;
                  }
                })
            .withMaxCheck(60.0);

    Assert.assertEquals(0.001, raw.getMaxCheckInterval(), 1.0e-15);
    Assert.assertEquals(60.0, aboveGroundElevationDetector.getMaxCheckInterval(), 1.0e-15);
    Assert.assertEquals(1.0e-6, aboveGroundElevationDetector.getThreshold(), 1.0e-15);
    Assert.assertEquals(
        AbstractDetector.DEFAULT_MAX_ITER, aboveGroundElevationDetector.getMaxIterationCount());

    Propagator propagator =
        new EcksteinHechlerPropagator(
            orbit,
            Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
            Constants.EIGEN5C_EARTH_MU,
            Constants.EIGEN5C_EARTH_C20,
            Constants.EIGEN5C_EARTH_C30,
            Constants.EIGEN5C_EARTH_C40,
            Constants.EIGEN5C_EARTH_C50,
            Constants.EIGEN5C_EARTH_C60);

    EventsLogger logger = new EventsLogger();
    propagator.addEventDetector(logger.monitorDetector(aboveGroundElevationDetector));

    propagator.propagate(start, end);
    for (LoggedEvent e : logger.getLoggedEvents()) {
      final double eMinus = raw.getElevation(e.getState().shiftedBy(-10.0));
      final double e0 = raw.getElevation(e.getState());
      final double ePlus = raw.getElevation(e.getState().shiftedBy(+10.0));
      Assert.assertTrue(e0 > eMinus);
      Assert.assertTrue(e0 > ePlus);
      Assert.assertTrue(e0 > minElevation);
    }
    Assert.assertEquals(expectedEvents, logger.getLoggedEvents().size());

    propagator.clearEventsDetectors();
    double g1Raw = raw.g(propagator.propagate(orbit.getDate().shiftedBy(18540.0)));
    double g2Raw = raw.g(propagator.propagate(orbit.getDate().shiftedBy(18624.0)));
    double g1 =
        aboveGroundElevationDetector.g(propagator.propagate(orbit.getDate().shiftedBy(18540.0)));
    double g2 =
        aboveGroundElevationDetector.g(propagator.propagate(orbit.getDate().shiftedBy(18624.0)));
    Assert.assertTrue(g1Raw > 0);
    Assert.assertTrue(g2Raw < 0);
    if (sameSign) {
      Assert.assertTrue(g1 > 0);
      Assert.assertTrue(g2 < 0);
    } else {
      Assert.assertTrue(g1 < 0);
      Assert.assertTrue(g2 > 0);
    }
  }