/**
 * File:    CustomNamespaceContext.java
 * Created: 21.03.2008
 *
 *
/*******************************************************************************
 * Copyright (c) 2008  Open Wide (www.openwide.fr)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Guillaume Decarnin, Open Wide, Lyon, France
 *      - Creation and implementation (From Jwt2XpdlService.java)
 *    Mickael Istria, Open Wide, Lyon, France
 *      - Extraction from Jwt2XpdlService.java to
 *        include it in common XSLT tools plugin
 *******************************************************************************/
package org.eclipse.jwt.transformations.xslt.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.xalan.processor.TransformerFactoryImpl;
import org.eclipse.jwt.transformations.api.TransformationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;

/**
 * This class wraps all XSLT stuff to call a XSL Transformation.
 * 
 * Anyone who wants to process an XSL transformation can simply instantiate this class
 * and call the {@link XSLTProcessor}{@link #processXSLT(String, String, InputStream...)}
 * method.
 * 
 * @author mistria
 * @since 0.6
 */
public class XSLTProcessor {

	@SuppressWarnings("nls")
	public void processXSLT(String inFilePath, String outFilePath, InputStream ... xsltInputs) throws TransformationException {
        
        File inFile = new File(inFilePath);
        if (!inFile.exists() || inFile.isDirectory() || !inFile.canRead()) {
        	throw new TransformationException("Can't open in file " + inFile.getAbsolutePath());
        }
        
        File outFile = new File(outFilePath);
        if (!outFile.exists()) {
        	try {
        		outFile.createNewFile();
        	} catch (IOException ex) {
        		throw new TransformationException("Cannot create output file " + outFile.getAbsolutePath(), ex);
        	}
        }
        
        if (outFile.isDirectory() || !outFile.canWrite()) {
        	throw new TransformationException("Can't open out file " + outFile.getAbsolutePath());
        }
        
        // init
    	//CustomXslFunctions.clear();

    	XMLReader reader;
    	SAXTransformerFactory stf;
    	
        try {
			// create reader and filters
			SAXParserFactory spf = SAXParserFactory.newInstance();
			spf.setNamespaceAware(true);
			reader = spf.newSAXParser().getXMLReader();
        } catch (ParserConfigurationException e) {
			throw new TransformationException("Can't init SAX parser", e);
		}  catch (SAXException e) {
			throw new TransformationException("Can't init SAX parser or XML reader", e);
		}
		
        
        try {
			stf = (SAXTransformerFactory) TransformerFactoryImpl.newInstance();
        } catch (TransformerFactoryConfigurationError e) {
			throw new TransformationException("Can't init transformer factory", e);
		}
		
		XMLReader parent = reader;
		int i = 0; // to log error
		for (InputStream xslIs : xsltInputs) {
			XMLFilter filter = null;
			try {
				filter = stf.newXMLFilter(new StreamSource(xslIs));
			} catch (TransformerConfigurationException e) {
				throw new TransformationException("Can't init transformer from XSLT", e);
			}
			filter.setParent(parent);
			parent = filter;
			i++;
		}
	
		try {
			// create source and result
			SAXSource source = new SAXSource(parent, new InputSource(new FileInputStream(inFile)));
			StreamResult result = new StreamResult(new FileOutputStream(outFile));
			
			// transformation
			Transformer transformer = stf.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.transform(source, result);
		} catch (Exception e) {
			throw new TransformationException("Error transforming " + inFile.getAbsolutePath()
					+ " to " + outFile.getAbsolutePath() + " using specified xsl path", e);
		}
	}
}
