/**
 *  Licensed under GPL. For more information, see
 *    http://jaxodraw.sourceforge.net/license.html
 *  or the LICENSE file in the jaxodraw distribution.
 */

package net.sf.jaxodraw.util;


import java.io.File;
import java.io.IOException;

import java.util.Map;

import javax.xml.transform.Source;
import javax.xml.transform.SourceLocator;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/** Perform xslt transformations. */
public final class JaxoXsltTransformer {

    /**
     * Transform an xml file with xslt.
     *
     * @param inFile the file to transform.
     * @param outFile the target file.
     * @param xslFile the xslt stylesheet.
     * @param parameters a Map of parameters for the transformation. May be null.
     * @param properties a Map of output properties for the transformation. May be null.
     *
     * @throws IOException if an I/O error happens.
     */
    public static void transform(final File inFile, final File outFile, final File xslFile,
            Map<String, String> parameters, Map<String, String> properties) throws IOException {
        try {
            // baseDir for xsl:include, xsl:import, etc.
            final String baseDir = xslFile.getParent();
            final MyResolver resolver = new MyResolver(baseDir);

            final TransformerFactory factory = TransformerFactory.newInstance();
            final Templates template = factory.newTemplates(new StreamSource(xslFile));
            final Transformer xformer = template.newTransformer();

            xformer.setURIResolver(resolver);

            if (parameters != null && !parameters.isEmpty()) {
                for (Map.Entry<String, String> entry : parameters.entrySet()) {
                    xformer.setParameter(entry.getKey(), entry.getValue());
                }
            }

            if (properties != null && !properties.isEmpty()) {
                for (Map.Entry<String, String> entry : properties.entrySet()) {
                    xformer.setOutputProperty(entry.getKey(), entry.getValue());
                }
            }

            xformer.transform(new StreamSource(inFile), new StreamResult(outFile));
        } catch (TransformerException e) {
            final SourceLocator locator = e.getLocator();
            final String info = "column: " + locator.getColumnNumber() + "line: " + locator.getLineNumber()
                    + "publicId: " + locator.getPublicId() + "systemId: " + locator.getSystemId();
            throw new IOException(info, e);
        }
    }

    private static class MyResolver implements URIResolver {
        private final String basePath;

        MyResolver(final String path) {
            this.basePath = path;
        }

        public Source resolve(final String href, final String base) {
            final StringBuffer path = new StringBuffer(this.basePath);
            path.append(File.separator).append(href);

            final File file = new File(path.toString());

            if (file.exists()) {
                return new StreamSource(file);
            }

            return null;
        }
    }

    private JaxoXsltTransformer() {
        // do not instantiate
    }
}
