/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.fukurou.system;

import java.io.PrintStream ;
import java.io.PrintWriter ;

/**
 * 共通的に使用されるRuntimeExceptionクラスです。
 *
 * RuntimeException を継承しているため、try{} catch() {} は不要です。
 * 本システムでは、すべてこのエクセプションクラスを継承させたクラスを作成し、用途によって、
 * 使い分けるようにします。つまり、他のどのような、Throwable が発生したとしても、一旦、
 * try{} catch() {} で受けて、このクラスのサブクラスを、再度 throw させます。
 * そして、必要であれば、try{} catch() {} を用いて捕まえて、それぞれの対応処理を行います。
 *
 * このクラスには、元々の発生したエクセプション( Throwable )を引数にとり、
 * その printStackTrace()情報を、自分自身のトレース情報に含めます。
 * また、引数にオブジェクトを渡すことができますので、object.toString() で、オブジェクトの
 * 状態を表示できるようにしておけば、手軽にデバッグに使うことが可能になります。
 *
 * このRuntimeExceptionを使うと、ThrowUtil#ogStackTrace(String,Throwable) に準拠した
 * StackTrace を作成します。これは、最初の３行＋org.opengionを含む行だけのエラーを出力
 * しますので、エラーログの容量を大幅に抑えることが可能です。
 *
 * @og.group エラー処理
 * @og.rev 6.4.2.0 (2016/01/29) 新規作成
 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
 *
 * @version  6.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK8.0,
 */
public class OgRuntimeException extends RuntimeException {
	private static final long serialVersionUID = 642020160129L ;

//	private final Throwable orgTh ;
//	private		String		addMsg ;
	private final StringBuilder msgBuf = new StringBuilder( HybsConst.BUFFER_MIDDLE );		// 7.1.0.0 (2020/01/20)

	/**
	 *  詳細メッセージを指定しないで OgRuntimeException を構築します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 *
	 * @see		java.lang.RuntimeException#RuntimeException()
	 */
	public OgRuntimeException() {
		super();
//		orgTh = null;
	}

	/**
	 *  指定された詳細メッセージを持つ OgRuntimeException を構築します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 6.9.2.1 (2018/03/12) 引数のメッセージを、内部メッセージにセットしておきます。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @param	msg	詳細メッセージ
	 * @see		java.lang.RuntimeException#RuntimeException(String)
	 */
	public OgRuntimeException( final String msg ) {
		super( msg );
//		orgTh = null;
//		if( msg != null ) { addMsg = msg; }				// 6.9.2.1 (2018/03/12)
		addMessage( msg );								// 7.1.0.0 (2020/01/20)
	}

	/**
	 *  指定されたThrowableオブジェクトを持つ OgRuntimeException を構築します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @param	th	例外Throwableオブジェクト
	 * @see		java.lang.RuntimeException#RuntimeException(Throwable)
	 */
	public OgRuntimeException( final Throwable th ) {
		super( th );
		addMessage( th );								// 7.1.0.0 (2020/01/20)

//		super();
//		orgTh = th ;
	}

	/**
	 *  指定された詳細メッセージと、Throwableオブジェクトを持つ OgRuntimeException を構築します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 6.9.2.1 (2018/03/12) 引数のメッセージを、内部メッセージにセットしておきます。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @param	msg	詳細メッセージ
	 * @param	th	例外Throwableオブジェクト
	 * @see		java.lang.RuntimeException#RuntimeException(String,Throwable)
	 */
	public OgRuntimeException( final String msg,final Throwable th ) {
		super( msg,th );
//		super( msg );
//		orgTh = th ;
//		if( msg != null ) { addMsg = msg; }				// 6.9.2.1 (2018/03/12)
		addMessage( msg );								// 7.1.0.0 (2020/01/20)
		addMessage( th );								// 7.1.0.0 (2020/01/20)
	}

	/**
	 * 発生元もメッセージも含めたメッセージ文字列を返します。
	 *
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @param    th  元のThrowableオブジェクト
	 */
	public final void addMessage( final Throwable th ) {
		Throwable th2 = th;
		while( th2 != null ) {
			final String msg2 = th2.getLocalizedMessage();
			if( msg2 != null && msgBuf.indexOf( msg2 ) < 0 ) {		// メッセージの重複を除外
				msgBuf.append( msg2 ).append( HybsConst.CR );
			}
			th2 = th2.getCause();
		}
	}

	/**
	 *  指定された追加メッセージを、printStackTrace() 出力時に、合成します。
	 *
	 * 主に、openGionバージョンや、その他追記したいメッセージを登録することで、
	 * printStackTrace() 出力時に、合成できます。
	 * 複数のメッセージは登録できません。最後に登録したメッセージのみ使用されます。
	 * なお、null のメッセージは登録できません。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @param	msg	追加メッセージ
	 */
	public final void addMessage( final String msg ) {
//		if( msg != null ) { addMsg = msg; }
		if( msg != null && msgBuf.indexOf( msg ) < 0 ) {		// メッセージの重複を除外
			msgBuf.append( msg ).append( HybsConst.CR );
		}
	}

	/**
	 * このスロー可能オブジェクトの詳細メッセージ文字列を返します。
	 *
	 * 内部メッセージに、原因のメッセージも含めたメッセージです。
	 *
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @return	詳細メッセージ文字列
	 * @og.rtnNotNull
	 */
	@Override
	public String getMessage() {
		return msgBuf.toString().trim();
	}

	/**
	 * このスロー可能オブジェクトおよびそのバックトレースを標準エラー・ストリームに出力します。
	 *
	 * ここのメソッドは、このThrowableオブジェクトのスタック・トレースを、System.errフィールドの
	 * 値であるエラー出力ストリームで出力します。出力の先頭行には、このオブジェクトに対する
	 * toString()メソッドの結果が含まれます。
	 * 残りの行は、以前にfillInStackTrace()メソッドによって記録されたデータを表します。
	 * この情報の書式は実装によって異なりますが、典型的な書式の例を次に示します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をStackTraceに入れる。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @see		java.lang.RuntimeException#printStackTrace()
	 */
	@Override
	public void printStackTrace() {
//		System.err.println( ThrowUtil.ogStackTrace( addMsg,orgTh ) );
//		System.err.println( ThrowUtil.ogStackTrace( addMsg,this ) );
		System.err.println( ThrowUtil.ogStackTrace( getMessage(),this ) );		// 7.1.0.0 (2020/01/20)
	}

	/**
	 * このスロー可能オブジェクトとそのバックトレースを指定された印刷ストリームに出力します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 * @og.rev 7.1.0.0 (2020/01/20) 内部メッセージに、原因のメッセージも含める。
	 *
	 * @param	ps 出力する印刷ストリーム
	 * @see		java.lang.RuntimeException#printStackTrace(PrintStream)
	 */
	@Override
	public void printStackTrace( final PrintStream ps ) {
//		ps.println( ThrowUtil.ogStackTrace( addMsg,orgTh ) );
//		ps.println( ThrowUtil.ogStackTrace( addMsg,this ) );
		ps.println( ThrowUtil.ogStackTrace( getMessage(),this ) );				// 7.1.0.0 (2020/01/20)
	}

	/**
	 * このスロー可能オブジェクトとそのバックトレースを指定されたプリント・ライターに出力します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 7.0.5.0 (2019/09/09) 自分自身をsuperに入れる。
	 *
	 * @param	pw 出力するプリント・ライター
	 * @see		java.lang.RuntimeException#printStackTrace(PrintWriter)
	 * @see		ThrowUtil#ogStackTrace(String,Throwable)
	 */
	@Override
	public void printStackTrace( final PrintWriter pw ) {
//		pw.println( ThrowUtil.ogStackTrace( addMsg,orgTh ) );
//		pw.println( ThrowUtil.ogStackTrace( addMsg,this ) );
		pw.println( ThrowUtil.ogStackTrace( getMessage(),this ) );				// 7.1.0.0 (2020/01/20)
	}

	/**
	 * スタックトレース要素の配列を返します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。
	 * @og.rev 6.9.3.0 (2018/03/26) 内部 Throwable が null の場合、長さゼロの StackTraceElementを返します。
	 * @og.rev 7.0.5.0 (2019/09/09) 廃止
	 * @og.rev 7.0.6.4 (2019/11/29) 復活
	 *
	 * @return	スタックトレース要素の配列
	 * @see		java.lang.RuntimeException#getStackTrace()
	 * @see		ThrowUtil#selectElement(Throwable,int)
	 */
	@Override
	public StackTraceElement[] getStackTrace() {
		return ThrowUtil.selectElement( super.getCause() , ThrowUtil.MIN_STACK_SIZE );
	}

	/**
	 * このスロー可能オブジェクトの原因を返しますが、原因が存在しないか不明な場合はnullを返します。
	 *
	 * @og.rev 7.0.6.4 (2019/11/29) 常に null を返すようにします。
	 *
	 * @return	このスロー可能オブジェクトの原因（常に null）
	 */
	@Override
	public Throwable getCause() {
//		return super.getCause() ;
		return null ;
	}
}
