/**
 *
 * Copyright INRA-URGI 2009-2010
 * 
 * This software is governed by the CeCILL license under French law and
 * abiding by the rules of distribution of free software. You can use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 * 
 * As a counterpart to the access to the source code and rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty and the software's author, the holder of the
 * economic rights, and the successive licensors have only limited
 * liability.
 * 
 * In this respect, the user's attention is drawn to the risks associated
 * with loading, using, modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean that it is complicated to manipulate, and that also
 * therefore means that it is reserved for developers and experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and, more generally, to use and operate it in the
 * same conditions as regards security.
 * 
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
 *
 */
import java.util.*;
import java.io.*;
import javax.swing.SwingUtilities;
import javax.swing.*;
import java.util.concurrent.CountDownLatch;

public class ProgramLauncher extends SwingWorker<Boolean, String>  {

  String[]     command;
  JTextArea    logArea;
  JLabel       messageField;
  JProgressBar progressBar;
  JLabel       etaField;
  int          exitValue;
  

  public ProgramLauncher (LinkedList <String> c, JTextArea la, JLabel mf, JProgressBar pb, JLabel ef) {
    command       = new String[c.size()];
    logArea       = la;
    messageField  = mf;
    progressBar   = pb;
    etaField      = ef;
    exitValue     = -1;
    c.toArray(command);
  }


  public ProgramLauncher (String[] c, JTextArea la, JLabel mf, JProgressBar pb, JLabel ef) {
    command       = c;
    logArea       = la;
    messageField  = mf;
    progressBar   = pb;
    etaField      = ef;
    exitValue     = -1;
  }


  @Override
  public Boolean doInBackground() {
    ProcessBuilder pb           = new ProcessBuilder(command);
    Process process             = null;
    BufferedReader outputReader = null;
    pb                          = pb.redirectErrorStream(true);
    Map<String, String> env     = pb.environment();
    env.put("PYTHONPATH", System.getProperty("user.dir") + java.io.File.separator + "Python");
    env.put("SMARTPATH", System.getProperty("user.dir") + java.io.File.separator + "Python");
    env.put("SMARTMYSQLPATH", Global.mysqlCommand);
    env.put("SMARTRPATH", Global.rCommand);
    String commandJoined = Arrays.toString(command);

    try {
      publish("=== Starting command '" + commandJoined.trim() + "' ===\n");
      process = pb.start();

      BufferedInputStream outputStream = new BufferedInputStream(process.getInputStream());
      InputStream is                   = process.getInputStream();
      InputStreamReader isr            = new InputStreamReader(is);
      outputReader                     = new BufferedReader(isr);
    }
    catch (Exception exception) {
      publish("!Process cannot be started (command is '" + commandJoined + "')!\n");
      exception.printStackTrace();
      return Boolean.FALSE;
    }
    if (outputReader == null) {
      publish("!Problem in the output of the command!\n");
      return Boolean.FALSE;
    }
    else {
      try {
        String line;
        while ((line = outputReader.readLine()) != null) {
          publish(line + "\n");
        }
      }
      catch (IOException e) {
        e.printStackTrace();
        publish("!Cannot get the output of the command!\n");
        return Boolean.FALSE;
      }
    }
    try {
      process.waitFor();
    }
    catch (InterruptedException e) {
      e.printStackTrace();
      publish("!Cannot wait for the end of the command!\n");
      return Boolean.FALSE;
    }
    try {
      exitValue = process.exitValue();
      System.out.println(exitValue);
    }
    catch (IllegalThreadStateException e) {
      e.printStackTrace();
      publish("!Cannot get the exit value of the command!\n");
      return Boolean.FALSE;
    }
    if (exitValue != 0) {
      publish("!Problem during the execution of the command '" + commandJoined + "'!\n");
      return Boolean.FALSE;
    }
    publish("=== Ending command '" + commandJoined.trim() + "' ===\n");
    return Boolean.TRUE;
  }


  @Override
  protected void process(List<String> chunks) {
    String message = "";
    String text    = logArea.getText();
    for (String chunk: chunks) {
      text += chunk;
    }
    for (String lineSeparatedByCarriageReturn: text.split("\n")) {
      for (String line: lineSeparatedByCarriageReturn.split("\r")) {
        boolean progressLine = false;
        if (line.matches(".*\\[=*\\s*\\]\\s*\\d*/\\d*\\s*")) {
          String[] ratioElements = line.split("\\]")[1].trim().split("/");
          int      current       = Integer.parseInt(ratioElements[0].trim());
          int      aim           = Integer.parseInt(ratioElements[1].trim());
          messageField.setText(line.split("\\[")[0].trim());
          progressBar.setValue(current * 100 / aim);
          etaField.setText("");
          progressLine = true;
        }
        else if (line.matches(".*\\[=*\\s*\\]\\s*\\d*/\\d*\\s*ETA:\\s*.*")) {
          String[] ratioElements = line.split("\\]")[1].split("E")[0].trim().split("/");
          int      current       = Integer.parseInt(ratioElements[0].trim());
          int      aim           = Integer.parseInt(ratioElements[1].trim());
          String   eta           = line.split("ETA:")[1].trim();
          messageField.setText(line.split("\\[")[0].trim());
          progressBar.setValue(current * 100 / aim);
          etaField.setText("ETA: " + eta);
          progressLine = true;
        }
        else if (line.matches(".*\\[=*\\s*\\]\\s*\\d*\\s*completed in.*")) {
          String nbElements = line.split("\\]")[1].split("completed")[0].trim();
          String timeSpent  = line.split("completed in")[1].trim();
          message          += line.split("\\[")[0].trim() + ": " + nbElements + " elements completed in " + timeSpent + "\n";
          messageField.setText(line.split("\\[")[0].trim());
          progressLine = true;
        }
        if (! progressLine) {
          message += line + "\n";
        }
      }
    }
    String lines[]     = message.split("\n");
    String toBeWritten = "";
    for (int i = Math.max(0, lines.length - Global.logAreaSize); i < lines.length; i++) {
      toBeWritten += lines[i] + "\n";
    }
    logArea.setText(toBeWritten);
  }

  public int getExitValue() {
    return exitValue;
  }
}
