package com.atlassian.stash.internal.process;

import com.atlassian.stash.internal.ApplicationSettings;
import com.atlassian.utils.process.*;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 * A configurable version of {@link DefaultExternalProcessFactory} which applies standard settings to all processes
 * before they are returned, enforcing consistent behaviour for settings we wish to apply application-wide.
 */
public class ExtendedExternalProcessFactory extends ConfigurableExternalProcessFactory {

    private final ApplicationSettings settings;

    public ExtendedExternalProcessFactory(ExecutorService executorService, ApplicationSettings settings) {
        super(executorService);

        this.settings = settings;
    }

    /**
     * Sets this {@code ExternalProcessFactory} as the one which should be used by {@code ExternalProcessBuilder} when
     * {@code ExternalProcessBuilder.build()} is called to produce an {@code ExternalProcess}.
     */
    @PostConstruct
    public void initialise() {
        ExternalProcessBuilder.setExternalProcessFactory(this);

        //On Windows, configures a path for the winp library to extract its native DLL. By default it attempts to write
        //the DLL next to its jar file. However, it is not guaranteed that the system has write access to that directory,
        //so it is better to unpack the DLL in our home directory.
        if (SystemUtils.IS_OS_WINDOWS) {
            //The winp library has a bug in it that drops the last segment from this path, so to get the native DLL
            //extracted into the right folder we need a path that goes one layer deeper. It doesn't need to exist
            System.setProperty("winp.folder.preferred",
                    new File(settings.getNativeDir(), "truncated").getAbsolutePath());
        }
    }

    /**
     * Sets a list of configurers that will be called when a newly constructed ExternalProcess is about to be configured.
     *
     * @param configurers the configurers
     */
    @Autowired(required = false)
    @Override
    public void setConfigurers(@Nonnull List<ExternalProcessConfigurer> configurers) {
        super.setConfigurers(configurers);
    }

    @PreDestroy
    @Override
    public void shutdown() {
        super.shutdown();
    }
}
