/**
   * Add given sample to buffer, performing a back-in-time check, updating the sample buffer error
   * state.
   *
   * @param value Value to archive
   * @return <code>false</code> if value failed back-in-time or future check, <code>true</code> if
   *     value was added.
   */
  protected final boolean addValueToBuffer(final VType value) {
    // Suppress samples that are too far in the future
    final Timestamp time = VTypeHelper.getTimestamp(value);

    if (isFuturistic(time)) {
      trouble_sample_log.log("'" + getName() + "': Futuristic " + value);
      return false;
    }

    synchronized (this) {
      if (last_archived_value != null
          && VTypeHelper.getTimestamp(last_archived_value).compareTo(time)
              >= 0) { // Cannot use this sample because of back-in-time problem.
        // Usually this is NOT an error:
        // We logged an initial sample, disconnected, disabled, ...,
        // and now we got an update from the IOC which still
        // carries the old, original time stamp of the PV,
        // and that's back in time...
        trouble_sample_log.log(
            getName()
                + " skips back-in-time:\n"
                + "last: "
                + VTypeHelper.toString(last_archived_value)
                + "\n"
                + "new : "
                + VTypeHelper.toString(value));
        return false;
      }
      // else ...
      last_archived_value = value;
    }
    buffer.add(value);
    if (SampleBuffer.isInErrorState()) need_write_error_sample = true;
    return true;
  }
  /**
   * Called for each value received from PV.
   *
   * <p>Base class remembers the <code>most_recent_value</code>, and asserts that one 'first' sample
   * is archived. Derived class <b>must</b> call <code>super()</code>.
   *
   * @param value Value received from PV
   * @return true if the value was already written because it's the first value after startup or
   *     error, so there's no need to write that sample again.
   */
  protected boolean handleNewValue(final VType value) {
    synchronized (this) {
      ++received_value_count;
      most_recent_value = value;
    }
    // NaN test
    if (value instanceof VNumber) {
      if (Double.isNaN(VTypeHelper.toDouble(value)))
        trouble_sample_log.log("'" + getName() + "': NaN " + VTypeHelper.toString(value));
    }
    if (!enabled) return false;

    // Did we recover from write errors?
    if (need_write_error_sample && SampleBuffer.isInErrorState() == false) {
      need_write_error_sample = false;
      Activator.getLogger().log(Level.FINE, "Wrote error sample for {0}", getName());
      addInfoToBuffer(ValueButcher.createWriteError());
      need_first_sample = true;
    }
    // Is this the first sample after startup or an error?
    if (!need_first_sample) return false;
    need_first_sample = false;
    // Try to add as-is, but time stamp will be corrected to fit in
    final VType added = addInfoToBuffer(value);
    Activator.getLogger()
        .log(Level.FINE, "Wrote first sample for {0}: {1}", new Object[] {getName(), added});
    return true;
  }
 /**
  * Check a received value for basic problems before passing it on to the sample mechanism
  *
  * @param value Value as received from network layer
  * @return Value to be used for archive
  */
 private VType checkReceivedValue(VType value) {
   if (value instanceof Time) {
     try {
       final Time time = (Time) value;
       // Invoke time.getTimestamp() to detect RuntimeError in VType 2013/11/01
       if (time.isTimeValid() && time.getTimestamp() != null) return value;
       else {
         trouble_sample_log.log("'" + getName() + "': Invalid time stamp ");
         value = VTypeHelper.transformTimestamp(value, Timestamp.now());
       }
     } catch (RuntimeException ex) {
       Logger.getLogger(getClass().getName())
           .log(Level.WARNING, "'" + getName() + "': Exception getting time stamp", ex);
       value = VTypeHelper.transformTimestamp(value, Timestamp.now());
     }
   } else trouble_sample_log.log("'" + getName() + "': Received no time information for " + value);
   return value;
 }