/*
 * Main.java
 * 
 * Created on Oct 27, 2007, 1:21:32 PM
 */

package saxon.xslt.stacktrace;

import java.io.File;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.TransformerFactoryImpl;
import net.sf.saxon.trans.XPathException;

/**
 * Sample application that run a stylesheet an output the XSLT stacktrace in case of error.
 *
 * <p>The stylesheet used is {@code src/saxon/xslt/stacktrace/style.xsl}.</p>
 * 
 * @author Florent Georges
 */
public class Main
{
    public static void main(String[] args)
            throws TransformerException
    {
        TransformerFactory factory = TransformerFactoryImpl.newInstance();
        Source style = new StreamSource(new File("src/saxon/xslt/stacktrace/style.xsl"));
        Transformer trans = factory.newTransformer(style);
        trans.setErrorListener(new NullErrorListener());
        try {
            trans.transform(style, new StreamResult(System.out));
        }
        catch ( XPathException ex ) {
            System.err.println(ex.getErrorCodeLocalPart() + ": " + ex.getMessage());
            StackFrame stack = StackFrame.makeStack(ex);
            DisplayerStackVisitor visitor = new DisplayerStackVisitor();
            stack.acceptVisitor(visitor);
            visitor.finish();
        }
    }

    /**
     * Does nothing, to supress error messages from Saxon itself.
     */
    private static class NullErrorListener
            implements ErrorListener
    {
        public void warning(TransformerException ex)
                throws TransformerException {
        }
        public void error(TransformerException ex)
                throws TransformerException {
        }
        public void fatalError(TransformerException ex)
                throws TransformerException {
        }
    }

    /**
     * Stack visitor that display the stack as text on {@code System.err}.
     */
    private static class DisplayerStackVisitor
            implements StackVisitor
    {
        public void visitFunctionFrame(FunctionFrame frame)
        {
            doVisit(frame);
            myHead = "  called ";
        }

        public void visitTemplateFrame(TemplateFrame frame)
        {
            doVisit(frame);
            myHead = frame.isCalled() ? "  called " : "  applied ";
        }

        public void finish()
        {
            System.err.println(myHead + "from external application");
        }

        private void doVisit(StackFrame frame)
        {
            int line = frame.getLocator().getLineNumber();
            int col = frame.getLocator().getColumnNumber();
            String pos = getFile(frame) + ":" + line + ( col < 0 ? "" : ":" + col );
            System.err.println(myHead + "in " + frame + " (at " + pos + ")");
            String path = frame.getPath();
            if ( path != null ) {
                System.err.println("    `-> " + path);
            }
        }

        private static String getFile(StackFrame frame)
        {
            String sysid = frame.getLocator().getSystemId();
            int slash = sysid.lastIndexOf('/');
            if ( slash < 0 ) {
                return sysid;
            }
            else {
                return sysid.substring(slash + 1);
            }
        }

        private String myHead = "  ";
    }
}
