package org.openmhealth.shim.withings.mapper;

import org.openmhealth.schema.domain.omh.DataPoint;
import org.openmhealth.schema.domain.omh.DataPointAcquisitionProvenance;
import org.openmhealth.schema.domain.omh.DataPointHeader;
import org.openmhealth.schema.domain.omh.Measure;
import org.openmhealth.shim.common.mapper.JsonNodeDataPointMapper;

import java.util.UUID;

import static org.openmhealth.schema.domain.omh.DataPointModality.SELF_REPORTED;
import static org.openmhealth.schema.domain.omh.DataPointModality.SENSED;


/**
 * @author Chris Schaefbauer
 */
public abstract class WithingsDataPointMapper<T> implements JsonNodeDataPointMapper<T> {

    protected final static String TIME_ZONE_PROPERTY = "timezone";
    public final static String RESOURCE_API_SOURCE_NAME = "Withings Resource API";
    protected static final String BODY_NODE_PROPERTY = "body";

    /**
     * Creates a {@link DataPoint} from a measure, and its meta-information, generated from a Withings measure specific
     * {@link WithingsDataPointMapper}
     *
     * @param <T> the {@link Measure} type
     * @param measure {@link Measure} of type T, generated through a measure specific data point mapper
     * @param externalId the external id from the Withings API Response, can be null if the corresponding property is
     * missing from the Withings response
     * @param sensed a boolean indicating whether the datapoint was sensed by a device for now, can be null if the
     * corresponding property is missing from the Withings response
     * @param deviceName the name of the Withings device that generated the data point, can be null if the corresponding
     * property is missing from the Withings response
     * @return a datapoint
     */
    protected <T extends Measure> DataPoint<T> newDataPoint(T measure, Long externalId,
            Boolean sensed, String deviceName) {

        DataPointAcquisitionProvenance.Builder provenanceBuilder =
                new DataPointAcquisitionProvenance.Builder(RESOURCE_API_SOURCE_NAME);

        if (sensed != null) {
            if (sensed) {
                provenanceBuilder.setModality(SENSED);
            }
            else {
                provenanceBuilder.setModality(SELF_REPORTED);
            }
        }

        DataPointAcquisitionProvenance acquisitionProvenance = provenanceBuilder.build();
        if (deviceName != null) {
            acquisitionProvenance.setAdditionalProperty("device_name", deviceName);
        }

        // TODO discuss the name of the external identifier, to make it clear it's the ID used by the source
        if (externalId != null) {
            acquisitionProvenance.setAdditionalProperty("external_id", externalId);
        }

        DataPointHeader header = new DataPointHeader.Builder(UUID.randomUUID().toString(), measure.getSchemaId())
                .setAcquisitionProvenance(acquisitionProvenance)
                .build();

        return new DataPoint<>(header, measure);
    }

}

@@ -348,16 +348,23 @@
 %0Aimport 
+static 
 java.uti
@@ -369,18 +369,28 @@
 til.UUID
+.randomUUID
 ;
-%0A
 %0Aimport 
@@ -670,75 +670,8 @@
  %7B%0A%0A
-    protected final static String TIME_ZONE_PROPERTY = %22timezone%22;%0A
     
@@ -749,16 +749,83 @@
 e API%22;%0A
+    protected final static String TIME_ZONE_PROPERTY = %22timezone%22;%0A
     prot
@@ -895,17 +895,43 @@
 %0A     * 
-C
+A convenience method that c
 reates a
@@ -963,17 +963,16 @@
  measure
-,
  and its
@@ -980,417 +980,126 @@
 meta
--information, generated from a Withings measure specific%0A     * %7B@link WithingsDataPointMapper%7D%0A     *%0A     * @param %3CT%3E the %7B@link Measure%7D type%0A     * @param measure %7B@link Measure%7D of type T, generated through a measure specific data point mapper%0A     * @param externalId the external id from the Withings API Response, can be null if the corresponding property is%0A     * missing from the Withings response
+data.%0A     *%0A     * @param measure a measure%0A     * @param externalId the Withings identifier of the measure, if known
 %0A   
@@ -1149,25 +1149,23 @@
 her the 
-datapoint
+measure
  was sen
@@ -1183,301 +1183,149 @@
 vice
- for now, can be null if the%0A     * corresponding property is missing from the Withings response%0A     * @param deviceName the name of the Withings device that generated the data point, can be null if the corresponding%0A     * property is missing from the Withings response%0A     * @return a
+, if known%0A     * @param deviceName the name of the Withings device that generated the measure, if known%0A     * @return the constructed
  data
+ 
 poin
@@ -1421,28 +1421,16 @@
 ernalId,
-%0A           
  Boolean
@@ -1437,16 +1437,28 @@
  sensed,
+%0A           
  String 
@@ -1672,126 +1672,8 @@
     
-if (sensed) %7B%0A                provenanceBuilder.setModality(SENSED);%0A            %7D%0A            else %7B%0A                
 prov
@@ -1698,16 +1698,34 @@
 odality(
+sensed ? SENSED : 
 SELF_REP
@@ -1744,24 +1744,72 @@
     
+%7D%0A%0A
     
-%7D%0A
     
-    %7D%0A
+// additional properties are always subject to change
 %0A   
@@ -1895,16 +1895,17 @@
 uild();%0A
+%0A
         
@@ -2017,32 +2017,70 @@
 me);%0A        %7D%0A%0A
+        if (externalId != null) %7B%0A    
         // TODO 
@@ -2176,42 +2176,8 @@
 rce%0A
-        if (externalId != null) %7B%0A
     
@@ -2328,21 +2328,16 @@
 Builder(
-UUID.
 randomUU
@@ -2523,11 +2523,10 @@
 ;%0A    %7D%0A
-%0A
 %7D%0A

Clean up documentation of the parent Withings data point mapper