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

import org.opengion.fukurou.util.ErrMsg;
import org.opengion.fukurou.util.ErrorMessage;
import org.opengion.fukurou.util.StringUtil;				// 6.9.2.1 (2018/03/12)
import org.opengion.hayabusa.html.ViewForm;
import org.opengion.hayabusa.html.ViewFormFactory;
import org.opengion.hayabusa.resource.ResourceManager;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.DBTableModelUtil;
import org.opengion.hayabusa.db.DBColumn;

import java.util.Arrays;
import java.util.Comparator;

/**
 *  Taglib で共通的に使用される ユーティリティクラスです。
 *
 * 全てのメソッドは、 パッケージプライベートなstatic 宣言されています。
 *
 * @og.rev 3.1.1.0 (2003/03/28) 新規作成
 * @og.group その他部品
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
final class TaglibUtil  {
	/* default */ /** VIEW */ static final String VIEW_ID = "HYBS_VIEW" ;		// 3.5.6.4 (2004/07/16)
	/* default */ /** LINK */ static final String LINK_ID = "HYBS_LINK" ;		// 3.5.6.4 (2004/07/16)
	/* default */ /** MARK */ static final String MARK_ID = "HYBS_MARK" ;		// 3.5.6.4 (2004/07/16)

	private static int tagId	;

	// 4.3.2.0 (2008/09/11) 行番号順ソートのための、Comparator オブジェクト
	private static final Comparator<? super ErrMsg> ERR_COMP =		// 6.4.1.1 (2016/01/16) errComp  → ERR_COMP  refactoring
		new Comparator<ErrMsg>() {
			/**
			 * 順序付けのために2つの引数を比較します。
			 *
			 * Comparator インタフェースの実装です。
			 *
			 * @param	s1	比較対象の最初のErrMsg
			 * @param	s2	比較対象の2番目のErrMsg
			 * @return	最初の引数が2番目の引数より小さい場合は負の整数、両方が等しい場合は0、最初の引数が2番目の引数より大きい場合は正の整数。
			 */
			@Override
			public int compare( final ErrMsg err1,final ErrMsg err2 ) {
				return err1.getNo() - err2.getNo() ;
			}
		} ;

	/**
	 *	デフォルトコンストラクターをprivateにして、
	 *	オブジェクトの生成をさせないようにする。
	 *
	 */
	private TaglibUtil() {}

	/**
	 * チェックボックスのラベルを関連つけるための id 値を返します。
	 *
	 * InputTag と OrderByTag 全体で、呼び出される都度に連番をつけて返します。
	 * ユニークな番号になる様にする事が目的なので、99999 で、0 にクリアします。
	 * 別スレッドによる同時アクセスで整合性が破綻(同じ番号が返る)しても、
	 * 問題ありません。(単独のスレッド内でユニークになればよい。)
	 *
	 * @return  ユニークな id 値
	 */
	/* default */ static String getTagId() {
		final String id = "ID" + ( tagId++ );

		if( tagId >= 100000 ) { tagId = 0; }
		return id ;
	}

	/**
	 * ErrorMessage オブジェクトと、ResourceManager より、表示用 HTMLテーブルを作成します。
	 * これは、従来、各Taglibパッケージで使用していました、ErrorMessage オブジェクトを、
	 * HTMLテーブル形式で表示する為に、DBUtilクラスや、ViewFormクラスなど、複数のクラスを
	 * 複雑に組み合わせて使用していましたが、一つの static メソッドにまとめたものです。
	 *
	 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
	 *
	 * @param   errMsg  ErrorMessageオブジェクト
	 * @param   resource リソースマネージャー
	 *
	 * @return  HTMLのテーブルタグに変換後の文字列(無ければ、ゼロストリング)
	 * @og.rtnNotNull
	 */
	/* default */ static String makeHTMLErrorTable( final ErrorMessage errMsg,final ResourceManager resource ) {
		return makeHTMLErrorTable( errMsg,resource , false );				// 通常ラベル使用
	}

	/**
	 * ErrorMessage オブジェクトと、ResourceManager より、表示用 HTMLテーブルを作成します。
	 * これは、従来、各Taglibパッケージで使用していました、ErrorMessage オブジェクトを、
	 * HTMLテーブル形式で表示する為に、DBUtilクラスや、ViewFormクラスなど、複数のクラスを
	 * 複雑に組み合わせて使用していましたが、一つの static メソッドにまとめたものです。
	 *
	 * @og.rev 3.5.5.2 (2004/04/02) 新規追加
	 * @og.rev 3.5.6.1 (2004/06/25) lang 言語コード 属性を削除します。
	 * @og.rev 3.5.6.2 (2004/07/05) setBgColorCycle の引数定義を変更
	 * @og.rev 3.8.0.4 (2005/08/08) setUseScrollBar の追加(ヘッダー固定のスクロールバーを出さない)
	 * @og.rev 3.8.9.5 (2007/09/12) PG名、ステップ名追加(開発ガイドライン対応)
	 * @og.rev 4.0.0.0 (2005/01/31) ResourceManager getMessage 関数を使用
	 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
	 * @og.rev 4.3.2.0 (2008/09/11) 行番号順ソート、メッセージのラベル(短)化、コメント出力
	 * @og.rev 4.3.4.5 (2009/01/08) 対応方法(概要説明)が存在すれば表示する
	 * @og.rev 4.3.7.6 (2009/07/15) 対応方法のパラメータ対応
	 * @og.rev 6.0.2.5 (2014/10/31) エラーメッセージに、preタグを付けます。
	 * @og.rev 6.2.2.0 (2015/03/27) interface に変更タイプ と、書込み許可を追加
	 * @og.rev 6.4.5.2 (2016/05/06) Exception: の後ろに改行を入れます(クラス名が長いと、メッセージが見えにくいため)。
	 * @og.rev 6.8.1.1 (2017/07/22) makeNthChild 処理時に、自身のﾃｰﾌﾞﾙと区別するために、viewClass を追加します。
	 * @og.rev 6.9.2.1 (2018/03/12) エラーメッセージのタグ情報を、パースします。
	 * @og.rev 6.9.3.1 (2018/04/02) エラーメッセージのタグ情報のパースは、JasperException 以降から、改行２つまでの間のみとする。
	 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
	 * @og.rev 7.0.7.2 (2020/01/09) メッセージを比較して、同じなら出力しない。
	 * @og.rev 7.2.9.0 (2020/10/12) getRawShortLabel → getShortErrorMsg メソッド名変更
	 *
	 * @param   errMsg  ErrorMessageオブジェクト
	 * @param   resource リソースマネージャー
	 * @param   useSLabel SLABEL利用 [true:利用する/false:利用しない]
	 *
	 * @return  HTMLのテーブルタグに変換後の文字列(無ければ、ゼロストリング)
	 * @og.rtnNotNull
	 */
//	/* default */ static String makeHTMLErrorTable( final ErrorMessage errMsg,final ResourceManager resource ) {
	/* default */ static String makeHTMLErrorTable( final ErrorMessage errMsg,final ResourceManager resource, final boolean useSLabel ) {
		if( errMsg == null ) { return ""; }

		final String[] names ;
		if( errMsg.isSetPgStep() ) {
			// names = new String[] { "ROW_NO","KEKKA","MSGID","MESSAGE","PG","STEP" }; // 3.8.9.5 (2007/09/12)
			names = new String[] { "ROW_NO","KEKKA","MSGID","MESSAGE", "PG","STEP" }; // 3.8.9.5 (2007/09/12)
		}
		else {
			names = new String[] { "ROW_NO","KEKKA","MSGID","MESSAGE" };
		}

		final int clmSize = names.length;

		final DBTableModel errTable = DBTableModelUtil.newDBTable();
		errTable.init( clmSize );

		for( int i=0; i<clmSize; i++ ) {
			final DBColumn dbColumn = resource.makeDBColumn( names[i] );
			errTable.setDBColumn( i,dbColumn );
		}

		// 4.3.2.0 (2008/09/11) 行番号順ソート
		final ErrMsg[] errMsgs = errMsg.toArray();
		Arrays.sort( errMsgs, ERR_COMP );

		for( int i=0; i<errMsg.size(); i++ ) {
			final ErrMsg err = errMsgs[i];
			String[] clmVals = new String[clmSize];
			clmVals[0] = String.valueOf( err.getNo() );
			clmVals[1] = String.valueOf( err.getKekka() );
			clmVals[2] = err.getId();

			// 6.9.3.1 (2018/04/02) エラーメッセージのタグ情報のパースは、JasperException 以降から、改行２つまでの間のみとする。
//			String tmpVals3 = resource.getLabel( err );
//			String tmpVals3 = useSLabel ? resource.getRawShortLabel( err ) : resource.getLabel( err );		// 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
			String tmpVals3 = useSLabel ? resource.getShortErrorMsg( err ) : resource.getLabel( err );		// 7.2.9.0 (2020/10/12) メソッド名変更

			if( tmpVals3 != null ) {
				tmpVals3 = tmpVals3.trim();
	//			// 7.0.7.2 (2020/01/09) Exception: で改行処理を中断する。
	//			if( tmpVals3.contains( "Exception:" ) ) {
	//				tmpVals3 = tmpVals3.replaceAll( "Exception: " , "Exception:\n" );
	//			}
				final int idx0 = tmpVals3.indexOf( "JasperException" );		// JSP画面のｴﾗｰ
				if( idx0 >= 0 ) {
					final int idx1 = tmpVals3.indexOf( "\n\n",idx0 );		// 改行２つ
					if( idx1 >= 0 ) {
						tmpVals3 = tmpVals3.substring( 0,idx0 ) +
									StringUtil.htmlFilter( tmpVals3.substring( idx0,idx1 ) ) +
									tmpVals3.substring( idx1 );
					}
					else {
						tmpVals3 = tmpVals3.substring( 0,idx0 ) +
									StringUtil.htmlFilter( tmpVals3.substring( idx0 ) );
					}
				}
				clmVals[3] = "<pre>" + tmpVals3 + "</pre>";
			}

//			// 6.0.2.5 (2014/10/31) エラーメッセージに、preタグを付けます。
//			clmVals[3] = "<pre>" + resource.getLabel( err ) + "</pre>";
//	//		clmVals[3] = "<pre>" + StringUtil.htmlFilter( resource.getLabel( err ) ) + "</pre>";		// 6.9.2.1 (2018/03/12)
//
//			// 6.4.5.2 (2016/05/06) Exception: の後ろに改行を入れます(クラス名が長いと、メッセージが見えにくいため)。
//			if( clmVals[3].contains( "Exception:" ) ) {
//				clmVals[3] = clmVals[3].replaceAll( "Exception: " , "Exception:\n" );
//			}

			if( errMsg.isSetPgStep() ) {
				clmVals[4] = err.getPg();
				clmVals[5] = err.getStep();
			}
			errTable.addColumnValues( clmVals , null , false );		// 6.2.2.0 (2015/03/27)

			// 7.0.7.0 (2019/12/13) useSLabel 属性を追加。対応方法(概要説明)は、useSLabel=true時には、出しません。
			if( !useSLabel ) {
				// 対応方法(概要説明)が存在すれば直下に一行追加する 4.3.4.5 (2009/01/08)
				// String desc = resource.getDescription( clmVals[2] );
				final String desc = resource.getDescription( err );		// 4.3.7.6 (2009/07/15)
//				if( desc != null && desc.length() > 0 ){
				// 7.0.7.2 (2020/01/09) メッセージを比較して、同じなら出力しない。
//				if( desc != null && desc.length() > 0 ){
				if( desc != null && desc.length() > 0 && !desc.trim().equals( tmpVals3 ) ){
					String[] descVals = new String[clmSize];
//					descVals[3] = desc;
//					descVals[3] = "<pre>" + desc + "</pre>";				// 7.0.7.0 (2019/12/13) pre を付けます。
					descVals[3] = "<pre>" + desc.trim() + "</pre>";			// 7.0.7.2 (2020/01/09) trim()追加
					errTable.addColumnValues( descVals , null , false );	// 6.2.2.0 (2015/03/27)
				}
			}
		}

		// ここまでが、DBTableModel の作成。以下は、View での表示

		final ViewForm form = ViewFormFactory.newInstance( "HTMLTable" );

		form.init( errTable );
		if( ! errMsg.isOK() )  { 								// 正常以外
			form.setViewClass( "errorView" );					// 6.4.6.1 (2016/06/03)
			form.setBgColorCycle( -1 * errMsg.getKekka() );		// エラー処理時のゼブラ模様
			form.setNumberType( "delete" );						// 番号欄を出さない。
			form.setUseTableSorter( false );					// ソート用リンクは出さない。
			form.setUseScrollBar( false );						// 4.0.0 (2005/01/31) スクロールバー用のDIV要素を出力しない。
		}

		return form.create();
	}

	/**
	 * ErrorMessage オブジェクトと、ResourceManager より、表示用 HTMLテーブルを作成します。
	 * このメソッドでは、エラーメッセージ及びエラーコードを一覧形式で表示します。
	 *
	 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
	 *
	 * @param   errMsg  ErrorMessageオブジェクト
	 * @param   resource リソースマネージャー
	 *
	 * @return  HTMLのテーブルタグに変換後の文字列(無ければ、ゼロストリング)
	 * @og.rtnNotNull
	 */
	/* default */ static String makeHTMLSimpleErrorList( final ErrorMessage errMsg,final ResourceManager resource ) {
		return makeHTMLSimpleErrorList( errMsg,resource,false );				// 通常ラベル使用
	}

	/**
	 * ErrorMessage オブジェクトと、ResourceManager より、表示用 HTMLテーブルを作成します。
	 * このメソッドでは、エラーメッセージ及びエラーコードを一覧形式で表示します。
	 *
	 * @og.rev 6.2.2.0 (2015/03/27) interface に変更タイプ と、書込み許可を追加
	 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
	 * @og.rev 7.1.0.1 (2020/02/07) ShortLabelの引数対応で、RawShortLabel を使います。
	 * @og.rev 7.2.9.0 (2020/10/12) getRawShortLabel → getShortErrorMsg メソッド名変更
	 *
	 * @param   errMsg  ErrorMessageオブジェクト
	 * @param   resource リソースマネージャー
	 * @param   useSLabel SLABEL利用 [true:利用する/false:利用しない]
	 *
	 * @return  HTMLのテーブルタグに変換後の文字列(無ければ、ゼロストリング)
	 * @og.rtnNotNull
	 */
//	/* default */ static String makeHTMLSimpleErrorList( final ErrorMessage errMsg,final ResourceManager resource ) {
	/* default */ static String makeHTMLSimpleErrorList( final ErrorMessage errMsg,final ResourceManager resource, final boolean useSLabel ) {
		if( errMsg == null ) { return ""; }

		final String[] names = new String[] { "MESSAGE" };

		final int clmSize = names.length;

		final DBTableModel errTable = DBTableModelUtil.newDBTable();
		errTable.init( clmSize );

		for( int i=0; i<clmSize; i++ ) {
			final DBColumn dbColumn = resource.makeDBColumn( names[i] );
			errTable.setDBColumn( i,dbColumn );
		}

		final ErrMsg[] errMsgs = errMsg.toArray();
		Arrays.sort( errMsgs, ERR_COMP );

		for( int i=0; i<errMsg.size(); i++ ) {
			final ErrMsg err = errMsgs[i];
			String[] clmVals = new String[clmSize];
			// 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
//			clmVals[0] = resource.getShortLabel( err.getId() ) + "(" + err.getId() + ")";
//			clmVals[0] = useSLabel ? resource.getRawShortLabel( err ) : resource.getShortLabel( err.getId() ) + "(" + err.getId() + ")";

			// 7.1.0.1 (2020/02/07) ShortLabelの引数対応で、RawShortLabel を使います。
//			clmVals[0] = resource.getRawShortLabel( err );
			clmVals[0] = resource.getShortErrorMsg( err );			// 7.2.9.0 (2020/10/12) メソッド名変更
			if( !useSLabel ) { clmVals[0] = clmVals[0] + "(" + err.getId() + ")"; }

			errTable.addColumnValues( clmVals , null , false );		// 6.2.2.0 (2015/03/27)
		}

		// ここまでが、DBTableModel の作成。以下は、View での表示
		final ViewForm form = ViewFormFactory.newInstance( "HTMLSimpleList" );
		form.init( errTable );

		if( ! errMsg.isOK() )  { 	// 正常以外
			form.setBgColorCycle( -1 * errMsg.getKekka() );	// エラー処理時のゼブラ模様
		}

		return form.create();
	}
}
