package se.l4.vibe.sampling;

import se.l4.vibe.Exportable;
import se.l4.vibe.internal.MergedProbes;
import se.l4.vibe.mapping.KeyValueMap;
import se.l4.vibe.probes.Probe;

/**
 * Probe that measures a value that requires sampling to be read.
 *
 * @param <T>
 */
public interface SampledProbe<T>
	extends Exportable
{
	/**
	 * Sample the current value and optionally reset the probe.
	 *
	 * @return
	 */
	T sample();

	/**
	 * Create a {@link SampledProbe} by reading values from a {@link Probe}.
	 *
	 * @param probe
	 *   the probe to convert
	 * @return
	 *   converted probe
	 */
	static <T> SampledProbe<T> over(Probe<T> probe)
	{
		return probe::read;
	}

	/**
	 * Start building a new probe that contains merged data.
	 *
	 * <p>
	 * Example:
	 *
	 * <pre>
	 * ThreadPoolExecutor executor = ...;
	 *
     * Probe<KeyValueMap> probe = Probe.merged()
     *  .add("maxSize", executor::getMaximumPoolSize)
     *  .add("size", executor:getPoolSize)
     *  .add("active", executor::getActiveCount)
     *  .build();
	 * </pre>
	 */
	static MergedBuilder merged()
	{
		return new MergedProbes.SampledProbeBuilder();
	}

	/**
	 * Builder for creating a {@link SampledProbe} that contains values from
	 * several other probes.
	 */
	interface MergedBuilder
	{
		/**
		 * Add a probe to that will be used to read out the value associated
		 * with the given key.
		 *
		 * @param name
		 *   the name of the property
		 * @param probe
		 *   probe used to read the property
		 * @return
		 *   builder
		 */
		MergedBuilder add(String name, SampledProbe<?> probe);

		/**
		 * Create the probe.
		 *
		 * @return
		 */
		SampledProbe<KeyValueMap> build();
	}
}

@@ -164,16 +164,57 @@
 s.Probe;
+%0Aimport se.l4.vibe.probes.ProbeOperation;
 %0A%0A/**%0A *
@@ -454,16 +454,365 @@
 ple();%0A%0A
+%09/**%0A%09 * Create a new probe that applies the given operation to the value of this%0A%09 * probe.%0A%09 *%0A%09 * @param %3CO%3E%0A%09 * @param operation%0A%09 *   operation to apply%0A%09 * @return%0A%09 *   new probe%0A%09 */%0A%09default %3CO%3E SampledProbe%3CO%3E apply(ProbeOperation%3CT, O%3E operation)%0A%09%7B%0A%09%09return () -%3E %7B%0A%09%09%09T value = this.sample();%0A%09%09%09return operation.apply(value);%0A%09%09%7D;%0A%09%7D%0A%0A
 %09/**%0A%09 *

apply for SampledProbe using ProbeOperation