package be.iminds.ilabt.jfed.connectivity_tester;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.Optional;
import java.util.concurrent.*;

/**
 * User: twalcari
 * Date: 8/19/2016
 * Time: 16:16
 */
public class SafeConnectivityTest<CT extends ConnectivityTest> implements Callable<Optional<ConnectivityTest.ConnectivityTestResult>> {
    private static final Logger LOG = LoggerFactory.getLogger(SafeConnectivityTest.class);
    private final CT connectivityTest;
    private final long maxRunTime;

    public SafeConnectivityTest(CT connectivityTest, long maxRunTime) {
        this.connectivityTest = connectivityTest;
        this.maxRunTime = maxRunTime;
    }

    @Override
    public Optional<ConnectivityTest.ConnectivityTestResult> call() {
        ExecutorService es = Executors.newSingleThreadExecutor(
                new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ConnectivityTestThread#" + connectivityTest + "#%d").build());

        Date startTime = new Date();
        Future<ConnectivityTest.ConnectivityTestResult> testResult = es.submit(connectivityTest);

        es.shutdown();
        try {
            if (!es.awaitTermination(maxRunTime, TimeUnit.MILLISECONDS)) {
                es.shutdownNow();
            }
        } catch (InterruptedException ignored) {
        }

        Date stopTime = new Date();


        try {
            Optional<ConnectivityTest.ConnectivityTestResult> result = Optional.of(testResult.get());
            long durationMs = stopTime.getTime() - startTime.getTime();
            LOG.debug("{} took {}ms. result={}", connectivityTest.getName(), durationMs, result);

            return result;
        } catch (InterruptedException e) {
            LOG.info("ConnectivityTestThread of {} was interrupted", connectivityTest.getName(), e);
            return Optional.empty();
        } catch (ExecutionException e) {
            LOG.info("Error while executing {}", connectivityTest.getName(), e);
            return Optional.empty();
        }
    }
}
