package com.lowtuna.jsonblob.core;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;
import com.google.common.base.Stopwatch;
import io.dropwizard.util.Duration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.DirectoryWalker;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.time.LocalDate;
import java.util.Collection;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * Created by tburch on 8/18/17.
 */
@Slf4j
public class BlobCleanupProducer extends DirectoryWalker<Void> implements Runnable {
  private final Path dataDirectoryPath;
  private final Duration blobAccessTtl;
  private final BlockingQueue<File> filesToProcess;

  public BlobCleanupProducer(Path dataDirectoryPath, Duration blobAccessTtl, BlockingQueue<File> filesToProcess, MetricRegistry metricRegistry) {
    this.dataDirectoryPath = dataDirectoryPath;
    this.blobAccessTtl = blobAccessTtl;
    this.filesToProcess = filesToProcess;
    metricRegistry.register(MetricRegistry.name(getClass(), "filesToProcessCount"), (Gauge<Integer>) () -> filesToProcess.size());
  }


  @Override
  protected boolean handleDirectory(File directory, int depth, Collection<Void> results) throws IOException {
    File[] files = directory.listFiles();

    if (files != null && files.length == 0) {
      if (directory.delete()) log.info("{} has no files, so it's being deleted", directory.getAbsolutePath());
      return false;
    }

    if (files.length == 1) {
      if (files[0].getName().startsWith(FileSystemJsonBlobManager.BLOB_METADATA_FILE_NAME)) {
        if (directory.delete()) log.info("{} has only a metadata file, so it's being deleted", directory.getAbsolutePath());
        return false;
      }
    }

    boolean process = true;
    if (isDataDir(directory.getAbsolutePath())) {
      String[] dateParts = directory.getAbsolutePath().replace(dataDirectoryPath.toFile().getAbsolutePath(), "").split("/", 4);
      LocalDate localDate = LocalDate.of(Integer.parseInt(dateParts[1]), Integer.parseInt(dateParts[2]), Integer.parseInt(dateParts[3]));
      process = localDate.isBefore(LocalDate.now().minusDays(blobAccessTtl.toDays()));
      if (process) {
        log.info("Processing {} blobs for un-accessed blobs", directory.getAbsolutePath());
        for (File file: files) {
          try {
            filesToProcess.put(file);
          } catch (InterruptedException e) {
            log.warn("Interrupted while trying to add file to be processed at {}", file.getAbsolutePath(), e);
          }
        }
        process = false;
      }
    }

    return process;
  }

  private boolean isDataDir(String path) {
    return path.replace(dataDirectoryPath.toFile().getAbsolutePath(), "").split("/").length == 4;
  }

  @Override
  public void run() {
    Stopwatch stopwatch = new Stopwatch().start();
    try {
      walk(dataDirectoryPath.toFile(), null);
      log.info("Completed cleaning up un-accessed blobs in {}ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

@@ -311,24 +311,52 @@
 OException;%0A
+import java.nio.file.Files;%0A
 import java.
@@ -1314,548 +1314,8 @@
 n %7B%0A
-    File%5B%5D files = directory.listFiles();%0A%0A    if (files != null && files.length == 0) %7B%0A      if (directory.delete()) log.info(%22%7B%7D has no files, so it's being deleted%22, directory.getAbsolutePath());%0A      return false;%0A    %7D%0A%0A    if (files.length == 1) %7B%0A      if (files%5B0%5D.getName().startsWith(FileSystemJsonBlobManager.BLOB_METADATA_FILE_NAME)) %7B%0A        if (directory.delete()) log.info(%22%7B%7D has only a metadata file, so it's being deleted%22, directory.getAbsolutePath());%0A        return false;%0A      %7D%0A    %7D%0A%0A    boolean process = true;%0A
     
@@ -1628,24 +1628,32 @@
 3%5D));%0A      
+boolean 
 process = lo
@@ -1846,33 +1846,291 @@
     
-for (File file: files) %7B%0A
+Files.newDirectoryStream(directory.toPath())%0A                .forEach(path -%3E %7B%0A                  File file = path.toFile();%0A                  if (file.getName().startsWith(FileSystemJsonBlobManager.BLOB_METADATA_FILE_NAME)) %7B%0A                    return;%0A                  %7D%0A        
     
@@ -2137,24 +2137,32 @@
       try %7B%0A
+        
             
@@ -2193,24 +2193,32 @@
 ;%0A          
+       
+ 
 %7D catch (Int
@@ -2236,24 +2236,32 @@
 eption e) %7B%0A
+        
             
@@ -2361,32 +2361,40 @@
 , e);%0A          
+       
+ 
 %7D%0A        %7D%0A    
@@ -2391,68 +2391,805 @@
     
+       
-%7D
+ %7D);
 %0A      
-  proces
+%7D%0A%0A      File%5B%5D files = directory.listFiles();%0A      if (file
 s 
+!
 = 
-false;%0A      %7D%0A    %7D%0A%0A    return process
+null && files.length == 1) %7B%0A        if (files%5B0%5D.getName().startsWith(FileSystemJsonBlobManager.BLOB_METADATA_FILE_NAME)) %7B%0A          if (directory.delete()) %7B%0A            log.info(%22%7B%7D has only a metadata file, so it's being deleted%22, directory.getAbsolutePath());%0A          %7D%0A        %7D%0A      %7D else if (files.length == 0) %7B%0A        log.info(%22%7B%7D has no files, so it's being deleted%22, directory.getAbsolutePath());%0A      %7D%0A      return false;%0A    %7D else %7B%0A      File%5B%5D files = directory.listFiles();%0A      if (files != null && files.length == 0) %7B%0A        if (directory.delete()) log.info(%22%7B%7D has no files, so it's being deleted%22, directory.getAbsolutePath());%0A        return false;%0A      %7D%0A    %7D%0A%0A    return true
 ;%0A  

Use a directory Stream