package org.gcube.nlphub.nlp;

import java.io.PrintWriter;
import java.util.ArrayList;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.gcube.nlphub.legacy.Constants;
import org.gcube.nlphub.legacy.JsonManager;

public class RunnerCommander extends Thread {
	private HttpServletResponse response = null;
	private String annotationList = "";
	private String[] identifiers = null;
	private String link = "";
	private String token = "";
	private String dataMiner;
	private ArrayList<String> outResultList = null;
	private long sleepTime = 500l;
	private long maxWaitingTime = 5l * 60l * 1000l;
	private Logger logger = Logger.getLogger(RunnerCommander.class.getSimpleName());
	private boolean complete = false;

	public RunnerCommander(String dataMiner, String[] identifiers, String link, String annotationList, String token) {
		this.identifiers = identifiers;
		this.annotationList = annotationList;
		this.link = link;
		this.token = token;
		this.response = null;
		this.sleepTime = 500l;
		this.dataMiner = dataMiner;
		outResultList = new ArrayList<String>();
	}

	public RunnerCommander(String dataMiner, String[] identifiers, String link, String annotationList, String token,
			HttpServletResponse response) {
		this.identifiers = identifiers;
		this.annotationList = annotationList;
		this.link = link;
		this.token = token;
		this.response = response;
		this.sleepTime = 500l;
		this.dataMiner = dataMiner;
		outResultList = new ArrayList<String>();
	}

	public long getSleepTime() {
		return sleepTime;
	}

	public void setSleepTime(long sleepTime) {
		this.sleepTime = sleepTime;
	}

	public synchronized void updateResultList(String res) {
		outResultList.add(res);
	}

	public long getMaxWaitingtime() {
		return maxWaitingTime;
	}

	public void setMaxWaitingTime(long maxWaitingTime) {
		this.maxWaitingTime = maxWaitingTime;
	}

	public void startProcess() {
		start();
		// the following loop is needed in order to wait the end of all computations
		// before return...
		long counter = 0;
		while(!complete) {
			try {
				sleep(sleepTime);
				counter += sleepTime;
				if(counter > 2*maxWaitingTime)
					complete = true;
			} catch (InterruptedException x) {
				logger.info("Interrupted.");
			}
		}
	}
	
	private void runAlgorithms() {
		for (String id : identifiers) {
			NlpAsyncNerRunner n = new NlpAsyncNerRunner(dataMiner, id, token, link, annotationList, null, this);
			n.start();
		}
	}

	public void run() {
		runAlgorithms();
		long counter = 0;
		try {
			while (counter <= maxWaitingTime) {
				//logger.info("complete: " + outResultList.size() + "/" + identifiers.length);
				if (outResultList.size() == identifiers.length) {
					String[] links = new String[outResultList.size()];
					links = outResultList.toArray(links);
					writeResponse(links);
					logger.info("Elapsed time: " + counter + " msec.");
					return;
				}
				counter += sleepTime;
				sleep(sleepTime);
			}
			logger.error("Timeout error.");
			timeoutHandler();
		} catch (InterruptedException x) {
			logger.info("Elapsed time: " + counter + " msec.");
			logger.info("Thread interrupted.");
			timeoutHandler();
		}
	}

	private void timeoutHandler() {
		boolean found = false;
		for(int i=0; i<identifiers.length; i++, found=false) {
			String id = identifiers[i];
			id = id.substring(id.lastIndexOf(".") + 1);
			for(String s : outResultList) {
				if(s.startsWith(id)) {
					found = true;
					break;
				}
			}
			if(!found) {
				outResultList.add(id + ":::" + Constants.ERROR_ID);
			}
		}
		String[] links = new String[outResultList.size()];
		links = outResultList.toArray(links);
		writeResponse(links);
	}
	
	private void writeResponse(String[] content) {
		logger.info("RunnerCommander has run " + content.length + " tasks.");
		if (response != null) {
			response.setContentType("application/json;charset=UTF-8");
			PrintWriter writer = null;
			try {
				writer = response.getWriter();
				String msg = new JsonManager().getSuccessJsonResponse(content);
				writer.println(msg);
				if (writer.checkError()) {
					logger.error("writeResponse method has some problem in writing result.");
				}

			} catch (Exception ex) {
				logger.error(ex.getLocalizedMessage());
				ex.printStackTrace();
			} finally {
				complete = true;
				if (writer != null)
					writer.close();
			}
		}
	}
	
}
