package eu.dnetlib.enabling.ui.server;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Required;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import eu.dnetlib.enabling.manager.msro.rmi.MSROService;
import eu.dnetlib.enabling.manager.msro.rmi.ProcessDescription;
import eu.dnetlib.enabling.tools.ServiceLocator;
import eu.dnetlib.enabling.ui.common.beans.GraphInfo;
import eu.dnetlib.enabling.ui.common.beans.ManagerRuleInfo;
import eu.dnetlib.enabling.ui.common.beans.ProcessHtmlInfo;
import eu.dnetlib.enabling.ui.common.beans.ProcessInfo;
import eu.dnetlib.enabling.ui.common.services.ManagerService;
import eu.dnetlib.enabling.ui.common.services.MyGwtException;
import eu.dnetlib.enabling.ui.server.workflow.Rule;
import eu.dnetlib.enabling.ui.server.workflow.RulesManager;
import eu.dnetlib.enabling.ui.server.workflow.configuration.RuleConfiguration;

public class ManagerServlet extends RemoteServiceServlet implements ManagerService {

	/**
	 * 
	 */
	private static final long serialVersionUID = 874365563782740856L;
	private ServiceLocator<MSROService> msroLocator;
	private RulesManager rulesManager;
	
	
	/**
	 * The time waited to refresh a process image on UI.
	 */
	private int refreshFrequencyMillis;
	/**
	 * The delay used to simulate framebuffer during the redraw of a process image.
	 */
	private int frameDelayMillis;
	
	private static final Log log = LogFactory.getLog(ManagerServlet.class); // NOPMD by marko on 11/24/08 5:02 PM

	
	public ServiceLocator<MSROService> getMsroLocator() {
		return msroLocator;
	}

	@Required
	public void setMsroLocator(ServiceLocator<MSROService> msroLocator) {
		this.msroLocator = msroLocator;
	}

	
	public List<ProcessInfo> listOrchestrationProcess(String rsId, int maxProcesses) throws MyGwtException {
		List<ProcessInfo> list = new ArrayList<ProcessInfo>();
		
		List<ProcessDescription> plist = msroLocator.getService().listOrchestrationProcesses(rsId, maxProcesses);
		
		if (plist == null) {
			log.error("MSRO.listOrchestrationProcesses has returned NULL (rsId: ["+rsId+"], maxProcess: ["+ maxProcesses + "])");
		} else {
			for (ProcessDescription p : plist) {
				ProcessInfo info = new ProcessInfo();
				info.setProcessId(p.getProcessId());
				info.setLastActivity(p.getLastActivity());
				info.setStatus(p.getStatus().toString());
				info.setWorkflowName(p.getWorkflowName());
				info.setCompletionStatus(p.getCompletionStatus().toString());
				
				list.add(info);
			}
		}
		return list;
	}
	
	public ProcessHtmlInfo obtainHtmlProcess(String pid) throws MyGwtException {
		ProcessHtmlInfo info = new ProcessHtmlInfo();
		info.setRefreshFrequencyMillis(refreshFrequencyMillis);
		info.setFrameDelayMillis(frameDelayMillis);
		info.setHtml(msroLocator.getService().processHtmlMap(pid));
		return info;
		
	}

	public String obtainHtmlProcessNode(String pid, String nodeId) throws MyGwtException {
		// TODO Auto-generated method stub
		return "NOT IMPLEMENTED";
	}
	
	public ProcessHtmlInfo verifyRule(String ruleId) throws MyGwtException {
		ProcessHtmlInfo info = new ProcessHtmlInfo();
		info.setRefreshFrequencyMillis(refreshFrequencyMillis);
		info.setFrameDelayMillis(frameDelayMillis);
		
		Rule rule = rulesManager.getRule(ruleId);
		if (rule == null) {
			info.setHtml("Invalid Rule");
		} else {
			info.setHtml(rule.execute(rulesManager.getConfigDatabase().getConfig(ruleId)));
		}	
			
		return info;
	}

	public ProcessHtmlInfo asImageMap(String ruleId) throws MyGwtException {
		ProcessHtmlInfo info = new ProcessHtmlInfo();
		info.setRefreshFrequencyMillis(refreshFrequencyMillis);
		info.setFrameDelayMillis(frameDelayMillis);
		
		Rule rule = rulesManager.getRule(ruleId);
		if (rule == null) { info.setHtml("Invalid Rule"); }
		else              { info.setHtml(rule.generateImageMap()); }
		
		return info;
	}

	public ProcessHtmlInfo asSavedImageMap(String ruleId, int i) throws MyGwtException {
		ProcessHtmlInfo info = new ProcessHtmlInfo();
		info.setRefreshFrequencyMillis(refreshFrequencyMillis);
		info.setFrameDelayMillis(frameDelayMillis);
		
		Rule rule = rulesManager.getRule(ruleId);
		if (rule == null) { info.setHtml("Invalid Rule"); }
		else              { info.setHtml(rule.generateSavedImageMap(i)); }

		return info;
	}

	public List<GraphInfo> listSavedGraphs(String ruleId) throws MyGwtException {
		Rule rule = rulesManager.getRule(ruleId);
		if (rule == null) return new ArrayList<GraphInfo>(); 
		return rule.getSavedGraphs();
	}
	
	public List<String> listCategoryRules() throws MyGwtException {
		return rulesManager.listCategories();
	}

	public List<ManagerRuleInfo> listRules(String category) throws MyGwtException {
		return rulesManager.listRulesAsGwtInfo(category);
	}

	public Boolean updateRule(ManagerRuleInfo info) throws MyGwtException {
		String ruleId = info.getId();
		
		RuleConfiguration config = new RuleConfiguration(
				ruleId,
				info.getAutomatic(),
				info.getDefaultCorrectiveAction(),
				info.isSchedulingEnabled(),
				info.getScheduling(),
				info.getNotificationMode()
		);
		rulesManager.getConfigDatabase().addOrUpdateConfig(config);
		try {
			Rule rule = rulesManager.getRule(ruleId);
			if (rule != null) {
				rulesManager.getScheduler().updateRuleJob(rule, config);
			}
		} catch (SchedulerException e) {
			log.error(e.getMessage());
			throw (new MyGwtException());
		} catch (ParseException e) {
			log.error(e.getMessage());
			throw (new MyGwtException("Invalid cron scheduling", ""));
		}
		
		return true;
	}

	public Boolean reactivateRule(String ruleId, String action) throws MyGwtException {
		return rulesManager.getTokenRegistry().reactivateNode(ruleId, action);
	}
	
	public int getRefreshFrequencyMillis() {
		return refreshFrequencyMillis;
	}

	@Required
	public void setRefreshFrequencyMillis(int refreshFrequencyMillis) {
		this.refreshFrequencyMillis = refreshFrequencyMillis;
	}

	public int getFrameDelayMillis() {
		return frameDelayMillis;
	}
	
	@Required
	public void setFrameDelayMillis(int frameDelayMillis) {
		this.frameDelayMillis = frameDelayMillis;
	}

	public RulesManager getRulesManager() {
		return rulesManager;
	}
	
	@Required
	public void setRulesManager(RulesManager rulesManager) {
		this.rulesManager = rulesManager;
	}


}
