//
//  FriendlyTransformerException.java
//
//  Created by Marc Liyanage on Mon Dec 24 2001.
//  Copyright (c) 2001 futureLAB AG.
//
//  http://www.futurelab.ch
//
//  May be reused in any form if the copyright notice is kept unchanged.
//

package ch.futurelab.xml;

import org.xml.sax.SAXParseException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.SourceLocator;
import java.lang.reflect.Method;


public class FriendlyTransformerException extends Exception {

    protected TransformerException te;

    private String errorLocation = "[location unknown]";
    private int errorLine = 0;
    private int errorColumn = 0;
    private String errorMessage = "";




    public FriendlyTransformerException(TransformerException te) {

        this.te = te;

        Class saxParseExecptionClass = null;
        Class transformerExecptionClass = null;

        try {
            saxParseExecptionClass = Class.forName("org.xml.sax.SAXParseException");
            transformerExecptionClass = Class.forName("javax.xml.transform.TransformerException");
        } catch (Exception e) {
            throw new RuntimeException("Unable to create FriendlyTramsformerException, unable to find classes by name!");
        }


        /*
         * What we're doing here is to get to the deepest Exception
         * if one was wrapped inside another by following the chain
         * of exceptions using getException().
         *
         */
        Throwable t = this.te.getException();

        try {

            while (true) {

                // We want to invoke getException() on all exceptions in the chain,
                // but these are all of different types (TransformException, SAXParse Exception).
                // All types support the getException() method but since they are not
                // derived from a common base class that implements this method, we
                // have to use reflection to get access to the method.
                //
                // This might throw MethodNotFound, which is one way to get out
                // of the infinite loop.
                //
                Method m = t.getClass().getMethod("getException", null);

                // OK, the exception supports a getException() method,
                // invoke it now.
                //
                Throwable temp = (Throwable) m.invoke(t, null);

                if (temp != null) {

                    // There is a wrapped exception in t, therefore we
                    // replace t with it and continue to look for nested exceptions.
                    //
                    t = temp;

                } else {

                    // There's no deeper wrapped exception in t,
                    // we've found the exception we're interested in and can break now.
                    // This is the second way to leave the loop
                    //
                    break;
                }
            }

        } catch (Exception e) { }



        if (t.getClass().equals(saxParseExecptionClass)) {

            SAXParseException spe = (SAXParseException) t;

            this.errorLocation = spe.getSystemId();
            this.errorLine     = spe.getLineNumber();
            this.errorColumn   = spe.getColumnNumber();
            this.errorMessage  = spe.getMessage();

        } else if (t.getClass().equals(transformerExecptionClass)) {

            TransformerException te2 = (TransformerException) t;
            SourceLocator sl = te2.getLocator();

            this.errorLocation = sl.getSystemId();
            this.errorLine     = sl.getLineNumber();
            this.errorColumn   = sl.getColumnNumber();
            this.errorMessage  = te2.getMessage();

        } else {

            this.errorMessage = t.getMessage();

        }


    }


    public String getSystemId() {
        return this.errorLocation;
    }

    public int getLineNumber() {
        return this.errorLine;
    }

    public int getColumnNumber() {
        return this.errorColumn;
    }
    public String getOriginalMessage() {
        return this.errorMessage;
    }

    public TransformerException getException() {
        return this.te;
    }





    public String getShortMessage() {

        return getLineNumber() + ":" + getColumnNumber() + "@" + getSystemId() + ": " + getOriginalMessage();

    }


    public String getMessage() {

        StringBuffer friendlyLongMessage = new StringBuffer();

        friendlyLongMessage.append("Unable to process because your input is invalid:\n\n");
        friendlyLongMessage.append("Location:      " + getSystemId() + "\n");
        friendlyLongMessage.append("Line number:   " + getLineNumber() + "\n");
        friendlyLongMessage.append("Column number: " + getColumnNumber() + "\n");
        friendlyLongMessage.append("Error message: " + getOriginalMessage() + "\n");

        return friendlyLongMessage.toString();

    }




}
