/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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 com.google.android.gnd.repository;

import static com.google.android.gnd.util.ImmutableListCollector.toImmutableList;
import static java8.util.stream.StreamSupport.stream;

import android.content.Context;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gnd.Config;
import com.google.android.gnd.model.basemap.OfflineArea;
import com.google.android.gnd.model.basemap.OfflineArea.State;
import com.google.android.gnd.model.basemap.tile.Tile;
import com.google.android.gnd.persistence.geojson.GeoJsonParser;
import com.google.android.gnd.persistence.local.LocalDataStore;
import com.google.android.gnd.persistence.uuid.OfflineUuidGenerator;
import com.google.android.gnd.workers.TileDownloadWorkManager;
import com.google.common.collect.ImmutableList;
import io.reactivex.Completable;
import java.io.File;
import javax.inject.Inject;
import timber.log.Timber;

public class OfflineAreaRepository {
  private final TileDownloadWorkManager tileDownloadWorkManager;
  private final LocalDataStore localDataStore;
  private final GeoJsonParser geoJsonParser;
  private final Context context;

  private static final String TAG = OfflineAreaRepository.class.getSimpleName();
  private final OfflineUuidGenerator uuidGenerator;

  @Inject
  public OfflineAreaRepository(
      TileDownloadWorkManager tileDownloadWorkManager,
      LocalDataStore localDataStore,
      GeoJsonParser geoJsonParser,
      Context context,
      OfflineUuidGenerator uuidGenerator) {
    this.tileDownloadWorkManager = tileDownloadWorkManager;
    this.localDataStore = localDataStore;
    this.geoJsonParser = geoJsonParser;
    this.context = context;
    this.uuidGenerator = uuidGenerator;
  }

  private Completable enqueueTileDownloads(OfflineArea area) {

    File jsonSource = new File(context.getFilesDir(), Config.GEO_JSON_SOURCE);

    ImmutableList<Tile> tiles = geoJsonParser.intersectingTiles(area.getBounds(), jsonSource);

    return localDataStore
        .insertOrUpdateOfflineArea(area.toBuilder().setState(State.IN_PROGRESS).build())
        .andThen(
            Completable.merge(
                stream(tiles.asList())
                    .map(localDataStore::insertOrUpdateTile)
                    .collect(toImmutableList())))
        .doOnError(__ -> Timber.d("failed to add/update a tile in the database"))
        .andThen(tileDownloadWorkManager.enqueueTileDownloadWorker());
  }

  public Completable addAreaAndEnqueue(LatLngBounds viewport) {
    OfflineArea offlineArea =
        OfflineArea.newBuilder()
            .setBounds(viewport)
            .setId(uuidGenerator.generateUuid())
            .setState(State.PENDING)
            .build();

    return localDataStore
        .insertOrUpdateOfflineArea(offlineArea)
        .doOnError(__ -> Timber.d("failed to add/update offline area in the database"))
        .andThen(enqueueTileDownloads(offlineArea));
  }
}

@@ -1268,16 +1268,64 @@
 erator;%0A
+import com.google.android.gnd.ui.util.FileUtil;%0A
 import c
@@ -1477,24 +1477,62 @@
 va.io.File;%0A
+import java.io.FileNotFoundException;%0A
 import javax
@@ -1788,106 +1788,27 @@
 nal 
-Context context;%0A%0A  private static final String TAG = OfflineAreaRepository.class.getSimpleName();
+FileUtil fileUtil;%0A
 %0A  p
@@ -2030,31 +2030,8 @@
 er,%0A
-      Context context,%0A
     
@@ -2066,16 +2066,41 @@
 enerator
+,%0A      FileUtil fileUtil
 ) %7B%0A    
@@ -2241,36 +2241,8 @@
 er;%0A
-    this.context = context;%0A
     
@@ -2277,16 +2277,46 @@
 erator;%0A
+    this.fileUtil = fileUtil;%0A
   %7D%0A%0A  p
@@ -2375,17 +2375,28 @@
 area) %7B%0A
-%0A
+    try %7B%0A  
     File
@@ -2413,40 +2413,25 @@
 e = 
-new File(context.getFilesDir(), 
+fileUtil.getFile(
 Conf
@@ -2448,24 +2448,26 @@
 N_SOURCE);%0A%0A
+  
     Immutabl
@@ -2546,32 +2546,34 @@
 onSource);%0A%0A    
+ 
+ 
 return localData
@@ -2570,32 +2570,34 @@
  localDataStore%0A
+  
         .insertO
@@ -2665,24 +2665,26 @@
 S).build())%0A
+  
         .and
@@ -2701,16 +2701,18 @@
         
+  
 Completa
@@ -2722,16 +2722,18 @@
 .merge(%0A
+  
         
@@ -2783,16 +2783,18 @@
         
+ 
+ 
 .map(loc
@@ -2846,16 +2846,18 @@
         
+  
 .collect
@@ -2878,16 +2878,18 @@
 st())))%0A
+  
         
@@ -2962,32 +2962,34 @@
 base%22))%0A        
+  
 .andThen(tileDow
@@ -3031,24 +3031,105 @@
 dWorker());%0A
+    %7D catch (FileNotFoundException e) %7B%0A      return Completable.error(e);%0A    %7D%0A
   %7D%0A%0A  publi
@@ -3173,24 +3173,22 @@
 gBounds 
-viewport
+bounds
 ) %7B%0A    
@@ -3273,16 +3273,14 @@
 nds(
-viewport
+bounds
 )%0A  
@@ -3484,33 +3484,33 @@
 or(__ -%3E Timber.
-d
+e
 (%22failed to add/

Improve OfflineAreaRepository Code Health