package com.beowulfe.hap.characteristics;

import java.util.concurrent.CompletableFuture;

import javax.json.JsonNumber;
import javax.json.JsonObjectBuilder;
import javax.json.JsonValue;

/**
 * A characteristic that provides a Float value type.
 *
 * @author Andy Lintner
 */
public abstract class FloatCharacteristic extends BaseCharacteristic<Double> {

	private final double minValue;
	private final double maxValue;
	private final double minStep;
	private final String unit;
	
	/**
	 * Default constructor
	 * 
	 * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these,
	 *  however implementors can create their own as well.
	 * @param isWritable indicates whether the value can be changed.
	 * @param isReadable indicates whether the value can be retrieved.
	 * @param description a description of the characteristic to be passed to the consuming device.
	 * @param minValue the minimum supported value.
	 * @param maxValue the maximum supported value
	 * @param minStep the smallest supported step. Values will be rounded to a multiple of this.
	 * @param unit a description of the unit this characteristic supports.
	 */
	public FloatCharacteristic(String type, boolean isWritable, boolean isReadable, String description,
			double minValue, double maxValue, double minStep, String unit) {
		super(type, "float", isWritable, isReadable, description);
		this.minValue = minValue;
		this.maxValue = maxValue;
		this.minStep = minStep;
		this.unit = unit;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected CompletableFuture<JsonObjectBuilder> makeBuilder(int iid) {
		return super.makeBuilder(iid).thenApply(builder -> {
			return builder
					.add("minValue", minValue)
					.add("maxValue", maxValue)
					.add("minStep", minStep)
					.add("unit", unit);
		});
			
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Double convert(JsonValue jsonValue) {
		return ((JsonNumber) jsonValue).doubleValue();
	}
	
	/**
	 * {@inheritDoc}. Calls the getDoubleValue method and applies rounding to the minStep supplied in the constructor.
	 */
	@Override
	protected final CompletableFuture<Double> getValue() {
		double rounder = 1 / this.minStep;
		return getDoubleValue().thenApply(d -> d == null ? null : Math.round(d * rounder) / rounder); 
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Double getDefault() {
		return minValue;
	}
	
	/**
	 * Supplies the value of this characteristic as a double.
	 * @return a future that will contain the value.
	 */
	protected abstract CompletableFuture<Double> getDoubleValue();
}

@@ -47,46 +47,56 @@
 ort 
-java.util.concurrent.CompletableFuture
+org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory
 ;%0A%0Ai
@@ -189,16 +189,63 @@
 onValue;
+%0Aimport java.util.concurrent.CompletableFuture;
 %0A%0A/**%0A *
@@ -407,16 +407,107 @@
 ble%3E %7B%0A%0A
+%09private final static Logger LOGGER = LoggerFactory.getLogger(FloatCharacteristic.class);%0A%0A
 %09private
@@ -1832,33 +1832,32 @@
  -%3E 
-%7B%0A%09%09%09return builder%0A%09%09%09%09%09
+builder%0A                
 .add
@@ -1875,29 +1875,40 @@
 , minValue)%0A
-%09%09%09%09%09
+                
 .add(%22maxVal
@@ -1922,21 +1922,32 @@
 xValue)%0A
-%09%09%09%09%09
+                
 .add(%22mi
@@ -1967,13 +1967,24 @@
 ep)%0A
-%09%09%09%09%09
+                
 .add
@@ -2001,19 +2001,10 @@
 nit)
+)
 ;
-%0A%09%09%7D);%0A%09%09%09
 %0A%09%7D%0A
@@ -2474,10 +2474,673 @@
 der)
+%0A%09%09%09%09.thenApply(d -%3E %7B%0A                    if (d != null) %7B%0A                        if (d %3C minValue) %7B%0A                            LOGGER.warn(%22Detected value out of range %22 + d%0A%09%09%09%09%09%09%09%09%09+ %22. Returning min value instead. Characteristic %22 + this);%0A                            return minValue;%0A                        %7D%0A                        if (d %3E maxValue) %7B%0A%09%09%09%09%09%09%09LOGGER.warn(%22Detected value out of range %22 + d%0A%09%09%09%09%09%09%09%09%09+ %22. Returning max value instead. Characteristic %22 + this);%0A                            return maxValue;%0A                        %7D%0A                        return d;%0A                    %7D%0A                    return null;%0A                %7D)
 ;
- 
 %0A%09%7D%0A

Enforce that value is within range