/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.exts.struts2.views.freemarker;

import nuts.exts.struts2.util.StrutsContextUtils;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.freemarker.ScopesHashModel;

import com.opensymphony.xwork2.util.ValueStack;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * FreemarkerUtils
 */
public class FreemarkerUtils {
	/**
	 * @return FreemarkerManager
	 */
	public static FreemarkerManager getFreemarkerManager() {
		return StrutsContextUtils.getContainer().getInstance(FreemarkerManager.class);
	}

	/**
	 * hasTemplate
	 * @param name template name
	 * @return true if template exists
	 */
	public static boolean hasTemplate(String name) {
		Locale locale = StrutsContextUtils.getLocale();
		try {
			getConfiguration().getTemplate(name, locale);
			return true;
		}
		catch (IOException e) {
			return false;
		}
	}

	/**
	 * @return Configuration
	 */
	public static Configuration getConfiguration() {
		ServletContext servletContext = StrutsContextUtils.getServletContext();

		FreemarkerManager freemarkerManager = getFreemarkerManager();

		Configuration configuration = (Configuration)freemarkerManager
			.getConfiguration(servletContext);

		return configuration;
	}

	/**
	 * @return template model
	 */
	public static ScopesHashModel buildTemplateModel() {
		ServletContext servletContext = StrutsContextUtils.getServletContext();
		HttpServletRequest request = StrutsContextUtils.getServletRequest();
		HttpServletResponse response = StrutsContextUtils.getServletResponse();
		ValueStack stack = StrutsContextUtils.getValueStack();
		Object action = StrutsContextUtils.getAction();
		FreemarkerManager freemarkerManager = getFreemarkerManager();

		Configuration configuration = (Configuration)freemarkerManager
			.getConfiguration(servletContext);

		ScopesHashModel model = freemarkerManager.buildTemplateModel(stack, action,
			servletContext, request, response, configuration.getObjectWrapper());

		return model;
	}

	/**
	 * process template
	 * @param name template name
	 * @param writer writer
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static void processTemplate(String name, Writer writer) throws TemplateException, IOException {
		processTemplate(name, null, writer);
	}
	
	/**
	 * process template
	 * @param name template name
	 * @param context context map
	 * @param writer writer
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static void processTemplate(String name, Map context, Writer writer) throws TemplateException, IOException {
		ServletContext servletContext = StrutsContextUtils.getServletContext();
		Locale locale = StrutsContextUtils.getLocale();
		FreemarkerManager freemarkerManager = getFreemarkerManager();

		Configuration configuration = (Configuration)freemarkerManager
			.getConfiguration(servletContext);

		Template template = configuration.getTemplate(name, locale);

		processTemplate(template, context, writer);
	}
	
	/**
	 * process template
	 * @param name template name
	 * @return result
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static String processTemplate(String name) throws TemplateException, IOException {
		return processTemplate(name, (Map)null);
	}

	/**
	 * process template
	 * @param name template name
	 * @param context context map
	 * @return result
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static String processTemplate(String name, Map context) throws TemplateException, IOException {
		StringWriter sw = new StringWriter();
		processTemplate(name, context, sw);
		return sw.toString();
	}

	/**
	 * process template
	 * @param template template
	 * @param context context map
	 * @param writer writer
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static void processTemplate(Template template, Map context, Writer writer) throws TemplateException, IOException {
		ScopesHashModel model = buildTemplateModel();

		if (context != null) {
			model.putAll(context);
		}
		template.process(model, writer);
	}
	
	/**
	 * process template
	 * @param template template
	 * @return result
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static String processTemplate(Template template) throws TemplateException, IOException {
		return processTemplate(template, null);
	}

	/**
	 * process template
	 * @param template template
	 * @param context context map
	 * @return result
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static String processTemplate(Template template, Map context) throws TemplateException, IOException {
		StringWriter sw = new StringWriter();
		processTemplate(template, context, sw);
		return sw.toString();
	}

	/**
	 * process template
	 * @param string template string
	 * @param writer writer
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static void processStringTemplate(String string, Writer writer) throws TemplateException, IOException {
		processStringTemplate(string, null, writer);
	}
	
	/**
	 * process template
	 * @param string template string
	 * @param context context map
	 * @param writer writer
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static void processStringTemplate(String string, Map context, Writer writer) throws TemplateException, IOException {
		Template template = new Template("string", new StringReader(string), getConfiguration());
		
		processTemplate(template, context, writer);
	}
	
	/**
	 * process template
	 * @param string template string
	 * @return result
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static String processStringTemplate(String string) throws TemplateException, IOException {
		return processStringTemplate(string, (Map)null);
	}

	/**
	 * process template
	 * @param string template string
	 * @param context context map
	 * @return result
	 * @throws TemplateException if a template error occurs
	 * @throws IOException if an I/O error occurs
	 */
	public static String processStringTemplate(String string, Map context) throws TemplateException, IOException {
		StringWriter sw = new StringWriter();
		processStringTemplate(string, context, sw);
		return sw.toString();
	}
}
