package de.renew.navigator.vc;

import java.io.File;
import java.util.HashMap;

import org.apache.log4j.Logger;


/**
 * The abstract version control saves the used repository for a file in memory.
 *
 * @author Konstantin Simon Maria Moellers
 * @version 2015-10-19
 */
public abstract class AbstractVersionControl implements VersionControl {

    /**
     * Log4j logger instance.
     */
    public static final Logger LOGGER = Logger.getLogger(AbstractVersionControl.class);
    private static final HashMap<File, Repository> REPOSITORIES;
    private static final String BELONGS_NOT_TO = " belongs not to ";


    static {
        REPOSITORIES = new HashMap<>();
    }

    @Override
    public final boolean controls(File fileInRepository) {
        return REPOSITORIES.containsKey(fileInRepository)
            || findRepository(fileInRepository) != null;
    }

    @Override
    public final Repository findRepository(File fileInRepository) {
        // Load cached variant for this exact file.
        if (REPOSITORIES.containsKey(fileInRepository)) {
            return REPOSITORIES.get(fileInRepository);
        }

        File rootDirectory = findRootDirectory(fileInRepository);
        if (rootDirectory == null) {
            LOGGER.warn(fileInRepository + BELONGS_NOT_TO + getName());
            return null;
        }
        // Load cached variant of the root directory.
        if (REPOSITORIES.containsKey(rootDirectory)) {
            Repository repository = REPOSITORIES.get(rootDirectory);
            REPOSITORIES.put(fileInRepository, repository);
            return repository;
        }

        final Repository repository = buildRepository(fileInRepository);

        if (repository == null) {
            LOGGER.warn(fileInRepository + BELONGS_NOT_TO + getName());
            return null;
        }

        // Cache the repository.
        REPOSITORIES.put(fileInRepository, repository);
        REPOSITORIES.put(repository.getRootDirectory(), repository);
        LOGGER.debug("Found " + fileInRepository + ", belongs to " + getName());

        return repository;
    }

    @Override
    public String getName() {
        final String simpleName = getClass().getSimpleName();

        final int index = simpleName.indexOf("VersionControl");
        return index == -1 ? simpleName : simpleName.substring(0, index);
    }

    /**
     * Returns the root directory of a repository for a file in that repository.
     *
     * @param fileInRepository The file in the repository
     * @return the root directory of the repository, <code>null</code> if the file is not in a repository
     */
    protected abstract File findRootDirectory(File fileInRepository);

    protected abstract Repository buildRepository(File fileInRepository);


    /**
     * Displays an error for a given exception.
     *
     * @param exception the exception to display.
     * @param action the action to display.
     */
    protected void errorException(Exception exception, String action) {
        LOGGER.error("Error while " + action, exception);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(getClass().getSimpleName() + ": " + exception);
        }
    }
}