package eu.dnetlib.functionality.modular.ui;

import java.net.URLEncoder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.view.RedirectView;

import eu.dnetlib.functionality.modular.ui.users.AuthorizationManager;
import eu.dnetlib.functionality.modular.ui.users.User;
import eu.dnetlib.functionality.modular.ui.utils.ShutdownUtils;

public abstract class ModuleEntryPoint extends MenuEntry implements Controller, BeanNameAware {

	private String beanName;

	private boolean validMenuEntry = true;

	private String group;
	private int groupOrder = 50;

	@Value("${dnet.modular.ui.authentication.url}")
	private String authenticationUrl;

	@Value("${dnet.modular.ui.logout.url}")
	private String logoutUrl;

	@Value("${dnet.modular.ui.ribbon.environment}")
	private String environment;

	@Value("${dnet.modular.ui.ribbon.accent}")
	private String ribbonAccent;

	@Resource
	protected EntryPointsAggregator aggregator;

	@Resource
	private ShutdownUtils shutdownUtils;

	@Resource(name = "modularUiAuthorizationManager")
	protected AuthorizationManager authorizationManager;

	@Override
	public ModelAndView handleRequest(final HttpServletRequest request, final HttpServletResponse response) throws Exception {

		final User user = authorizationManager.obtainUserDetails(request);
		if (user != null) {
			final ModelAndView mv = new ModelAndView();
			final ModelMap map = mv.getModelMap();
			map.addAttribute("ui_menu", getMenu());
			map.addAttribute("ui_title", getTitle());
			map.addAttribute("ui_description", getDescription());
			map.addAttribute("ui_group", getGroup());
			map.addAttribute("ui_modules", aggregator.getMenus(user));
			map.addAttribute("environment", environment);
			map.addAttribute("ribbonAccent", ribbonAccent);

			switch (shutdownUtils.currentStatus()) {
			case STOPPING:
				map.addAttribute("ui_navbar_class", "navbar-system-stopping");
				map.addAttribute("ui_message", "stopping system");
				break;
			case STOPPED:
				map.addAttribute("ui_navbar_class", "navbar-system-stopped");
				map.addAttribute("ui_message", "system stopped");
				break;
			default:
				map.addAttribute("ui_navbar_class", "navbar-inverse");
				break;
			}

			String baseUrl = "";
			for (int i = 1; i < StringUtils.countMatches(beanName, "/"); i++) {
				baseUrl += "/..";
			}
			if (baseUrl.length() > 0) {
				baseUrl = baseUrl.substring(1);
			}

			map.addAttribute("ui_baseUrl", baseUrl);

			if ((logoutUrl != null) && !logoutUrl.isEmpty()) {
				map.addAttribute("ui_logoutUrl", logoutUrl);
			}

			map.addAttribute("ui_user", user);

			initialize(map, request, response);
			return mv;
		} else {
			final StringBuffer url = request.getRequestURL();
			final String queryString = request.getQueryString();
			if (queryString != null) {
				url.append('?');
				url.append(queryString);
			}
			return new ModelAndView(new RedirectView(authenticationUrl + "?url=" + URLEncoder.encode(url.toString(), "UTF-8")));
		}
	}

	abstract protected void initialize(ModelMap map, HttpServletRequest request, HttpServletResponse response) throws Exception;

	public String getBeanName() {
		return beanName;
	}

	@Override
	public void setBeanName(final String beanName) {
		this.beanName = beanName;
	}

	public String getGroup() {
		return group;
	}

	@Required
	public void setGroup(final String group) {
		this.group = group;
	}

	@Override
	public String getRelativeUrl() {
		return beanName;
	}

	public boolean isValidMenuEntry() {
		return validMenuEntry;
	}

	public void setValidMenuEntry(final boolean validMenuEntry) {
		this.validMenuEntry = validMenuEntry;
	}

	public int getGroupOrder() {
		return groupOrder;
	}

	public void setGroupOrder(final int groupOrder) {
		this.groupOrder = groupOrder;
	}

}
