package com.iverticalleap.util.exception;

import java.io.Serializable;

/**
 *  Wrapping exception is an abstract base class defining the API for the
 *  exception holder that is used to track all parent exceptions, source classes
 *  and methods references that caused a failure. Every exception caught must
 *  not be simply thrown but rather it should be wrapped first with the
 *  exception wrapper to provide better error processing.
 *
 *@author     Kevin Ross
 *@created    October 1, 2001
 */
public class NestedException extends Exception implements Serializable {
    
    private Throwable rootThrowable = null;
    private String failedClassName = null;
    private String failedMethodName = null;
    
    
    //    boolean isRootThrowable = false;
    
    /**
     *  Constructor.
     *
     *@param  failedClass       Reference to the class that caused an error.
     *@param  failedMethodName  Method name that caused an error.
     *@param  errorMessage      Custom error message.
     *@param  rootThrowable     Reference to the parent exception resulted from the
     *      failure.
     */
    public NestedException(Object failedClass, String failedMethodName, String errorMessage, Throwable rootThrowable) {
        
        super(errorMessage);
        init(failedClass, failedMethodName, rootThrowable);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClass       Reference to the class that caused an error.
     *@param  failedMethodName  Method name that caused an error.
     *@param  errorMessage      Custom error message.
     */
    public NestedException(Object failedClass, String failedMethodName, String errorMessage) {
        
        super(errorMessage);
        init(failedClass, failedMethodName, null);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClass       Reference to the class that caused an error.
     *@param  failedMethodName  Method name that caused an error.
     *@param  rootThrowable     Reference to the parent exception resulted from the
     *      failure.
     */
    public NestedException(Object failedClass, String failedMethodName, Throwable rootThrowable) {
        
        super();
        init(failedClass, failedMethodName, rootThrowable);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClass       Reference to the class that caused an error.
     *@param  failedMethodName  Method name that caused an error.
     */
    public NestedException(Object failedClass, String failedMethodName) {
        
        super();
        init(failedClass, failedMethodName, null);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClassName   Class name that caused an error..
     *@param  failedMethodName  Method name that caused an error.
     *@param  errorMessage      Custom error message.
     *@param  rootThrowable     Reference to the parent exception resulted from the
     *      failure.
     */
    public NestedException(String failedClassName, String failedMethodName, String errorMessage, Throwable rootThrowable) {
        
        super(errorMessage);
        init(failedClassName, failedMethodName, rootThrowable);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClassName   Class name that caused an error..
     *@param  failedMethodName  Method name that caused an error.
     *@param  errorMessage      Custom error message.
     */
    public NestedException(String failedClassName, String failedMethodName, String errorMessage) {
        
        super(errorMessage);
        init(failedClassName, failedMethodName, null);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClassName   Class name that caused an error..
     *@param  failedMethodName  Method name that caused an error.
     *@param  rootThrowable     Reference to the parent exception resulted from the
     *      failure.
     */
    public NestedException(String failedClassName, String failedMethodName, Throwable rootThrowable) {
        
        super();
        init(failedClassName, failedMethodName, rootThrowable);
    }
    
    
    /**
     *  Constructor.
     *
     *@param  failedClassName   Class name that caused an error..
     *@param  failedMethodName  Method name that caused an error.
     */
    public NestedException(String failedClassName, String failedMethodName) {
        
        super();
        init(failedClassName, failedMethodName, null);
    }
    
    
    /**
     *  Returns a reference to a parent exception.
     *
     *@return    Parent exception.
     */
    public Throwable getRootThrowable() {
        
        return rootThrowable;
    }
    
    
    /**
     *  Returns a name of the class that failed.
     *
     *@return    Class Name.
     */
    public String getFailedClassName() {
        
        return failedClassName;
    }
    
    
    /**
     *  Return a name of a method that failed.
     *
     *@return    Method name.
     */
    public String getFailedMethodName() {
        
        return failedMethodName;
    }
    
    
    /**
     *  Determines if this instance of the ExceptionWrapper contains the original
     *  Exception.
     *
     *@return    true/false Depending of the origin of the wrapped exception
     */
    public boolean isRootThrowable() {
        
        if (rootThrowable == null) {
            return true;
        }
        else {
            return false;
        }
    }
    
    
    /**
     *  Overrides toString and defines the way this exception is being displayed by
     *  using current ExceptionFormatIF implementation.
     *
     *@return    String representation of this exception.
     */
    public String toString() {
        
        String string = null;
        try {
            
            string = getExceptionFormatter().format(this);
        }
        catch (NestedException e) {
            
            //			SingletonThrowableHandler.instance().handleSilentException(e);
            System.out.println("NestedException.toString() caught exception: ");
            e.printStackTrace();
        }
        
        return string;
    }
    
    
    /**
     *  Overrides the default ExceptionFormat used to convert the exception to
     *  String representation.
     *
     *@return    The ExceptionFormatter value
     */
    protected ExceptionFormatter getExceptionFormatter() {
        
        return SingletonExceptionFormatter.instance();
    }
    
    
    /**
     *  Description of the Method
     *
     *@param  failedClassName   Description of Parameter
     *@param  failedMethodName  Description of Parameter
     *@param  rootThrowable     Description of Parameter
     */
    private void init(String failedClassName, String failedMethodName, Throwable rootThrowable) {
        
        this.failedClassName = failedClassName;
        this.failedMethodName = failedMethodName;
        this.rootThrowable = rootThrowable;
        
        //        if(rootThrowable == null){
        //
        //            isRootThrowable = true;
        //        }
    }
    
    
    /**
     *  Description of the Method
     *
     *@param  failedClass       Description of Parameter
     *@param  failedMethodName  Description of Parameter
     *@param  rootThrowable     Description of Parameter
     */
    private void init(Object failedClass, String failedMethodName, Throwable rootThrowable) {
        
        init(failedClass.getClass().getName(), failedMethodName, rootThrowable);
    }
}
