package com.smoothcsv.core.csv;

import com.smoothcsv.commons.exception.UnexpectedException;
import com.smoothcsv.commons.utils.FileUtils;
import com.smoothcsv.framework.util.DigestUtils;
import com.smoothcsv.framework.util.DirectoryResolver;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author kohii
 */
@Slf4j
public class FileBackupService {

  @Getter
  private static FileBackupService instance = new FileBackupService();

  private static ExecutorService executor = new ThreadPoolExecutor(1, 30, 0L, TimeUnit.MILLISECONDS,
      new LinkedBlockingQueue<>());

  public File backup(File file, boolean copy) {
    try {
      File backupFile = createBackupFile(file, file.lastModified());
      if (backupFile.exists()) {
        return backupFile;
      }

      if (copy) {
        Files.copy(file.toPath(), backupFile.toPath());
      } else {
        if (!file.renameTo(backupFile)) {
          return null;
        }
      }

      // Delete the backup if it's same as last backup (Async)
      // FIXME don't block!
      executor.submit(new Runnable() {
        @Override
        public void run() {
          File dir = getBackupFileDirectory(file);
          File lastBackupFile = FileUtils.getLatestFileFromDir(dir, backupFile);
          if (lastBackupFile == null) {
            return;
          }
          try {
            if (org.apache.commons.io.FileUtils.contentEquals(lastBackupFile, backupFile)) {
              backupFile.delete();
            }
          } catch (IOException e) {
            log.error("", e);
          }
        }
      });
      return backupFile;
    } catch (Exception e) {
      log.error("", e);
      return null;
    }
  }

  public File getLastBackup(File file) {
    File dir = getBackupFileDirectory(file);
    return FileUtils.getLatestFileFromDir(dir);
  }

  private File createBackupFile(File file, long lastModified) {
    File dir = getBackupFileDirectory(file);
    String backupFileName = String.valueOf(lastModified);
    return new File(dir, backupFileName);
  }

  private File getBackupFileDirectory(File file) {
    String path = FileUtils.getCanonicalPath(file);
    String hash;
    try {
      hash = DigestUtils.md5Hex(path);
    } catch (NoSuchAlgorithmException e) {
      throw new UnexpectedException(e);
    }
    File dir = DirectoryResolver.instance().getBackupDirectory();
    dir = new File(dir, hash);
    if (!dir.exists()) {
      FileUtils.ensureDirectoryExists(dir);
    }
    return dir;
  }
}

@@ -420,188 +420,8 @@
 ion;
-%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.LinkedBlockingQueue;%0Aimport java.util.concurrent.ThreadPoolExecutor;%0Aimport java.util.concurrent.TimeUnit;
 %0A%0A/*
@@ -580,133 +580,36 @@
 ate 
-static ExecutorService executor = new ThreadPoolExecutor(1, 30, 0L, TimeUnit.MILLISECONDS,%0A      new LinkedBlockingQueue%3C%3E())
+Thread deleteDuplicateThread
 ;%0A%0A 
@@ -972,24 +972,151 @@
  %7D%0A      %7D%0A%0A
+      synchronized (this) %7B%0A%0A        if (deleteDuplicateThread != null) %7B%0A          deleteDuplicateThread.join();%0A        %7D%0A%0A  
       // Del
@@ -1176,51 +1176,44 @@
     
-// FIXME don't block!%0A      executor.submit
+  deleteDuplicateThread = new Thread
 (new
@@ -1222,24 +1222,26 @@
 unnable() %7B%0A
+  
         @Ove
@@ -1254,16 +1254,18 @@
         
+  
 public v
@@ -1272,24 +1272,26 @@
 oid run() %7B%0A
+  
           Fi
@@ -1335,24 +1335,26 @@
 ;%0A          
+  
 File lastBac
@@ -1418,24 +1418,26 @@
 ;%0A          
+  
 if (lastBack
@@ -1470,16 +1470,18 @@
     
+  
 return;%0A
     
@@ -1476,16 +1476,18 @@
 return;%0A
+  
         
@@ -1496,30 +1496,34 @@
 %7D%0A          
+  
 try %7B%0A
+  
             
@@ -1617,16 +1617,18 @@
         
+  
 backupFi
@@ -1644,32 +1644,34 @@
 ();%0A            
+  
 %7D%0A          %7D ca
@@ -1662,24 +1662,26 @@
 %7D%0A          
+ 
+ 
 %7D catch (IOE
@@ -1702,24 +1702,26 @@
             
+  
 log.error(%22%22
@@ -1728,34 +1728,38 @@
 , e);%0A          
+ 
+ 
 %7D%0A
+  
         %7D%0A      
@@ -1762,12 +1762,62 @@
     
+ 
+ 
 %7D);%0A
+        deleteDuplicateThread.start();%0A      %7D%0A%0A
     

Simplify async delete