package de.hsadmin.core.qserv;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang.CharEncoding;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import de.hsadmin.mods.dom.Domain;
import de.hsadmin.mods.pac.Hive;
import de.hsadmin.mods.pac.Pac;

public class VelocityProcessor extends AbstractProcessor {

	private static final long serialVersionUID = 2L;
	
	static {
		Properties props = new Properties();
		props.getProperty("resource.loader", "file");
		props.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
		Velocity.init(props);
	}
	
	private String content;
	private String targetPath;
	private boolean overwriteTarget;
	private String errorMessage;

	public VelocityProcessor(String templateName, Hive hive, String targetPath, boolean overwriteTarget) {
		errorMessage = "";
		this.targetPath = targetPath;
		this.overwriteTarget = overwriteTarget;
		VelocityContext context = new VelocityContext();
		context.put("hive", hive);
		mergeTemplate(templateName, context);
	}

	public VelocityProcessor(String templateName, Pac pac, String targetPath, boolean overwriteTarget) {
		this.targetPath = targetPath;
		this.overwriteTarget = overwriteTarget;
		VelocityContext context = new VelocityContext();
		context.put("pac", pac);
		context.put("hive", pac.getHive());
		mergeTemplate(templateName, context);
	}
	
	public VelocityProcessor(String templateName, Domain dom, String targetPath, boolean overwriteTarget) {
		this.targetPath = targetPath;
		this.overwriteTarget = overwriteTarget;
		VelocityContext context = new VelocityContext();
		context.put("dom", dom);
		Pac pac = dom.getUser().getPac();
		context.put("pac", pac);
		context.put("hive", pac.getHive());
		mergeTemplate(templateName, context);
	}

	public VelocityProcessor(String templateName, Map<String, Object> templateVars, Domain dom, String targetPath, boolean overwriteTarget) {
		this.targetPath = targetPath;
		this.overwriteTarget = overwriteTarget;
		VelocityContext context = new VelocityContext();
		context.put("dom", dom);
		Pac pac = dom.getUser().getPac();
		context.put("pac", pac);
		context.put("hive", pac.getHive());
		for (String key : templateVars.keySet()) {
			context.put(key, templateVars.get(key));
		}
		mergeTemplate(templateName, context);
	}

	public VelocityProcessor(String templateName, HashMap<String, Object> templateVars, 
			String targetPath, boolean overwriteTarget) {
		this.targetPath = targetPath;
		this.overwriteTarget = overwriteTarget;
		VelocityContext context = new VelocityContext();
		for (String key : templateVars.keySet()) {
			context.put(key, templateVars.get(key));
		}
		mergeTemplate(templateName, context);
	}

	private void mergeTemplate(String templateName, VelocityContext context) {
		StringWriter writer = new StringWriter();
		Velocity.mergeTemplate(templateName, CharEncoding.UTF_8, context, writer);
		this.content = writer.toString();
	}
	
	@Override
	public Object process() throws ProcessorException {
		try {
			File file = new File(targetPath);
			if (file.exists() && !overwriteTarget) {
				errorMessage = "did not overwrite existing file " + targetPath;
				return errorMessage;
			}
			if (!file.exists() || file.canWrite()) {
				BufferedWriter writer = new BufferedWriter(new FileWriter(file));
				writer.append(content);
				writer.close();
			} else {
				errorMessage = "could not write file " + targetPath;
				throw new ProcessorException(errorMessage);
			}
			return "wrote file " + targetPath;
		} catch (IOException e) {
			errorMessage = e.getMessage();
			throw new ProcessorException(e);
		}
	}

	@Override
	public String logInfo() {
		StringBuffer log = new StringBuffer("VelocityProcessor\n");
		log.append("Target: ");
		log.append(targetPath);
		log.append("\n");
		log.append("Error: ");
		log.append(errorMessage);
		log.append("\n");
		return log.toString();
	}

}
