/*
 * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the
 * @author tags. See the copyright.txt file in the distribution for a full
 * listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */
package org.zanata.workflow;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.IOUtils;
import org.zanata.util.Constants;
import org.zanata.util.PropertiesHolder;
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.SimpleTimeLimiter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ClientWorkFlow {

    private final int timeoutDuration;

    /**
     * @param timeoutDuration
     *            in seconds.
     */
    public ClientWorkFlow(int timeoutDuration) {
        this.timeoutDuration = timeoutDuration;
    }

    /**
     * With default timeout 120 seconds.
     */
    public ClientWorkFlow() {
        timeoutDuration = 120;
    }

    public File getProjectRootPath(String sampleProject) {
        String baseDir =
                PropertiesHolder.getProperty(Constants.sampleProjects.value());
        Preconditions.checkState(
                !(Strings.isNullOrEmpty(sampleProject) || Strings
                        .isNullOrEmpty(baseDir)),
                "base dir and sample project can't be empty");

        File projectDir = new File(baseDir, sampleProject);
        ClientWorkFlow.log.info("about to push project at: {}", projectDir.getAbsolutePath());
        return projectDir;
    }

    public static String getUserConfigPath(String user) {
        String configName = "zanata-" + user + ".ini";
        URL resource =
                Thread.currentThread().getContextClassLoader()
                        .getResource(configName);
        Preconditions.checkNotNull(resource, configName + " can not be found.");
        return resource.getPath();
    }

    public List<String> callWithTimeout(final File workingDirectory,
            String command) {
        log.info("=== about to call ===\n{}", command);
        final List<String> commands =
                Lists.newArrayList(Splitter.on(" ").split(command));

        SimpleTimeLimiter timeLimiter = new SimpleTimeLimiter();
        Callable<List<String>> work = () -> {
            Process process =
                    ClientWorkFlow.invokeClient(workingDirectory,
                            commands);
            process.waitFor();
            List<String> output = ClientWorkFlow.getOutput(process);
            logOutputLines(output);
            return output;
        };
        try {
            return timeLimiter
                    .callWithTimeout(work, timeoutDuration, TimeUnit.SECONDS, true);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean isPushSuccessful(List<String> output) {
        Optional<String> successOutput =
                Iterables.tryFind(output,
                        input -> input.contains("BUILD SUCCESS"));
        return successOutput.isPresent();
    }

    private synchronized static Process invokeClient(File projectDir,
            List<String> command) throws IOException {
        ProcessBuilder processBuilder =
                new ProcessBuilder(command).redirectErrorStream(true);
        Map<String, String> env = processBuilder.environment();
        // mvn and java home
        ClientWorkFlow.log.info("M2: {}", env.get("M2"));
        ClientWorkFlow.log.info("JAVA_HOME: {}", env.get("JAVA_HOME"));
        // log.debug("env: {}", env);
        processBuilder.directory(projectDir);
        return processBuilder.start();
    }

    private void logOutputLines(List<String> output) {
        for (String line : output) {
            ClientWorkFlow.log.info(line);
        }
    }

    /**
     * Returns process's output as a list of strings; closes all I/O streams.
     * @param process
     * @return
     * @throws IOException
     */
    private static List<String> getOutput(Process process) throws IOException {
        try (
                InputStream in = process.getInputStream();
                InputStream stdErr = process.getErrorStream();
                OutputStream ignored2 = process.getOutputStream();
        ) {
            List<String> output = IOUtils.readLines(in, Charsets.UTF_8);
            output.addAll(IOUtils.readLines(stdErr, Charsets.UTF_8));
            return output;
        }
    }
}

@@ -3264,16 +3264,170 @@
 mmand);%0A
+        if (!workingDirectory.isDirectory()) %7B%0A            throw new RuntimeException(%22working directory does not exist: %22 + workingDirectory);%0A        %7D%0A
         
@@ -4658,24 +4658,26 @@
 ream(true);%0A
+//
         Map%3C
@@ -4732,177 +4732,17 @@
 ();%0A
+//
        
- // mvn and java home%0A        ClientWorkFlow.log.info(%22M2: %7B%7D%22, env.get(%22M2%22));%0A        ClientWorkFlow.log.info(%22JAVA_HOME: %7B%7D%22, env.get(%22JAVA_HOME%22));%0A        //
  log

Check for existing directory