package uk.ac.ic.wlgitbridge.bridge.repo;

import com.google.api.client.repackaged.com.google.common.base.Preconditions;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import uk.ac.ic.wlgitbridge.util.Log;
import uk.ac.ic.wlgitbridge.util.Project;
import uk.ac.ic.wlgitbridge.util.Tar;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import static uk.ac.ic.wlgitbridge.util.Util.deleteInDirectoryApartFrom;

/**
 * Created by winston on 20/08/2016.
 */
public class FSGitRepoStore implements RepoStore {

    private static final long DEFAULT_MAX_FILE_SIZE = 50 * 1024 * 1024;

    private final String repoStorePath;

    private final File rootDirectory;

    private final long maxFileSize;

    private final Function<File, Long> fsSizer;

    public FSGitRepoStore(
            String repoStorePath,
            Optional<Long> maxFileSize
    ) {
        this(
                repoStorePath,
                maxFileSize.orElse(DEFAULT_MAX_FILE_SIZE),
                d -> d.getTotalSpace() - d.getFreeSpace()
        );
    }

    public FSGitRepoStore(
            String repoStorePath,
            long maxFileSize,
            Function<File, Long> fsSizer
    ) {
        this.repoStorePath = repoStorePath;
        rootDirectory = initRootGitDirectory(repoStorePath);
        this.maxFileSize = maxFileSize;
        this.fsSizer = fsSizer;
    }

    @Override
    public String getRepoStorePath() {
        return repoStorePath;
    }

    @Override
    public File getRootDirectory() {
        return rootDirectory;
    }

    @Override
    public ProjectRepo initRepo(String project) throws IOException {
        GitProjectRepo ret = GitProjectRepo.fromName(project);
        ret.initRepo(this);
        return new WalkOverrideGitRepo(
                ret, Optional.of(maxFileSize), Optional.empty());
    }

     @Override
     public ProjectRepo initRepoFromExisting(
             String project, String fromProject
     ) throws IOException {
         GitProjectRepo ret = GitProjectRepo.fromName(project);
         ret.initRepo(this);
         String repoRoot = getRepoStorePath();
         String sourcePath = repoRoot + "/" + fromProject;
         String destinationPath = repoRoot + "/" + project;
         Log.info("[{}] Init repo by copying data from: {}, to: {}",
             project,
             sourcePath,
             destinationPath
         );
         new ProcessBuilder(
                 "rm", "-rf",
                 destinationPath
         ).start();
         Process copyProcess = new ProcessBuilder(
                 "cp", "-ra",
                 sourcePath,
                 destinationPath + "/"
         ).start();
         try {
             copyProcess.waitFor();
         } catch (InterruptedException e) {
             e.printStackTrace();
             throw new IOException("copy failed" + e.getLocalizedMessage());
         }
         return new WalkOverrideGitRepo(
                 ret, Optional.of(maxFileSize), Optional.empty());
     }

    @Override
    public ProjectRepo getExistingRepo(String project) throws IOException {
        GitProjectRepo ret = GitProjectRepo.fromName(project);
        ret.useExistingRepository(this);
        return new WalkOverrideGitRepo(
                ret, Optional.of(maxFileSize), Optional.empty());
    }

    @Override
    public ProjectRepo useJGitRepo(Repository repo, ObjectId commitId) {
        GitProjectRepo ret = GitProjectRepo.fromJGitRepo(repo);
        return new WalkOverrideGitRepo(
                ret, Optional.of(maxFileSize), Optional.of(commitId));
    }

    /* TODO: Perhaps we should just delete bad directories on the fly. */
    @Override
    public void purgeNonexistentProjects(
            Collection<String> existingProjectNames
    ) {
        List<String> excludedFromDeletion =
                new ArrayList<>(existingProjectNames);
        excludedFromDeletion.add(".wlgb");
        deleteInDirectoryApartFrom(
                rootDirectory,
                excludedFromDeletion.toArray(new String[] {})
        );
    }

    @Override
    public long totalSize() {
        return fsSizer.apply(rootDirectory);
    }

    @Override
    public InputStream bzip2Project(
            String projectName,
            long[] sizePtr
    ) throws IOException {
        Project.checkValidProjectName(projectName);
        return Tar.bz2.zip(getDotGitForProject(projectName), sizePtr);
    }

    @Override
    public void remove(String projectName) throws IOException {
        Project.checkValidProjectName(projectName);
        FileUtils.deleteDirectory(new File(rootDirectory, projectName));
    }

    @Override
    public void unbzip2Project(
            String projectName,
            InputStream dataStream
    ) throws IOException {
        Preconditions.checkArgument(
                Project.isValidProjectName(projectName),
                "[%s] invalid project name: ",
                projectName
        );
        Preconditions.checkState(
                getDirForProject(projectName).mkdirs(),
                "[%s] directories for " +
                        "evicted project already exist",
                projectName
        );
        Tar.bz2.unzip(dataStream, getDirForProject(projectName));
    }

    private File getDirForProject(String projectName) {
        Project.checkValidProjectName(projectName);
        return Paths.get(
                rootDirectory.getAbsolutePath()
        ).resolve(
                projectName
        ).toFile();
    }

    private File getDotGitForProject(String projectName) {
        Project.checkValidProjectName(projectName);
        return Paths.get(
                rootDirectory.getAbsolutePath()
        ).resolve(
                projectName
        ).resolve(
                ".git"
        ).toFile();
    }

    private File initRootGitDirectory(String rootGitDirectoryPath) {
        File rootGitDirectory = new File(rootGitDirectoryPath);
        rootGitDirectory.mkdirs();
        Preconditions.checkArgument(
                rootGitDirectory.isDirectory(),
                "given root git directory " +
                        "is not a directory: %s",
                rootGitDirectory.getAbsolutePath()
        );
        return rootGitDirectory;
    }

}

@@ -2653,209 +2653,50 @@
     
-new ProcessBuilder(%0A                 %22rm%22, %22-rf%22,%0A                 destinationPath%0A         ).start();%0A         Process copyProcess = new ProcessBuilder(%0A                 %22cp%22, %22-ra%22,%0A                 
+try %7B%0A             File source = new File(
 sour
@@ -2693,33 +2693,34 @@
  File(sourcePath
-,
+);
 %0A               
@@ -2709,36 +2709,60 @@
 );%0A             
-    
+File destination = new File(
 destinationPath 
@@ -2764,15 +2764,15 @@
 Path
- + %22/%22%0A
+);%0A    
     
@@ -2780,67 +2780,104 @@
     
-).start();%0A         try %7B%0A             copyProcess.waitFor(
+FileUtils.deleteDirectory(destination);%0A             FileUtils.copyDirectory(source, destination
 );%0A 
@@ -2897,19 +2897,8 @@
 ch (
-Interrupted
 Exce

Use FileUtils to handle copying of migrated repository