/**
 * Copyright 2020 interactive instruments GmbH
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package de.ii.ldproxy.ogcapi.features.core.api;

import com.google.common.collect.ImmutableMap;
import de.ii.ldproxy.ogcapi.domain.FeatureTypeConfigurationOgcApi;
import de.ii.ldproxy.ogcapi.domain.ImmutableCollectionExtent;
import de.ii.ldproxy.ogcapi.domain.ImmutableFeatureTypeConfigurationOgcApi;
import de.ii.ldproxy.ogcapi.domain.ImmutableOgcApiApiDataV2;
import de.ii.ldproxy.ogcapi.domain.OgcApiApiDataV2;
import de.ii.ldproxy.ogcapi.domain.OgcApiDataHydratorExtension;
import de.ii.ldproxy.ogcapi.features.core.application.OgcApiFeaturesCoreConfiguration;
import de.ii.xtraplatform.crs.domain.BoundingBox;
import de.ii.xtraplatform.features.domain.FeatureProvider2;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;

import java.util.AbstractMap;
import java.util.Map;
import java.util.Optional;

@Component
@Provides
@Instantiate
public class OgcApiFeatureCoreDataHydrator implements OgcApiDataHydratorExtension {

    private final OgcApiFeatureCoreProviders providers;

    public OgcApiFeatureCoreDataHydrator(@Requires OgcApiFeatureCoreProviders providers) {
        this.providers = providers;
    }

    @Override
    public boolean isEnabledForApi(OgcApiApiDataV2 apiData) {
        return getExtensionConfiguration(apiData, OgcApiFeaturesCoreConfiguration.class).filter(OgcApiFeaturesCoreConfiguration::getEnabled)
                                                                                        .isPresent();
    }

    @Override
    public OgcApiApiDataV2 getHydratedData(OgcApiApiDataV2 apiData) {

        OgcApiApiDataV2 newData = apiData;

        if (hasMissingBboxes(apiData.getCollections())) {

            ImmutableMap<String, FeatureTypeConfigurationOgcApi> collectionsWithComputedBboxes = computeMissingBboxes(apiData);

            newData = new ImmutableOgcApiApiDataV2.Builder()
                    .from(newData)
                    .collections(collectionsWithComputedBboxes)
                    .build();
        }

        return newData;
    }

    private boolean hasMissingBboxes(Map<String, FeatureTypeConfigurationOgcApi> featureTypes) {
        return featureTypes
                .entrySet()
                .stream()
                .anyMatch(entry -> entry.getValue()
                                        .getExtent()
                                        .getSpatialComputed());
    }

    //TODO Test
    private ImmutableMap<String, FeatureTypeConfigurationOgcApi> computeMissingBboxes(
            OgcApiApiDataV2 apiData) throws IllegalStateException {


        return apiData.getCollections()
                      .entrySet()
                      .stream()
                      .map(entry -> {

                          FeatureProvider2 featureProvider = providers.getFeatureProvider(apiData, entry.getValue());

                          if (entry.getValue()
                                   .getExtent()
                                   .getSpatialComputed() && featureProvider.supportsExtents()) {
                              Optional<BoundingBox> spatialExtent = featureProvider.extents()
                                                                                   .getSpatialExtent(entry.getValue()
                                                                                                          .getId());

                              if (spatialExtent.isPresent()) {

                                  ImmutableFeatureTypeConfigurationOgcApi featureTypeConfiguration = new ImmutableFeatureTypeConfigurationOgcApi.Builder()
                                          .from(entry.getValue())
                                          .extent(new ImmutableCollectionExtent.Builder()
                                                  .from(entry.getValue()
                                                             .getExtent())
                                                  .spatial(spatialExtent.get())
                                                  .build())
                                          .build();


                                  return new AbstractMap.SimpleEntry<>(entry.getKey(), featureTypeConfiguration);
                              }
                          }
                          return entry;
                      })
                      .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
    }
}

@@ -388,353 +388,9 @@
 ain.
-FeatureTypeConfigurationOgcApi;%0Aimport de.ii.ldproxy.ogcapi.domain.ImmutableCollectionExtent;%0Aimport de.ii.ldproxy.ogcapi.domain.ImmutableFeatureTypeConfigurationOgcApi;%0Aimport de.ii.ldproxy.ogcapi.domain.ImmutableOgcApiApiDataV2;%0Aimport de.ii.ldproxy.ogcapi.domain.OgcApiApiDataV2;%0Aimport de.ii.ldproxy.ogcapi.domain.OgcApiDataHydratorExtension
+*
 ;%0Aim
@@ -511,27 +511,17 @@
 .domain.
-BoundingBox
+*
 ;%0Aimport
@@ -787,16 +787,57 @@
 uires;%0A%0A
+import javax.ws.rs.ServerErrorException;%0A
 import j
@@ -1082,16 +1082,79 @@
 oviders;
+%0A    private final CrsTransformerFactory crsTransformerFactory;
 %0A%0A    pu
@@ -1238,46 +1238,161 @@
 ders
-) %7B%0A        this.providers = providers
+, @Requires CrsTransformerFactory crsTransformerFactory) %7B%0A        this.providers = providers;%0A        this.crsTransformerFactory = crsTransformerFactory
 ;%0A  
@@ -3645,24 +3645,968 @@
 esent()) %7B%0A%0A
+                                  BoundingBox boundingBox = spatialExtent.get();%0A                                  if (!boundingBox.getEpsgCrs().equals(OgcCrs.CRS84))%7B%0A                                      try %7B%0A                                          Optional%3CCrsTransformer%3E transformer = crsTransformerFactory.getTransformer(boundingBox.getEpsgCrs(), OgcCrs.CRS84);%0A                                          if (transformer.isPresent()) %7B%0A                                              boundingBox = transformer.get().transformBoundingBox(boundingBox);%0A                                          %7D%0A                                      %7D catch (CrsTransformationException e) %7B%0A                                          throw new ServerErrorException(String.format(%22Error transforming the bounding box with CRS '%25s'%22, boundingBox.getEpsgCrs().toUriString()), 500);%0A                                      %7D%0A                                  %7D%0A%0A
             
@@ -5111,35 +5111,27 @@
 spatial(
-spatialExtent.get()
+boundingBox
 )%0A      
@@ -5237,17 +5237,16 @@
 ild();%0A%0A
-%0A
         

convert computed extents to CRS84