private void assertFurtherValuesSorting(final FDate key) {
    final FDate firstKey = extractKey(key, furtherValues.getHead());
    if (firstKey.compareTo(key) <= -1) {
      /*
       * readAllValuesAscendingFrom loads all data, thus we set the min key very deep so that later queries are
       * skipped if they are before minKey
       */
      minKey = minKey();
    }
    if (minKeyInDB == null || firstKey.compareTo(minKey) <= -1) {
      minKeyInDB = firstKey;
    }
    minKeyInDBFromLoadFurtherValues = FDates.min(minKeyInDBFromLoadFurtherValues, firstKey);
    final FDate lastKey = extractKey(key, furtherValues.getTail());
    if (maxKeyInDB == null || lastKey.compareTo(maxKeyInDB) <= -1) {
      maxKeyInDB = FDates.max(maxKeyInDB, lastKey);
    }
    maxKeyInDBFromLoadFurtherValues = FDates.max(maxKeyInDBFromLoadFurtherValues, lastKey);

    if (furtherValues.size() > 1) {
      Assertions.checkState(
          firstKey.compareTo(lastKey) <= 0,
          "Not ascending sorted! At firstKey [%s] and lastKey [%s]",
          firstKey,
          lastKey);
    }
  }
  private V searchInFurtherValues(final FDate key) {
    // Take the first matching value from the sorted list
    // Search for the newest value
    V prevValue = (V) null;
    FDate prevKey = null;
    if (!lastValuesFromFurtherValues.isEmpty()) {
      // though maybe use the last one for smaller increments than the data itself is loaded
      for (final V lastValueFromFurtherValues : lastValuesFromFurtherValues) {
        final FDate keyLastValueFromFurtherValues = extractKey(key, lastValueFromFurtherValues);
        if (keyLastValueFromFurtherValues.isBeforeOrEqualTo(key)) {
          prevValue = lastValueFromFurtherValues;
          prevKey = keyLastValueFromFurtherValues;
        } else {
          // only go to further values if it might be possible that those are useable
          return prevValue;
        }
      }
    }

    final FDate earliestStartOfLoadFurtherValues = determineEaliestStartOfLoadFurtherValues(key);
    while (furtherValues.size() > 0) {
      final V newValue = furtherValues.getHead();
      final FDate newValueKey = extractKey(key, newValue);
      final int compare = key.compareTo(newValueKey);
      if (compare < 0) {
        // key < newValueKey
        // run over the key we wanted
        break;
      } else if (compare == 0) {
        // key == newValueKey
        // This is the value we searched for! It will later be added with the db key to the cache.
        pushLastValueFromFurtherValues();
        return newValue;
      } else {
        // key > newValueKey
        // put this value into the cache; gaps do not get filled here, so that the max size of the
        // cache does not get reached prematurely
        put(newValueKey, newValue, prevKey, prevValue);
        pushLastValueFromFurtherValues();
        // continue with the next one
        prevValue = newValue;
        prevKey = newValueKey;

        if (furtherValues.isEmpty()
            && newValueKey.isBefore(maxKeyInDB)
            && key.isBefore(maxKeyInDB)
            && maxKeyInDBFromLoadFurtherValues.isBefore(maxKeyInDB)) {
          final FDate timeForLoadFurtherValues =
              FDates.max(newValueKey, earliestStartOfLoadFurtherValues);
          Assertions.checkState(
              eventuallyLoadFurtherValues(
                  "searchInFurtherValues", newValueKey, timeForLoadFurtherValues, false, true));
          if (!furtherValues.isEmpty()) {
            pushLastValueFromFurtherValues();
            if (!timeForLoadFurtherValues.equals(newValue)) {
              // do not distort prev/next lookup when using earlisetStartOfLoadFurtherValues, thus
              // reset those
              prevValue = null;
              prevKey = null;
            }
          }
        }
      }
    }
    return prevValue;
  }
 public void addComponent(final Component e) {
   Assertions.assertThat(wicket_component.put(e.getId(), e)).isNull();
 }