/*
 * 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.util;

import java.util.List;
import java.util.ArrayList;

import org.opengion.fukurou.system.ThrowUtil;							// 6.5.0.1 (2016/10/21)
import static org.opengion.fukurou.system.HybsConst.CR;					// 6.1.0.0 (2014/12/26) refactoring
import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;		// 6.4.3.1 (2016/02/12) refactoring

/**
 * エラーメッセージを受け渡すときに使用するクラスです。
 * 結果値として、0:正常 1:警告 2:異常 8:EXCEPTION 9:ORACLEエラー を持っています。
 *
 * @og.rev 6.5.0.1 (2016/10/21) 連結を、StringBuilder#appendのように、自分自身に出来るように、修正します。
 *
 * @og.group エラー処理
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class ErrorMessage {
	/** 結果値 0:正常 {@value} */
	public static final int OK        = 0;
	/** 結果値 1:警告 {@value} */
	public static final int WARNING   = 1;
	/** 結果値 2:異常 {@value} */
	public static final int NG        = 2;
	/** 結果値 8:EXCEPTION {@value} */
	public static final int EXCEPTION = 8;
	/** 結果値 9:ORACLEエラー {@value} */
	public static final int ORCL_ERR  = 9;

	private int			maxKekka	= OK;
	private String		title		= "";
	private final List<ErrMsg> list	= new ArrayList<>();

	private boolean  setPgStep	;	// 3.8.9.5 (2007/09/12)

	/**
	 * デフォルトコンストラクター
	 * 詳細メッセージを指定しないで ErrorMessage を構築します。
	 * (明示しないと、引き通付きコンストラクタのみのクラスになってしまいます。)
	 */
	public ErrorMessage() {
		setTitle( "NO TITLE" );
	}

	/**
	 * タイトルを指定して ErrorMessage を構築します。
	 *
	 * @param	title	タイトル
	 */
	public ErrorMessage( final String title ) {
		setTitle( title );
	}

	/**
	 * 指定されたエラー情報を追加登録します。
	 * これは、行番号０、結果：NG IDは無し(ゼロ文字列)です。
	 * 引数の メッセージ が null の場合は,何もしません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 連結を、StringBuilder#appendのように、自分自身に出来るように、修正します。
	 * @og.rev 6.9.0.0 (2018/01/31) null引数の場合は、NGも登録せず、スルーします。
	 *
	 * @param    args String... メッセージの引数(可変引数)
	 * @return	自分自身
	 */
	public ErrorMessage addMessage( final String... args ) {
		if( args != null ) {
			addMessage( 0,NG,"",args );
		}
		return this;
	}

	/**
	 * 指定されたエラー情報を追加登録します。
	 *
	 * ただし、id が null の場合は、登録しません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 連結を、StringBuilder#appendのように、自分自身に出来るように、修正します。
	 *
	 * @param	no	行番号
	 * @param	kekka	結果 0:正常 1:警告 2:異常
	 * @param	id	メッセージID
	 * @param    args String... メッセージの引数(可変引数)
	 * @return	自分自身
	 */
	public ErrorMessage addMessage( final int no,final int kekka,final String id,final String... args ) {
		if( id != null ) {
			final ErrMsg msg = new ErrMsg( no,kekka,null,null,id,args );
			list.add( msg );
			if( maxKekka < kekka ) {  maxKekka = kekka; }
		}
		return this;
	}

	/**
	 * 指定されたThrowableオブジェクトを元に、エラー情報を追加登録します。
	 * この処理が、一番最初の場合は、行番号０、IDは無し(ゼロ文字列)です。
	 * 結果は、NG で登録します。
	 * ここでは、最後に登録された ErrMsg を元に、行番号、id をコピーして使用します。
	 * 引数の Throwableオブジェクト が null の場合は,何もしません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 新規追加
	 * @og.rev 6.9.0.0 (2018/01/31) null引数の場合は、NGも登録せず、スルーします。
	 * @og.rev 6.9.2.1 (2018/03/12) スタックトレース情報の処理方法を変更
	 *
	 * @param    th   printStackTraceすべき元のThrowableオブジェクト
	 * @return	自分自身
	 * @see		#addMessage(Throwable,boolean)
	 */
	public ErrorMessage addMessage( final Throwable th ) {
		return addMessage( th , false );
	}

	/**
	 * 指定されたThrowableオブジェクトを元に、エラー情報を追加登録します。
	 *
	 * isST 引数により、スタックトレース情報を利用するかどうか指定できます。
	 * 結果は、NG で登録します。
	 * この処理が、一番最初の場合は、行番号０、IDは無し(ゼロ文字列)です。
	 * ここでは、最後に登録された ErrMsg を元に、行番号、id をコピーして使用します。
	 * 引数の Throwableオブジェクト が null の場合は,何もしません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 新規追加
	 * @og.rev 6.9.0.0 (2018/01/31) null引数の場合は、NGも登録せず、スルーします。
	 * @og.rev 6.9.2.1 (2018/03/12) スタックトレース情報の処理方法を変更
	 *
	 * @param    th   printStackTraceすべき元のThrowableオブジェクト
	 * @param    isST スタックトレース情報を使用するかどうか。
	 * @return	自分自身
	 * @see		ThrowUtil#ogStackTrace(Throwable)
	 * @see		ThrowUtil#ogThrowMsg(String,Throwable)
	 */
	public ErrorMessage addMessage( final Throwable th , final boolean isST ) {
		if( th != null ) {
			final String thMsg = isST	? ThrowUtil.ogStackTrace( th )
//										: ThrowUtil.ogThrowMsg( th.getMessage(),th );
										: ThrowUtil.ogThrowMsg( null,th );

			final int size = list.size();
			if( size == 0 ) {
				addMessage( 0 , NG , "" , thMsg );
			}
			else {
				final ErrMsg msg = list.get( size-1 );			// 最後のErrMsgを取り出す。
				addMessage( msg.getNo() , NG , msg.getId() , thMsg );
			}
		}

		return this;
	}

	/**
	 * 指定されたエラーオブジェクトを追加登録します。
	 * 追加するErrMsgが、内部の結果値より大きい場合は、その結果値にセットします。
	 * つまり、内部結果値は、登録されたすべてのエラーオブジェクトの最大値です。
	 * 引数の ErrMsgオブジェクト が null の場合は,何もしません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 連結を、StringBuilder#appendのように、自分自身に出来るように、修正します。
	 * @og.rev 6.9.0.0 (2018/01/31) null引数の場合は、NGも登録せず、スルーします。
	 *
	 * @param	msg	エラーオブジェクト
	 * @return	自分自身
	 */
	public ErrorMessage addMessage( final ErrMsg msg ) {
		if( msg != null ) {
			list.add( msg );
			if( maxKekka < msg.getKekka() ) {  maxKekka = msg.getKekka(); }
			if( msg.getPg() != null || msg.getStep() != null ) { setPgStep = true; }  // 3.8.9.5 (2007/09/12)
		}

		return this;
	}

	/**
	 * 指定された ErrorMessageオブジェクトを追加登録します。
	 * タイトルは元のまま変わりません。
	 * 現状の ErrorMessage の続きに、追加していきます。
	 * 引数の ErrorMessageオブジェクト が null の場合は,何もしません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 連結を、StringBuilder#appendのように、自分自身に出来るように、修正します。
	 *
	 * @param   msg ErrorMessageオブジェクト
	 * @return	自分自身
	 */
	public ErrorMessage append( final ErrorMessage msg ) {
		if( msg != null ) {
			if( maxKekka < msg.getKekka() ) {  maxKekka = msg.getKekka(); }

			final ErrMsg[] emsg = msg.toArray();
			for( int i=0; i<emsg.length; i++ ) {
				list.add( emsg[i] );
			}
		}
		return this;
	}

	/**
	 * 指定された ErrorMessageオブジェクトを行番号指定で追加登録します。
	 * タイトルは元のまま変わりません。
	 * 現状の ErrorMessage の続きに、追加していきます。
	 * 引数の ErrorMessageオブジェクト が null の場合は,何もしません。
	 *
	 * @og.rev 6.5.0.1 (2016/10/21) 連結を、StringBuilder#appendのように、自分自身に出来るように、修正します。
	 *
	 * @param	no	行番号
	 * @param   msg ErrorMessageオブジェクト
	 * @return	自分自身
	 */
	public ErrorMessage append( final int no,final ErrorMessage msg ) {
		if( msg != null ) {
			if( maxKekka < msg.getKekka() ) {  maxKekka = msg.getKekka(); }

			final ErrMsg[] emsg = msg.toArray();
			for( int i=0; i<emsg.length; i++ ) {
				list.add( emsg[i].copy( no ) );
			}
		}
		return this;
	}

	/**
	 *  このリスト内の要素を適切な順序で繰り返し処理する反復子を返します。
	 *
	 * @og.rev 4.0.0.0 (2004/12/31) 新規追加
	 * @og.rev 4.3.2.0 (2008/09/11) private ⇒ public に変更。
	 *
	 * @return  すべての要素を正しい順序で保持するErrMsg配列
	 * @og.rtnNotNull
	 */
	public ErrMsg[] toArray() {
		return list.toArray( new ErrMsg[list.size()] ) ;
	}

	/**
	 * リスト内のキーと値のマッピングの数を返します。
	 *
	 * @return   リスト内の size
	 */
	public int size() {
		return list.size() ;
	}

	/**
	 *  タイトルを返します。
	 *
	 * @return   タイトル
	 */
	public String getTitle() {
		return title;
	}

	/**
	 *  タイトルをセットします。
	 *
	 * @param	title	タイトル
	 */
	public void setTitle( final String title ) {
		this.title = title;
	}

	/**
	 *  このエラーメッセージの中で、最大の結果値(エラーの最大レベル)を返します。
	 *
	 * @return   結果   OK, WARNING, NG, ORCL_ERR
	 */
	public int getKekka() {
		return maxKekka;
	}

	/**
	 *  すべてのメッセージが 正常(OK)かを返します。
	 *
	 * @return   結果 すべてOK：true / それ以外 false
	 */
	public boolean isOK() {
		return maxKekka == OK ;
	}

	/**
	 *  配列中にPG名またはステップ名が設定されているかを返します。
	 *
	 * @og.rev 3.8.9.5 (2007/09/12) 新規作成
	 *
	 * @return   PG名またはステップ名が設定されているか
	 */
	public boolean isSetPgStep() {
		return setPgStep;
	}

	/**
	 *  メッセージの連結リストを返します。
	 *
	 * @return   メッセージの連結リスト
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
			.append( getTitle() ).append( CR );
		// 6.1.1.0 (2015/01/17) refactoring
		for( final ErrMsg msg : list ) {
			rtn.append( msg ).append( CR );
		}

		return rtn.toString();
	}
}
