/*
 * Created on Feb 9, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package gov.nasa.jsc.plum;

import gov.nasa.jsc.plum.Configuration;
import gov.nasa.jsc.plum.PlumUtil.DatabaseConfiguration;
import gov.nasa.jsc.plum.PlumUtil.DatabaseWindow;
import gov.nasa.jsc.plum.PlumUtil.PlumUtilities;
import gov.nasa.jsc.plum.PlumUtil.TextAreaOutput;

import java.awt.BorderLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Date;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * @author randrews
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class ProgressWindow extends JFrame implements ActionListener {

    private DatabaseWindow parent;
    private Connection conn;
    private Configuration config;
    private ResultSet run;
    private int idx;
    
    private Vector commands;
    private Vector labels;
    
    private JTextArea text;
    private JButton cancel;
    
    private Runner runner;
    private Process current;
    
    /**
     * @param parent
     * @param conn
     * @param config
     * @param run
     * @throws java.awt.HeadlessException
     */
    public ProgressWindow(DatabaseWindow parent, Connection conn,
            Configuration config, ResultSet run) throws HeadlessException{
        super("Run Progress");
        this.parent = parent;
        this.conn = conn;
        this.config = config;
        this.run = run;
        
        commands=new Vector();
        labels=new Vector();
        
        try{
            idx=run.getInt("idx");
        } catch(Exception e){
            e.printStackTrace();
        }
        
        String delimiter;
        if(parent.getCfg().getDelimiter().equals("slash"))
            delimiter="/";
        else delimiter="\\";
        
//        System.out.println("idx: "+idx);
        commands.add(parseCommand(config.getPrograms()+delimiter+config.getCombogen()));
        labels.add("Making combinations...");
        
        commands.add(parseCommand(config.getPrograms()+delimiter+config.getCalc()));
        labels.add("Running combinations...");
        
        commands.add(parseCommand(config.getPrograms()+delimiter+config.getIncrementGraph()));
        labels.add("Making increment graph...");
        
        commands.add(parseCommand(config.getPrograms()+delimiter+config.getSimulGraph()));
        labels.add("Making simultaneous graph...");
        
        commands.add(parseCommand(config.getPrograms()+delimiter+config.getAvgRuntime()));
        labels.add("Making average runtime graph...");

        commands.add(parseCommand(config.getPrograms()+delimiter+config.getSelSuccess()));
        labels.add("Making selection success graph...");
        
        commands.add(parseCommand(config.getPrograms()+delimiter+config.getTopology()));
        labels.add("Making topology chart...");
        
        text=new JTextArea();
        text.setRows(10);
        text.setColumns(35);
        text.setEditable(false);
        text.setLineWrap(true);
        
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(new JScrollPane(text),BorderLayout.CENTER);
        
        cancel=new JButton("Cancel");
        cancel.addActionListener(this);
        cancel.setSelected(false);
        getContentPane().add(cancel,BorderLayout.SOUTH);
        
        runner=new Runner(commands,labels,new TextAreaOutput(text));
        runner.start();
        
        pack();
    }
    
    private class Runner extends Thread{
        private Vector commands;
        private Vector labels;
        private boolean stop;
        private PrintStream out;
        
        public Runner(Vector commands, Vector labels,OutputStream out) {
            super();
            this.commands = commands;
            this.labels = labels;
            stop=false;
            this.out=new PrintStream(out);
        }
        
        public void run() {
            Date start = new Date();
            cancel.setEnabled(true);

            try {

                if (run.getString("tblname") == null
                        || run.getString("tblname").equals("")) {
                    out
                            .print("You must specify a table name to put the run output in. Assign a value to the field \"tblname\".");
                    return;
                }

                if (commands.size() != labels.size()) {
                    out.print("Something is bad wrong. Aborting.\n");
                    return;
                }
                
                File f = new File(parseCommand("$output"));
                if (!f.exists())
                    f.mkdirs();
                else if (!f.isDirectory()) {
                    out.print("Output directory exists, but is not directory.");
                    return;
                }
                
                if (!PlumUtilities.setTopology(conn, run.getString("topology")))
                    out
                            .print("Unable to set run topology; using default topology.");
                for (int n = 0; n != commands.size(); n++) {
                    out.print((String) commands.get(n) + "\n");
                    out.print((String) labels.get(n));
                    current = Runtime.getRuntime().exec((String) commands.get(n));
                    
                    BufferedReader stdout = new BufferedReader(new InputStreamReader(current.getInputStream()));
                    BufferedReader stderr = new BufferedReader(new InputStreamReader(current.getErrorStream()));

                    String line="",error="";
                    while ((line=stdout.readLine())!=null || (error=stderr.readLine())!=null)
                    {
                        if(!line.equals(""))
                            out.println(line);
                        if(!error.equals(""))
                            out.println(error);
                        line=error="";
                    }
                    
                    out.print(" Done.\n");
                    current.waitFor();
                    if (stop)
                        break;
                }
            }
            catch (IOException e) {
                out.print("\nCommand does not exist.");
            }
            catch (Exception e) {
                e.printStackTrace();
            } finally {
                PlumUtilities.setTopology(conn, "default");
                cancel.setEnabled(false);
                Date end = new Date();
                long runtime = (end.getTime() - start.getTime()) / 1000;
                out.println("\nRuntime (mm:ss): " + (runtime / 60) + ":"
                        + (runtime % 60));
            }
        }
        public void cancel(){
            this.stop=true;
        }
    }
        
        public String parseCommand(String cmd){
        try{
            DatabaseConfiguration db=new DatabaseConfiguration(getClass());
            Configuration cfg=parent.getCfg();

            
            String runoutput=run.getString("outputpath");
            String outputpath=cfg.getOutput();
            String delimiter;
            if(cfg.getDelimiter().equals("slash"))
                delimiter="/";
            else
                delimiter="\\\\"; // Two of them because the thing replaced with is ALSO a regex. 
            outputpath+=delimiter;
            
            if(runoutput!=null && !runoutput.equals(""))
            {
                outputpath=outputpath+runoutput;
                outputpath+=delimiter;
            }
            System.out.println("outputpath: "+outputpath);
            
            String numcombos="1000";Object nc=run.getObject("numcombos");
            if(nc!=null && !nc.toString().equals(""))
                numcombos=nc.toString();
            
            cmd=cmd.replaceAll("\\$idx",Integer.toString(idx));
            cmd=cmd.replaceAll("\\$host",db.getHost());
            cmd=cmd.replaceAll("\\$db",db.getDB());
            cmd=cmd.replaceAll("\\$user",db.getUser());
            cmd=cmd.replaceAll("\\$pass",db.getPass());
            cmd=cmd.replaceAll("\\$outputdb",run.getString("outputdb"));
            cmd=cmd.replaceAll("\\$output",outputpath);
            cmd=cmd.replaceAll("\\$table",run.getString("tblname"));
            cmd=cmd.replaceAll("\\$order",numcombos);
            cmd=cmd.replaceAll("\\$numcombos",numcombos);
            System.out.println(cmd);
        } catch(Exception e){
            e.printStackTrace();
        }
        return cmd;
    }
    
    public static String staticParse(String cmd,int idx){
        try{
            DatabaseConfiguration db=new DatabaseConfiguration(new PlumMain().getClass());
            cmd=cmd.replaceAll("\\$idx",Integer.toString(idx));
            cmd=cmd.replaceAll("\\$host",db.getHost());
            cmd=cmd.replaceAll("\\$db",db.getDB());
            cmd=cmd.replaceAll("\\$user",db.getUser());
            cmd=cmd.replaceAll("\\$pass",db.getPass());
            cmd=cmd.replaceAll("\\$outputdb","plum_output");
        } catch(Exception e){
            e.printStackTrace();
        }
        return cmd;
    }
    
    public void actionPerformed(ActionEvent arg0) {
        if(runner!=null)
        {
            runner.cancel();
            if(current!=null)
                current.destroy();
            text.append("\nCancelled.\n");
        }
    }
}
