package eu.dnetlib.springutils.stringtemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;

import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateErrorListener;
import org.antlr.stringtemplate.StringTemplateGroup;

/**
 * This subclass overrides the getFileNameFromTemplateName() and getTemplateNameFromFileName() methods in
 * org.antlr.stringtemplate.StringTemplateGroup in order to retrieve template files from the classpath.
 */

public class ClassPathStringTemplateGroup extends StringTemplateGroup {

	/**
	 * uncheked exception.
	 */
	private static final String UNCHECKED = "unchecked";

	/**
	 * apply this prefix to all templates.
	 */
	private String prefix = "";

	public ClassPathStringTemplateGroup(final String arg0) {
		super(arg0);
	}

	public ClassPathStringTemplateGroup(final Reader arg0) {
		super(arg0);
	}

	public ClassPathStringTemplateGroup(final String arg0, final String arg1) {
		super(arg0, arg1);
	}

	@SuppressWarnings(UNCHECKED)
	public ClassPathStringTemplateGroup(final String arg0, final Class arg1) {
		super(arg0, arg1);
	}

	public ClassPathStringTemplateGroup(final Reader arg0, final StringTemplateErrorListener arg1) {
		super(arg0, arg1);
	}

	@SuppressWarnings(UNCHECKED)
	public ClassPathStringTemplateGroup(final Reader arg0, final Class arg1) {
		super(arg0, arg1);
	}

	@SuppressWarnings(UNCHECKED)
	public ClassPathStringTemplateGroup(final String arg0, final String arg1, final Class arg2) {
		super(arg0, arg1, arg2);
	}

	@SuppressWarnings(UNCHECKED)
	public ClassPathStringTemplateGroup(final Reader arg0, final Class arg1, final StringTemplateErrorListener arg2) {
		super(arg0, arg1, arg2);
	}

	@SuppressWarnings(UNCHECKED)
	public ClassPathStringTemplateGroup(final Reader arg0, final Class arg1, final StringTemplateErrorListener arg2, final StringTemplateGroup arg3) {
		super(arg0, arg1, arg2, arg3);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.antlr.stringtemplate.StringTemplateGroup#getFileNameFromTemplateName(java.lang.String)
	 *
	 * @param filename
	 *            with relative path
	 * @returns templatename
	 *
	 */
	@Override
	public String getFileNameFromTemplateName(final String fileName) {
		return getPrefix() + super.getFileNameFromTemplateName(fileName);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.antlr.stringtemplate.StringTemplateGroup#getTemplateNameFromFileName(java.lang.String)
	 */
	@Override
	public String getTemplateNameFromFileName(final String fileName) {
		if (fileName.startsWith(getPrefix()))
			return super.getTemplateNameFromFileName(fileName.substring(getPrefix().length()));
		else
			return super.getTemplateNameFromFileName(fileName);
	}

	/**
	 * transforms a package name in a path and sets it as prefix.
	 *
	 * @param packageName
	 *            java package name
	 */
	public void setPackage(final String packageName) {
		setPrefix("/" + packageName.replace('.', '/') + "/");
	}

	public String getPrefix() {
		return prefix;
	}

	public void setPrefix(final String prefix) {
		this.prefix = prefix;
	}

	/**
	 * Base implementation doesn't work during integration tests for an obscure problem in Classloader vs Class
	 * getResourceAsStream, so we rewrite the important stuff here.
	 *
	 * {@inheritDoc}
	 *
	 * @see org.antlr.stringtemplate.StringTemplateGroup#loadTemplateFromBeneathRootDirOrCLASSPATH(java.lang.String)
	 */
	@Override
	protected StringTemplate loadTemplateFromBeneathRootDirOrCLASSPATH(final String fileName) {

		final String name = getTemplateNameFromFileName(fileName);
		final InputStream input = getClass().getResourceAsStream(fileName);
		if(input == null)
			throw new IllegalArgumentException("resource " + fileName + " doesn't exist");

		BufferedReader breader = null; // NOPMD: needed in finally block
		try {
			breader = new BufferedReader(getInputStreamReader(input));
			return loadTemplate(name, breader);
		} catch (IOException ioe) {
			error("Problem reading template file: " + fileName, ioe);
		} finally {
			if (breader != null) {
				try {
					breader.close();
				} catch (IOException ioe2) {
					error("Cannot close template file: " + fileName, ioe2);
				}
			}
		}
		return null;
	}

}
