package eu.dnetlib.scripting.inspector;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import com.google.common.collect.Lists;

import eu.dnetlib.enabling.inspector.AbstractInspectorController;
import eu.dnetlib.miscutils.collections.MappedCollection;
import eu.dnetlib.miscutils.functional.UnaryFunction;
import eu.dnetlib.scripting.ScriptingLanguage;

@Controller
@SessionAttributes("history")
public class ScriptingController extends AbstractInspectorController {

	public static class SelectOption {
		private String value;
		private boolean selected;

		public SelectOption(final String value, final boolean selected) {
			super();
			this.value = value;
			this.selected = selected;
		}

		public String getValue() {
			return value;
		}

		public void setValue(final String value) {
			this.value = value;
		}

		public boolean isSelected() {
			return selected;
		}

		public void setSelected(final boolean selected) {
			this.selected = selected;
		}

	}

	@Resource(name = "languageMap")
	private Map<String, ScriptingLanguage> languages;

	@RequestMapping("/inspector/scripting.do")
	void scripting(Model model, HttpSession session) {
		ScriptingHistory history = (ScriptingHistory) session.getAttribute("history"); 
		if(history == null) {
			history = freshHistory();
			session.setAttribute("history", history);
		}
		commonScripting(model, "", history);
	}

	private ScriptingHistory freshHistory() {
		return new ScriptingHistory();
	}

	@RequestMapping(value = "/inspector/scripting.do", method = RequestMethod.POST)
	void doScripting(Model model, HttpSession session, @RequestParam("code") String code, @RequestParam("language") String language) {
		ScriptingHistory history = (ScriptingHistory) session.getAttribute("history");
		if(history == null)
			history = freshHistory();
				
		ScriptingLanguage engine = languages.get(language);
		
		final String result = engine.execute(code);
		model.addAttribute("results", result);
		
		history.register(code, result);
		
		commonScripting(model, language, history);
	}

	void commonScripting(Model model, String language, ScriptingHistory history) {
		model.addAttribute("languages", selectOptions(Lists.newArrayList(languages.keySet()), language));
		model.addAttribute("history", history);
	}
	
	@RequestMapping("/inspector/clearScript.do")
	public String clearScripting(@ModelAttribute("history") ScriptingHistory history) {
		history.clear();
		return "redirect:scripting.do";
	}
	
	@RequestMapping("/inspector/reloadScript.do")
	public String reloadScripting(@RequestParam("language") String language) {
		ScriptingLanguage engine = languages.get(language);
		engine.reload();
		return "redirect:scripting.do";
	}
			

	/**
	 * Given an list of values, return a list of SelectOption instances which have the "selected" boolean field set to
	 * true only for the element matching "current".
	 * 
	 * @param input
	 *            list of input strings
	 * @param current
	 *            current value to select
	 * @return
	 */
	private List<SelectOption> selectOptions(final List<String> input, final String current) {
		final UnaryFunction<SelectOption, String> mapper = new UnaryFunction<SelectOption, String>() {
			public SelectOption evaluate(final String value) {
				return new SelectOption(value, value.equals(current));
			}
		};
		return Lists.newArrayList(new MappedCollection<SelectOption, String>(input, mapper));
	}

}
