/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package java.lang;

import java.io.PrintStream;

public class Throwable extends intrinsic.Error {

	private Throwable cause;
	private StackTraceElement[] stack;

	public Throwable() {
	}

	public Throwable(String message) {
		this(message, null);
	}

	public Throwable(String message, Throwable cause) {
		this.cause = cause;
		setMessage(message);
	}

	public Throwable(Throwable cause) {
		this((cause == null) ? null : cause.toString(), cause);
	}

	public Throwable fillInStackTrace() {
		return this;
	}

	public Throwable getCause() {
		return cause;
	}

	public String getLocalizedMessage() {
		return getMessage();
	}

	public native String getMessage()/*{
		return message;
	}*/;
	
	private native String getStackString() /*{
		var str:String = super.getStackTrace();
		var index:int = str.indexOf("\n");
		if (index == -1) return str;
		str = str.substring(index + 1);
		return str;
	}*/;

	public StackTraceElement[] getStackTrace() {
		return stack == null ? new StackTraceElement[0] : stack;
	}

	public Throwable initCause(Throwable cause) {
		if (this.cause != null) {
			throw new IllegalStateException("Can't overwrite cause");
		}
		if (cause == this) {
			throw new IllegalArgumentException("Self-causation not permitted");
		}
		this.cause = cause;
		return this;
	}

	public void printStackTrace() {
		printStackTrace(System.err);
	}

	public void printStackTrace(PrintStream out) {
		StringBuffer msg = new StringBuffer();
		Throwable currentCause = this;
		while (currentCause != null) {
			String causeMessage = currentCause.getMessage();
			if (currentCause != this) msg.append("Caused by: ");
			msg.append(currentCause.getClass().getName());
			msg.append(": ");
			if (causeMessage != null) msg.append(causeMessage);
			msg.append("\n");
			if (stack != null) {
				for (int i = 0; i < stack.length; i++) {
					msg.append("\t");
					msg.append(stack[i]);
				}
			} else {
				msg.append(getStackString());
			}
			currentCause = currentCause.getCause();
		}
		out.println(msg.toString());
	}
	
	private native void setMessage(String message)/*{
		this.message = message;
		this.name = Object(this).getClass__().getName__();
	}*/;

	public void setStackTrace(StackTraceElement[] stackTrace) {
		int length = stackTrace.length;
		StackTraceElement[] stack = new StackTraceElement[length];
		for (int i = 0; i < length; ++i) {
			if (stackTrace[i] == null) throw new NullPointerException();
			stack[i] = stackTrace[i];
		}
		this.stack = stack;
	}

	public String toString() {
		String className = getClass().getName();
		String msg = getLocalizedMessage();
		if (msg != null) {
			return className + ": " + msg;
		} else {
			return className;
		}
	}

}
