/*
 * Copyright 2014 Open mHealth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.openmhealth.data.generator.service;

import org.openmhealth.data.generator.domain.TimestampedValueGroup;
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.springframework.beans.factory.annotation.Value;

import java.util.ArrayList;
import java.util.List;

import static java.time.OffsetDateTime.now;
import static java.util.UUID.randomUUID;
import static org.openmhealth.schema.domain.omh.DataPointModality.SENSED;


/**
 * @author Emerson Farrugia
 */
public abstract class AbstractDataPointGeneratorImpl<T extends Measure>
        implements DataPointGenerator<T> {

    @Value("${data.header.user-id}")
    private String userId;

    @Value("${data.header.acquisition-provenance.source-name:generator}")
    private String sourceName;


    @Override
    public Iterable<DataPoint<T>> generateDataPoints(Iterable<TimestampedValueGroup> valueGroups) {

        List<DataPoint<T>> dataPoints = new ArrayList<>();

        for (TimestampedValueGroup timestampedValueGroup : valueGroups) {
            dataPoints.add(newDataPoint(newMeasure(timestampedValueGroup)));
        }

        return dataPoints;
    }

    /**
     * @param valueGroup a group of values
     * @return a measure corresponding to the specified values
     */
    public abstract T newMeasure(TimestampedValueGroup valueGroup);

    /**
     * @param measure a measure
     * @return a data point corresponding to the specified measure
     */
    public DataPoint<T> newDataPoint(T measure) {

        DataPointAcquisitionProvenance acquisitionProvenance = new DataPointAcquisitionProvenance.Builder(sourceName)
                .setModality(SENSED)
                .setSourceCreationDateTime(now().minusMinutes(5))
                .build();

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

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

@@ -752,198 +752,9 @@
 omh.
-DataPoint;%0Aimport org.openmhealth.schema.domain.omh.DataPointAcquisitionProvenance;%0Aimport org.openmhealth.schema.domain.omh.DataPointHeader;%0Aimport org.openmhealth.schema.domain.omh.Measure
+*
 ;%0Aim
@@ -807,24 +807,57 @@
 ion.Value;%0A%0A
+import java.time.OffsetDateTime;%0A
 import java.
@@ -2105,24 +2105,1536 @@
 measure) %7B%0A%0A
+        OffsetDateTime creationDateTime = null;%0A        TimeInterval effectiveTimeInterval = measure.getEffectiveTimeFrame().getTimeInterval();%0A%0A        if (effectiveTimeInterval != null) %7B%0A            // set the creation date time to the end of the effective time interval%0A            if (effectiveTimeInterval.getEndDateTime() != null) %7B%0A                creationDateTime = effectiveTimeInterval.getEndDateTime();%0A            %7D%0A            else %7B%0A                if (effectiveTimeInterval.getDuration() != null) %7B%0A                    if (effectiveTimeInterval.getDuration().getTypedUnit() == DurationUnit.SECOND) %7B%0A                        creationDateTime = effectiveTimeInterval.getStartDateTime()%0A                                .plusSeconds(effectiveTimeInterval.getDuration().getValue().longValue());%0A                    %7D%0A                    else if (effectiveTimeInterval.getDuration().getTypedUnit() == DurationUnit.MINUTE) %7B%0A                        creationDateTime = effectiveTimeInterval.getStartDateTime()%0A                                .plusMinutes(effectiveTimeInterval.getDuration().getValue().longValue());%0A                    %7D%0A                    else %7B%0A                        throw new IllegalStateException(%22A creation date time can't be determined.%22);%0A                    %7D%0A                %7D%0A            %7D%0A        %7D%0A        else %7B%0A            // set the creation date time to the effective date time%0A            creationDateTime = measure.getEffectiveTimeFrame().getDateTime();%0A        %7D%0A%0A
         Data
@@ -3683,16 +3683,32 @@
 enance =
+%0A               
  new Dat
@@ -3755,16 +3755,24 @@
 ceName)%0A
+        
         
@@ -3812,24 +3812,32 @@
             
+        
 .setSourceCr
@@ -3882,32 +3882,40 @@
                 
+     
+   
 .build();%0A%0A     
@@ -3941,16 +3941,32 @@
 header =
+%0A               
  new Dat
@@ -4038,15 +4038,34 @@
 (), 
-now())%0A
+creationDateTime)%0A        
     
@@ -4137,24 +4137,32 @@
             
+        
 .setUserId(u
@@ -4168,16 +4168,24 @@
 userId)%0A
+        
         

Set the creation date time to the end of the effective time frame