package org.openmhealth.shim.withings.mapper;

import com.fasterxml.jackson.databind.JsonNode;
import org.openmhealth.schema.domain.omh.*;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static java.time.ZoneId.of;
import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.*;


/**
 * Created by Chris Schaefbauer on 7/6/15.
 */
public class WithingsSleepDurationDataPointMapper extends WithingsListDataPointMapper<SleepDuration>{

    @Override
    Optional<DataPoint<SleepDuration>> asDataPoint(JsonNode node) {

        Long lightSleepInSeconds = asRequiredLong(node,"data.lightsleepduration");
        Long deepSleepInSeconds = asRequiredLong(node, "data.deepsleepduration");
        Long remSleepInSeconds = asRequiredLong(node, "data.remsleepduration");

        Long totalSleepInSeconds = lightSleepInSeconds+deepSleepInSeconds+remSleepInSeconds;

        SleepDuration.Builder sleepDurationBuilder = new SleepDuration.Builder(new DurationUnitValue(DurationUnit.SECOND,totalSleepInSeconds));


        Optional<Long> startDateInEpochSeconds = asOptionalLong(node, "startdate");
        Optional<Long> endDateInEpochSeconds = asOptionalLong(node, "enddate");
        Optional<String> timezone = asOptionalString(node, "timezone");
        if(startDateInEpochSeconds.isPresent()&&endDateInEpochSeconds.isPresent()&&timezone.isPresent()){
            OffsetDateTime offsetStartDateTime = OffsetDateTime.ofInstant(Instant.ofEpochSecond(startDateInEpochSeconds.get()),of(
                    timezone.get()));
            OffsetDateTime offsetEndDateTime = OffsetDateTime.ofInstant(Instant.ofEpochSecond(endDateInEpochSeconds.get()),of(timezone.get()));
            sleepDurationBuilder.setEffectiveTimeFrame(TimeInterval.ofStartDateTimeAndEndDateTime(offsetStartDateTime,offsetEndDateTime));
        }

        Optional<Long> externalId = asOptionalLong(node, "id");
        Optional<Long> modelId = asOptionalLong(node, "model");
        String modelName = null;

        if(modelId.isPresent()){
            modelName = SleepDeviceTypes.valueOf(modelId.get());
        }

        SleepDuration sleepDuration = sleepDurationBuilder.build();
        Optional<Long> wakeupCount = asOptionalLong(node, "data.wakeupcount");
        if(wakeupCount.isPresent()){
            sleepDuration.setAdditionalProperty("wakeup_count",new Integer(wakeupCount.get().intValue()));
        }

        return Optional.of(newDataPoint(sleepDuration,RESOURCE_API_SOURCE_NAME,externalId.orElse(null),true, modelName));
    }

    @Override
    String getListNodeName() {
        return "series";
    }

    public enum SleepDeviceTypes{
        Pulse(16), Aura(32);

        private long deviceId;

        private static Map<Long, String> map = new HashMap<Long, String>();

        static {
            for (SleepDeviceTypes sleepDeviceTypeName : SleepDeviceTypes.values()) {
                map.put(sleepDeviceTypeName.deviceId, sleepDeviceTypeName.name());
            }
        }

        private SleepDeviceTypes(final long deviceId) { this.deviceId = deviceId; }

        public static String valueOf(long deviceId) {
            return map.get(deviceId);
        }
    }
}

@@ -383,162 +383,846 @@
 *;%0A%0A
-%0A
 /**%0A * 
-Created by Chris Schaefbauer on 7/6/15.%0A */%0Apublic class WithingsSleepDurationDataPointMapper extends WithingsListDataPointMapper%3CSleepDuration%3E%7B%0A
+A mapper from Withings Sleep Summary endpoint responses (/sleep?action=getsummary) to %7B@link SleepDuration%7D%0A * objects%0A *%0A * @author Chris Schaefbauer%0A * @see %3Ca href=%22http://oauth.withings.com/api/doc#api-Measure-get_sleep_summary%22%3ESleep Summary API documentation%3C/a%3E%0A */%0Apublic class WithingsSleepDurationDataPointMapper extends WithingsListDataPointMapper%3CSleepDuration%3E%7B%0A%0A    /**%0A     * Maps an individual list node from the array in the Withings sleep summary endpoint response into a %7B@link%0A     * SleepDuration%7D data point%0A     *%0A     * @param node activity node from the array %22series%22 contained in the %22body%22 of the endpoint response%0A     * @return a %7B@link DataPoint%7D object containing a %7B@link SleepDuration%7D measure with the appropriate values from%0A     * the JSON node parameter, wrapped as an %7B@link Optional%7D%0A     */
 %0A   
@@ -3302,80 +3302,428 @@
     
-@Override%0A    String getListNodeName() %7B%0A        return %22series%22;%0A    %7D%0A
+/**%0A     * The list name for splitting out individual sleep summary items that can then be mapped.%0A     *%0A     * @return the name of the array containing the individual sleep summary nodes%0A     */%0A    @Override%0A    String getListNodeName() %7B%0A        return %22series%22;%0A    %7D%0A%0A    /**%0A     * Enum mapping the different sleep tracking device names to the integer value used by Withings to identify them in datapoints%0A     */
 %0A   
@@ -4183,24 +4183,280 @@
 eviceId; %7D%0A%0A
+        /**%0A         * Returns the string device name for a device ID%0A         * @param deviceId the id number for the device contained within the Withings API response datapoint%0A         * @return common name of the device (e.g., Pulse, Aura)%0A         */%0A
         publ

Document withings sleep duration mapper