package yami;

import static com.google.common.collect.Maps.*;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import yami.configuration.CollectorRule;
import yami.configuration.ConfigurationManager;
import yami.configuration.HttpCollector;
import yami.configuration.Node;
import yami.configuration.VersionCollector;
import yami.model.Constants;
import yami.model.Result;
import yami.utils.ProcessExecuter;

public class RunMonitors implements Task
{
	private Node node;
	private static final Logger log = Logger.getLogger(RunMonitors.class);
	private Map<String, Long> lastRun = newHashMap();
	
	public RunMonitors(Node node)
	{
		this.node = node;
	}
	
	@Override
	public void exec()
	{
		for (File monitor : getMonitors())
		{
			HttpCollector c = ConfigurationManager.getInstance().getConfiguredProject().getCollector(monitor.getName());
			if (null == c)
			{
			    if (monitor.getName().equals(new VersionCollector().name))
			    {
			    	c = new VersionCollector();
			    }
			}
			runOnce(monitor, c);
		}
	}

	protected void runOnce(File monitor, HttpCollector c) {
	    if (null == c)
	    {
	    	log.debug("no collector defined for monitor file " + monitor.getName() + ", skipping exectution");
	    	return;
	    }
	    Long lastRuntime = lastRun.get(c.name);
	    if (lastRuntime == null || System.currentTimeMillis() - lastRuntime > minInterval(c))
	    {
	    	runMonitor(monitor, c);
	    	lastRun.put(c.name, System.currentTimeMillis());
	    }
	}

	private int minInterval(HttpCollector c)
	{
		if (null == c.minInterval)
		{
			return 20000;
		}
		return c.minInterval  * 60000;
	}
	
	private void runMonitor(File monitor, HttpCollector c)
	{
		if (monitor.isFile() && monitor.canExecute())
		{
			try
			{
				List<String> cmd = buildCmd(monitor, c);
				log.info("Will execute " + cmd);
				Result res = ProcessExecuter.execute(cmd);
				log.info(monitor.getName() + " ended with res=" + res.success());
				writeResult(res, monitor.getName(), c);
			}
			catch (Exception e)
			{
				log.warn("got exception when executing monitor ", e);
			}
		}
	}
	
	private List<String> buildCmd(File monitor, HttpCollector c)
	{
		List<String> cmd = new ArrayList<String>();
		cmd.add(monitor.getAbsolutePath());
		for (CollectorRule r : c.rules)
		{
			if (r.shouldApplyForNode(node.name))
			{
				for (String arg : r.arg)
				{
					cmd.add(arg);
				}
			}
		}
		return cmd;
	}
	
	private void writeResult(Result res, String outputFileName, HttpCollector c) throws IOException
	{
		BufferedWriter out = getWriter(outputFileName);
		if (c.hasStatus())
		{
		    out.write(res.success() ? "True\n" : "False\n");
		    out.write("run at " + new Date() + "\n");
		}
		out.write(res.output);
		out.close();
	}
	
	private BufferedWriter getWriter(String name) throws IOException
	{
		String out = Constants.getInstallDir() + Constants.NODES_DIR + node.name + "/" + name + ".txt";
		log.debug("Output for " + name + " will be written to: " + out);
		FileWriter fstream = new FileWriter(out);
		BufferedWriter bw = new BufferedWriter(fstream);
		return bw;
	}
	
	private List<File> getMonitors()
	{
		String dir = Constants.getInstallDir() + Constants.MONITORS_DIR;
		log.debug("Collecting monitors from " + dir);
		File folder = new File(dir);
		List<File> files = Arrays.asList(folder.listFiles());
		if (files.isEmpty())
		{
			log.debug("No files found to execute under " + dir);
		}
		else
		{
			log.debug("Found monitors: " + files);
		}
		return files;
	}
	
}

@@ -616,16 +616,58 @@
 cuter;%0A%0A
+import com.google.common.base.Stopwatch;%0A%0A
 public c
@@ -2071,48 +2071,183 @@
 %09%09%09%09
-Result res = ProcessExecuter.execute(cmd
+Stopwatch stopwatch = new Stopwatch().start();%0A%09%09%09%09Result res = ProcessExecuter.execute(cmd);%0A%09%09%09%09stopwatch.stop();%0A//%09%09%09%09long millis = stopwatch.elapsed(TimeUnit.MILLISECONDS
 );%0A%09
@@ -2312,16 +2312,45 @@
 uccess()
+ + %22 that took: %22 + stopwatch
 );%0A%09%09%09%09w
@@ -2385,16 +2385,33 @@
 ame(), c
+ , stopwatch, cmd
 );%0A%09%09%09%7D%0A
@@ -2906,16 +2906,55 @@
 lector c
+, Stopwatch stopwatch, List%3CString%3E cmd
 ) throws
@@ -3151,16 +3151,381 @@
 %22);%0A%09%09%7D%0A
+%09%09out.write(%22+------------------------------------------------------------------+%5Cn%22);%0A%09%09out.write(%22%7C command: %22 + cmd + %22%5Cn%22);%0A%09%09out.write(%22%7C exitstatus: %22 + res.exit() + %22%5Cn%22);%0A%09%09out.write(%22%7C completed at: %22 + new Date() + %22%5Cn%22);%0A%09%09out.write(%22%7C length: %22 + stopwatch + %22%5Cn%22);%0A%09%09out.write(%22+------------------------------------------------------------------+%5Cn%22);%0A
 %09%09out.wr

add header to output