package com.collective.celos.ci.mode;

import com.collective.celos.ci.CelosCi;
import com.collective.celos.ci.config.CelosCiCommandLine;
import com.collective.celos.ci.config.deploy.CelosCiTarget;
import com.collective.celos.ci.config.deploy.CelosCiTargetParser;
import com.collective.celos.ci.mode.test.TestCase;
import com.collective.celos.ci.mode.test.TestConfigurationParser;
import com.collective.celos.ci.mode.test.TestRun;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.concurrent.*;

/**
 * Created by akonopko on 10/1/14.
 */
public class TestTask extends CelosCi {

    private static final String TEST_CONFIG_JS_FILE = "test.js";
    private static final String CELOS_LOG_FILE = "celos.log";

    private final List<TestRun> testRuns = Lists.newArrayList();
    private final File celosCiTempDir;

    public TestTask(CelosCiCommandLine commandLine) throws Exception {
        this(commandLine, getConfigJSFile(commandLine), getTempDir());
    }

    TestTask(CelosCiCommandLine commandLine, File configJSFile, File tempDir) throws Exception {

        this.celosCiTempDir = tempDir;
        substituteLoggers();

        CelosCiTargetParser parser = new CelosCiTargetParser(commandLine.getUserName());
        CelosCiTarget target = parser.parse(commandLine.getTargetUri());

        TestConfigurationParser configurationParser = new TestConfigurationParser();
        configurationParser.evaluateTestConfig(configJSFile);

        for (TestCase testCase : configurationParser.getTestCases()) {
            testRuns.add(new TestRun(target, commandLine, testCase, celosCiTempDir));
        }
    }

    private static File getConfigJSFile(CelosCiCommandLine commandLine) {
        return new File(commandLine.getTestCasesDir(), TEST_CONFIG_JS_FILE);
    }

    private static File getTempDir() throws IOException {
        return Files.createTempDirectory("celos").toFile();
    }

    private void substituteLoggers() throws IOException {
        //don't load configuration from log4j.xml -- we're doing this programmatically
        System.getProperties().setProperty("log4j.defaultInitOverride", "true");

        FileAppender fileAppender = new FileAppender();
        fileAppender.setFile(new File(celosCiTempDir, CELOS_LOG_FILE).getAbsolutePath());

        PatternLayout patternLayout = new PatternLayout();
        patternLayout.setConversionPattern("[%d{YYYY-MM-dd HH:mm:ss.SSS}] [%t] %-5p: %m%n");
        fileAppender.setLayout(patternLayout);
        fileAppender.activateOptions();
        Logger.getRootLogger().addAppender(fileAppender);
        Logger.getRootLogger().setLevel(Level.INFO);
    }


    @Override
    public void start() throws Throwable {
        try {
            List<Future> futures = submitTestRuns();
            waitForCompletion(futures);
        } finally {
            if (allTestCasesDeletedTheirData()) {
                FileUtils.forceDelete(celosCiTempDir);
            }
        }
    }

    private boolean allTestCasesDeletedTheirData() {
        for (File child : celosCiTempDir.listFiles()) {
            if (child.isDirectory()) {
                return false;
            }
        }
        return true;
    }

    private List<Future> submitTestRuns() {
        ExecutorService executor = Executors.newCachedThreadPool();
        List<Future> futures = Lists.newArrayList();
        for (final TestRun testRun : testRuns) {
            Callable callable = new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    testRun.start();
                    return null;
                }
            };
            futures.add(executor.submit(callable));
        }
        return futures;
    }

    void waitForCompletion(List<Future> futures) throws Throwable {
        List<Throwable> throwables = Lists.newArrayList();
        for (Future future : futures) {
            try {
                future.get();
            } catch (ExecutionException ee) {
                throwables.add(ee.getCause());
            }
        }
        if (!throwables.isEmpty()) {
            List<Throwable> throwablesWOLast = throwables.subList(0, throwables.size() - 1);
            for (Throwable t : throwablesWOLast) {
                t.printStackTrace();
            }
            Throwable lastThrowable = throwables.get(throwables.size() - 1);
            throw lastThrowable;
        }
    }

    List<TestRun> getTestRuns() {
        return testRuns;
    }
}

@@ -32,16 +32,677 @@
 .mode;%0A%0A
+import java.io.File;%0Aimport java.io.IOException;%0Aimport java.nio.file.Files;%0Aimport java.nio.file.attribute.FileAttribute;%0Aimport java.nio.file.attribute.PosixFilePermission;%0Aimport java.nio.file.attribute.PosixFilePermissions;%0Aimport java.util.List;%0Aimport java.util.Set;%0Aimport java.util.concurrent.Callable;%0Aimport java.util.concurrent.ExecutionException;%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors;%0Aimport java.util.concurrent.Future;%0A%0Aimport org.apache.commons.io.FileUtils;%0Aimport org.apache.log4j.FileAppender;%0Aimport org.apache.log4j.Level;%0Aimport org.apache.log4j.Logger;%0Aimport org.apache.log4j.PatternLayout;%0A%0A
 import c
@@ -733,16 +733,16 @@
 elosCi;%0A
-
 import c
@@ -1135,311 +1135,38 @@
 ort 
-org.apache.commons.io.FileUtils;%0Aimport org.apache.log4j.FileAppender;%0Aimport org.apache.log4j.Level;%0Aimport org.apache.log4j.Logger;%0Aimport org.apache.log4j.PatternLayout;%0A%0Aimport java.io.File;%0Aimport java.io.IOException;%0Aimport java.nio.file.Files;%0Aimport java.util.List;%0Aimport java.util.concurrent.*
+com.google.common.collect.Sets
 ;%0A%0A/
@@ -2550,17 +2550,231 @@
 los%22
-).toFile(
+, getTempDirAttributes()).toFile();%0A    %7D%0A%0A    private static FileAttribute%3CSet%3CPosixFilePermission%3E%3E getTempDirAttributes() %7B%0A        return PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(%22rwxr-xr-x%22)
 );%0A 

Make test case temp dir world readable for better debuggability