/*
 *  @author Ranides Atterwim <ranides@gmail.com>
 *  @copyright Ranides Atterwim
 *  @license WTFPL
 *  @url http://ranides.net/projects/assira
 */

package net.ranides.assira.trace;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author ranides
 */
public final class ExceptionInspector {

    private ExceptionInspector() { }

    public static List<Throwable> getCauseList(Throwable cause) {
        List<Throwable> result = new LinkedList<>();
        for(Throwable i=cause; null!=i; i=i.getCause() ) {
            result.add(i);
        }
        return result;
    }

    public static List<String> getMessageList(Throwable cause) {
        List<String> result = new LinkedList<>();
        for(Throwable item : getCauseList(cause) ) { result.add( item.getMessage() ); }
        return result;
    }

    public static List<String> getLocalizedMessageList(Throwable cause) {
        List<String> result = new LinkedList<>();
        for(Throwable item : getCauseList(cause) ) { result.add( item.getLocalizedMessage() ); }
        return result;
    }

    public static List<Class<?>> getClassList(Throwable cause) {
        List<Class<?>> result = new ArrayList<>();
        for(Throwable item : getCauseList(cause) ) { result.add( item.getClass() ); }
        return result;
    }

    public static List<String> getClassNameList(Throwable cause) {
        List<String> result = new LinkedList<>();
        for(Throwable item : getCauseList(cause) ) { result.add( item.getClass().getSimpleName() ); }
        return result;
    }

    public static List<String> getFilesList(Throwable cause) {
        List<String> result = new LinkedList<>();
        for(StackTraceElement item :cause.getStackTrace() ) {
            result.add( String.format("%4d : %s", item.getLineNumber(), item.getFileName()) );
        }
        return result;
    }
    
    public static String getStackTrace(Throwable cause) {
        StringWriter result = new StringWriter();
        PrintWriter writer = new PrintWriter(result);
        cause.printStackTrace(writer);
        writer.flush();
        return result.toString();
    }

    public static RuntimeException rethrow(Throwable cause) {
        new ExceptionErasure<RuntimeException>().rethrow(cause);
        
        // not reachable, wyjątek bez wrappowania leci linię wyżej
        throw new RuntimeException(cause); 
    }
    
    private static class ExceptionErasure<T extends Throwable> { // NOPMD
        
        @SuppressWarnings("unchecked")
        private void rethrow(Throwable exception) throws T {
            throw (T) exception;
        }

    }
    
    public static AssertionError assertError(String message, Throwable cause) {
        AssertionError error = new AssertionError(message);
        error.initCause(cause);
        return error;
    }
	
	public static void print(PrintStream stream, List<? extends Throwable> list) {
		if(list.isEmpty()) {
			return;
		}
		stream.println();
		stream.println("CauseList: ");
		for(int i=0, n=list.size(); i<n; i++) {
			stream.println("\t[" + i + "] " + list.get(i));
		}
		stream.println();
		for(int i=0, n=list.size(); i<n; i++) {
			stream.print("CauseList details["+i+"]: ");
			list.get(i).printStackTrace(stream);
		}
    }

    public static void print(PrintWriter writer, List<? extends Throwable> list) {
        if(list.isEmpty()) {
			return;
		}
		writer.println();
		writer.println("CauseList: ");
		for(int i=0, n=list.size(); i<n; i++) {
			writer.println("\t[" + i + "] " + list.get(i));
		}
		writer.println();
		for(int i=0, n=list.size(); i<n; i++) {
			writer.println("Caused by["+i+"]:");
			list.get(i).printStackTrace(writer);
		}
    }

}
