package eu.dnetlib.springutils.stringtemplate;

import java.util.Locale;

import org.antlr.stringtemplate.StringTemplateGroup;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContextException;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

/**
 * Spring MVC view resolver based on string templates. You can parameterize this resolver with a java package name under
 * the templates will be searched.
 * 
 * <p>
 * requires a StringTemplateGroup bean
 * </p>
 * 
 * <p>
 * This code is based to a public domain example taken from <a
 * href="http://jira.springframework.org/browse/SPR-3266">here</a>
 * </p>
 * 
 * @author marko
 * @author Brian Lewis
 * 
 */
public class StringTemplateViewResolver extends UrlBasedViewResolver {

	/**
	 * template group.
	 */
	private StringTemplateGroup templateGroup;

	public void setTemplateGroup(final StringTemplateGroup value) {
		templateGroup = value;
	}

	public StringTemplateGroup getTemplateGroup() {
		return templateGroup;
	}

	/**
	 * Sets default viewClass to <code>requiredViewClass</code>.
	 * 
	 * @see #setViewClass
	 * @see #requiredViewClass
	 */
	public StringTemplateViewResolver() {
		setViewClass(requiredViewClass()); // NOPMD
		// XXX bad but we have to make assumptions later
		setRequestContextAttribute("rc");
	}

	/**
	 * Requires StringTemplateView.
	 * 
	 * @see StringTemplateView
	 * @return view class
	 */
	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected Class requiredViewClass() {
		return StringTemplateView.class;
	}

	/**
	 * Invoked on startup. Looks for a single StringTemplateGroup bean to find the relevant StringTemplate for this
	 * factory.
	 */
	@Override
	protected void initApplicationContext() {
		super.initApplicationContext();

		if (getTemplateGroup() == null) {
			// No explicit StringTemplateGroup: try to autodetect one.
			setTemplateGroup(autodetectMyStringTemplateGroup());
		}
	}

	/**
	 * Autodetect a StringTemplateGroup via the ApplicationContext. Called if no explicit StringTemplateGroup has been
	 * specified.
	 * 
	 * @return the StringTemplateGroup to use for StringTemplateViews
	 * @see #getApplicationContext
	 * @see #setMyStringTemplateGroup
	 */
	protected StringTemplateGroup autodetectMyStringTemplateGroup() {
		try {
			final StringTemplateGroup group = (StringTemplateGroup) BeanFactoryUtils.beanOfTypeIncludingAncestors(getApplicationContext(),
					StringTemplateGroup.class, true, false);
			return group;
		} catch (NoSuchBeanDefinitionException ex) {
			throw new ApplicationContextException("Must define a single StringTemplateGroup bean in this web application context"
					+ " (may be inherited). StringTemplateGroup is the usual implementation." + " This bean may be given any name.", ex);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.springframework.web.servlet.view.UrlBasedViewResolver#buildView(java.lang.String)
	 */
	@Override
	protected AbstractUrlBasedView buildView(final String viewName) throws Exception { // NOPMD
		if (logger.isDebugEnabled())
			logger.debug("looking up by view name: '" + viewName + "' based in '" + getPrefix() + "'");

		final StringTemplateView view = (StringTemplateView) super.buildView(getPrefix() + viewName);

		view.setStringTemplate(templateGroup.getInstanceOf(getPrefix() + viewName));

		return view;
	}

	@Override
	protected boolean canHandle(String viewName, Locale locale) {
		if(viewName.startsWith("redirect:"))
			return true;

		try {
			templateGroup.getInstanceOf(getPrefix() + viewName);
		} catch (IllegalArgumentException e) {
			return false;
		}

		if (super.canHandle(viewName, locale))
			return true;
		
		return true;
	}

}
