<commit_before>package org.openmhealth.shim.ihealth;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.openmhealth.shim.*;
import org.openmhealth.shim.ihealth.mapper.*;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.SerializationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.URI;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;
import static org.slf4j.LoggerFactory.getLogger;


/**
 * Encapsulates parameters specific to the iHealth REST API and processes requests made of shimmer for iHealth data.
 *
 * @author <NAME>
 * @author <NAME>
 */
@Component
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "openmhealth.shim.ihealth")
public class IHealthShim extends OAuth2ShimBase {

    public static final String SHIM_KEY = "ihealth";

    private static final String API_URL = "https://api.ihealthlabs.com:8443/openapiv2/";

    private static final String AUTHORIZE_URL = "https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/";

    private static final String TOKEN_URL = AUTHORIZE_URL;

    public static final List<String> IHEALTH_SCOPES = Arrays.asList("OpenApiActivity", "OpenApiBP", "OpenApiSleep",
            "OpenApiWeight", "OpenApiBG", "OpenApiSpO2", "OpenApiUserInfo", "OpenApiFood", "OpenApiSport");

    private static final Logger logger = getLogger(IHealthShim.class);

    @Autowired
    public IHealthShim(ApplicationAccessParametersRepo applicationParametersRepo,
            AuthorizationRequestParametersRepo authorizationRequestParametersRepo,
            AccessParametersRepo accessParametersRepo,
            ShimServerConfig shimServerConfig) {
        super(applicationParametersRepo, authorizationRequestParametersRepo, accessParametersRepo, shimServerConfig);
    }

    @Override
    public String getLabel() {
        return "iHealth";
    }

    @Override
    public String getShimKey() {
        return SHIM_KEY;
    }

    @Override
    public String getBaseAuthorizeUrl() {
        return AUTHORIZE_URL;
    }

    @Override
    public String getBaseTokenUrl() {
        return TOKEN_URL;
    }

    @Override
    public List<String> getScopes() {
        return IHEALTH_SCOPES;
    }

    @Override
    public AuthorizationCodeAccessTokenProvider getAuthorizationCodeAccessTokenProvider() {
        return new IHealthAuthorizationCodeAccessTokenProvider();
    }

    @Override
    public ShimDataType[] getShimDataTypes() {
        return new ShimDataType[] {
                IHealthDataTypes.PHYSICAL_ACTIVITY,
                IHealthDataTypes.BLOOD_GLUCOSE,
                IHealthDataTypes.BLOOD_PRESSURE,
                IHealthDataTypes.BODY_WEIGHT,
                IHealthDataTypes.BODY_MASS_INDEX,
                IHealthDataTypes.HEART_RATE,
                IHealthDataTypes.STEP_COUNT,
                IHealthDataTypes.SLEEP_DURATION
        };
    }

    /**
     * Map of values auto-configured from the application properties yaml.
     */
    Map<String, String> serialValues;

    public Map<String, String> getSerialValues() {

        return serialValues;
    }

    public void setSerialValues(Map<String, String> serialValues) {

        this.serialValues = serialValues;
    }

    public enum IHealthDataTypes implements ShimDataType {

        PHYSICAL_ACTIVITY(singletonList("sport.json")),
        BLOOD_GLUCOSE(singletonList("glucose.json")),
        BLOOD_PRESSURE(singletonList("bp.json")),
        BODY_WEIGHT(singletonList("weight.json")),
        BODY_MASS_INDEX(singletonList("weight.json")),
        HEART_RATE(Lists.newArrayList("bp.json", "spo2.json")),
        STEP_COUNT(singletonList("activity.json")),
        SLEEP_DURATION(singletonList("sleep.json"));

        private List<String> endPoint;

        IHealthDataTypes(List<String> endPoint) {

            this.endPoint = endPoint;
        }

        public List<String> getEndPoint() {
            return endPoint;
        }

    }

    @Override
    protected ResponseEntity<ShimDataResponse> getData(OAuth2RestOperations restTemplate,
            ShimDataRequest shimDataRequest) throws ShimException {

        final IHealthDataTypes dataType;
        try {
            dataType = IHealthDataTypes.valueOf(
                    shimDataRequest.getDataTypeKey().trim().toUpperCase());
        }
        catch (NullPointerException | IllegalArgumentException e) {
            throw new ShimException("Null or Invalid data type parameter: "
                    + shimDataRequest.getDataTypeKey()
                    + " in shimDataRequest, cannot retrieve data.");
        }

        OffsetDateTime now = OffsetDateTime.now();
        OffsetDateTime startDate = shimDataRequest.getStartDateTime() == null ?
                now.minusDays(1) : shimDataRequest.getStartDateTime();
        OffsetDateTime endDate = shimDataRequest.getEndDateTime() == null ?
                now.plusDays(1) : shimDataRequest.getEndDateTime();


        // SC and SV values are client-based keys that are unique to each endpoint within a project
        String scValue = getScValue();
        List<String> svValues = getSvValues(dataType);

        List<JsonNode> responseEntities = Lists.newArrayList();<commit_msg>Fix dates for physical activity request from iHealth<commit_after>package org.openmhealth.shim.ihealth;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.openmhealth.shim.*;
import org.openmhealth.shim.ihealth.mapper.*;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.SerializationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.URI;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;
import static org.openmhealth.shim.ihealth.IHealthShim.IHealthDataTypes.*;
import static org.slf4j.LoggerFactory.getLogger;


/**
 * Encapsulates parameters specific to the iHealth REST API and processes requests made of shimmer for iHealth data.
 *
 * @author <NAME>
 * @author <NAME>
 */
@Component
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "openmhealth.shim.ihealth")
public class IHealthShim extends OAuth2ShimBase {

    public static final String SHIM_KEY = "ihealth";

    private static final String API_URL = "https://api.ihealthlabs.com:8443/openapiv2/";

    private static final String AUTHORIZE_URL = "https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/";

    private static final String TOKEN_URL = AUTHORIZE_URL;

    public static final List<String> IHEALTH_SCOPES = Arrays.asList("OpenApiActivity", "OpenApiBP", "OpenApiSleep",
            "OpenApiWeight", "OpenApiBG", "OpenApiSpO2", "OpenApiUserInfo", "OpenApiFood", "OpenApiSport");

    private static final Logger logger = getLogger(IHealthShim.class);

    @Autowired
    public IHealthShim(ApplicationAccessParametersRepo applicationParametersRepo,
            AuthorizationRequestParametersRepo authorizationRequestParametersRepo,
            AccessParametersRepo accessParametersRepo,
            ShimServerConfig shimServerConfig) {
        super(applicationParametersRepo, authorizationRequestParametersRepo, accessParametersRepo, shimServerConfig);
    }

    @Override
    public String getLabel() {
        return "iHealth";
    }

    @Override
    public String getShimKey() {
        return SHIM_KEY;
    }

    @Override
    public String getBaseAuthorizeUrl() {
        return AUTHORIZE_URL;
    }

    @Override
    public String getBaseTokenUrl() {
        return TOKEN_URL;
    }

    @Override
    public List<String> getScopes() {
        return IHEALTH_SCOPES;
    }

    @Override
    public AuthorizationCodeAccessTokenProvider getAuthorizationCodeAccessTokenProvider() {
        return new IHealthAuthorizationCodeAccessTokenProvider();
    }

    @Override
    public ShimDataType[] getShimDataTypes() {
        return new ShimDataType[] {
                PHYSICAL_ACTIVITY,
                BLOOD_GLUCOSE,
                BLOOD_PRESSURE,
                BODY_WEIGHT,
                BODY_MASS_INDEX,
                HEART_RATE,
                STEP_COUNT,
                SLEEP_DURATION
        };
    }

    /**
     * Map of values auto-configured from the application.yaml.
     */
    Map<String, String> serialValues;

    public Map<String, String> getSerialValues() {

        return serialValues;
    }

    public void setSerialValues(Map<String, String> serialValues) {

        this.serialValues = serialValues;
    }

    public enum IHealthDataTypes implements ShimDataType {

        PHYSICAL_ACTIVITY(singletonList("sport.json")),
        BLOOD_GLUCOSE(singletonList("glucose.json")),
        BLOOD_PRESSURE(singletonList("bp.json")),
        BODY_WEIGHT(singletonList("weight.json")),
        BODY_MASS_INDEX(singletonList("weight.json")),
        HEART_RATE(Lists.newArrayList("bp.json", "spo2.json")),
        STEP_COUNT(singletonList("activity.json")),
        SLEEP_DURATION(singletonList("sleep.json"));

        private List<String> endPoint;

        IHealthDataTypes(List<String> endPoint) {

            this.endPoint = endPoint;
        }

        public List<String> getEndPoint() {
            return endPoint;
        }

    }

    @Override
    protected ResponseEntity<ShimDataResponse> getData(OAuth2RestOperations restTemplate,
            ShimDataRequest shimDataRequest) throws ShimException {

        final IHealthDataTypes dataType;
        try {
            dataType = valueOf(
                    shimDataRequest.getDataTypeKey().trim().toUpperCase());
        }
        catch (NullPointerException | IllegalArgumentException e) {
            throw new ShimException("Null or Invalid data type parameter: "
                    + shimDataRequest.getDataTypeKey()
                    + " in shimDataRequest, cannot retrieve data.");
        }

        OffsetDateTime now = OffsetDateTime.now();
        OffsetDateTime startDate = shimDataRequest.getStartDateTime() == null ?
                now.minusDays(1) : shimDataRequest.getStartDateTime();
        OffsetDateTime endDate = shimDataRequest.getEndDateTime() == null ?
                now.plusDays(1) : shimDataRequest.getEndDateTime();

        /*
            The physical activity point handles start and end datetimes differently than the other endpoints. It
            requires use to include the range until the beginning of the next day.
         */
        if (dataType == PHYSICAL_ACTIVITY) {

            endDate = endDate.plusDays(1);
        }

        // SC and SV values are client-based keys that are unique to each endpoint within a project
        String scValue = getScValue();
        List<String> svValues = getSvValues(dataType);

        List<JsonNode> responseEntities = Lists.newArrayList();
{'fraction_non_alphanumeric': 0.08635002721829069, 'fraction_numerical': 0.0049673380511703865, 'mean_word_length': 3.730286449951722, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1566749', 'n_tokens_mistral': 4124, 'n_tokens_neox': 3972, 'n_words': 752}