public static <T> long LazyMovingImmediateAverage(
      final int periods,
      final int interval_secs,
      final LazyMovingImmediateAverageAdapter<T> adapter,
      final T instance) {
    LazyMovingImmediateAverageState current = adapter.getCurrent(instance);

    if (current == null) {

      final LazyMovingImmediateAverageState state = current = new LazyMovingImmediateAverageState();

      SimpleTimer.addTickReceiver(
          new TimerTickReceiver() {

            public void tick(long mono_now, int tick_count) {
              long now = SystemTime.getMonotonousTime();

              if (now - state.last_read > 60 * 1000) {

                SimpleTimer.removeTickReceiver(this);

                adapter.setCurrent(instance, null);

              } else if (tick_count % interval_secs == 0) {

                long value = adapter.getValue(instance);

                long last = state.last_value;
                long diff = value - last;

                if (last >= 0 && diff >= 0) {

                  MovingImmediateAverage average = state.average;

                  if (diff == 0) {

                    state.consec_zeros++;

                  } else {

                    state.consec_zeros = 0;
                  }

                  if (average == null) {

                    if (diff > 0) {

                      state.average = average = MovingImmediateAverage(periods);

                      int zeros_to_do = Math.min(state.consec_zeros, periods);

                      for (int i = 0; i < zeros_to_do; i++) {

                        average.update(0);
                      }
                    }
                  }

                  if (average != null) {

                    long ave = (long) average.update(diff);

                    if (ave == 0 && average.getSampleCount() >= periods) {

                      // looks pretty dead

                      state.average = null;
                    }
                  }
                }

                state.last_value = value;
              }
            }
          });

      adapter.setCurrent(instance, current);

    } else {

      current.last_read = SystemTime.getMonotonousTime();
    }

    MovingImmediateAverage average = current.average;

    if (average == null) {

      return (0);

    } else {

      return ((long) average.getAverage() / interval_secs);
    }
  }