package com.github.blindpirate.gogradle.core.pack;

import com.github.blindpirate.gogradle.core.GolangPackageModule;
import com.github.blindpirate.gogradle.core.cache.CacheManager;
import com.github.blindpirate.gogradle.core.dependency.GolangDependency;
import com.github.blindpirate.gogradle.util.IOUtils;
import java.util.Optional;

import javax.inject.Inject;
import java.nio.file.Path;
import java.util.concurrent.Callable;

public abstract class AbstractVcsResolver<REPOSITORY, VERSION> implements DependencyResolver {

    @Inject
    private CacheManager cacheManager;

    @Override
    public GolangPackageModule resolve(final GolangDependency dependency) {
        GolangPackageModule module
                = cacheManager.runWithGlobalCacheLock(dependency, new Callable<GolangPackageModule>() {
            @Override
            public GolangPackageModule call() {
                Path path = cacheManager.getGlobalCachePath(dependency.getName());
                return doResolve(dependency, path);
            }
        });

        module.getDependencies();
        return module;
    }

    private GolangPackageModule doResolve(GolangDependency dependency, Path path) {
        REPOSITORY repository = resolveToGlobalCache(dependency, path);
        VERSION version = determineVersion(repository, dependency);
        resetToSpecificVersion(repository, version);
        return createModule(dependency, path, repository, version);
    }

    protected abstract GolangPackageModule createModule(GolangDependency dependency,
                                                        Path path,
                                                        REPOSITORY repository,
                                                        VERSION version);

    protected abstract void resetToSpecificVersion(REPOSITORY repository, VERSION version);

    protected abstract VERSION determineVersion(REPOSITORY repository, GolangDependency dependency);

    private REPOSITORY resolveToGlobalCache(GolangDependency dependency, Path path) {
        Optional<REPOSITORY> repositoryInGlobalCache = ensureGlobalCacheEmptyOrMatch(dependency, path);
        if (!repositoryInGlobalCache.isPresent()) {
            return initRepository(dependency, path);
        } else {
            return updateRepository(repositoryInGlobalCache.get(), path);
        }
    }

    protected abstract REPOSITORY updateRepository(REPOSITORY repository, Path path);

    protected abstract REPOSITORY initRepository(GolangDependency dependency, Path path);


    private Optional<REPOSITORY> ensureGlobalCacheEmptyOrMatch(GolangDependency dependency, Path path) {
        if (IOUtils.dirIsEmpty(path)) {
            return Optional.empty();
        } else {
            Optional<REPOSITORY> ret = repositoryMatch(path, dependency);
            if (ret.isPresent()) {
                return ret;
            } else {
                throw new IllegalStateException("Existing cache directory "
                        + path.toAbsolutePath().toString()
                        + " does not match the dependency "
                        + dependency.getName());
            }
        }
    }

    /**
     * Checks if a non-empty directory matches the dependency.
     *
     * @param repoPath   the directory
     * @param dependency the dependency
     * @return
     */
    protected abstract Optional<REPOSITORY> repositoryMatch(Path repoPath, GolangDependency dependency);
}

@@ -300,16 +300,17 @@
 OUtils;%0A
+%0A
 import j
@@ -695,32 +695,16 @@
 e module
-%0A               
  = cache
@@ -750,120 +750,16 @@
 cy, 
-new Callable%3CGolangPackageModule%3E() %7B%0A            @Override%0A            public GolangPackageModule call() %7B%0A    
+() -%3E %7B%0A
     
@@ -841,28 +841,24 @@
             
-    
 return doRes
@@ -893,60 +893,12 @@
     
-    %7D%0A        %7D);%0A%0A        module.getDependencies();
+%7D);%0A
 %0A   

simplify to lambda expression