/*
 * 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.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.resource.GUIInfo;
import org.opengion.fukurou.util.XHTMLTag;
import org.opengion.fukurou.util.TagBuffer;
import org.opengion.fukurou.util.StringUtil ;

import static org.opengion.fukurou.util.StringUtil.nval ;
import org.opengion.fukurou.util.EnumType ;

import java.util.Locale ;

/**
 * 戻るボタン/戻るリンクを表示するHTML拡張タグです(通常はcustom/query_info.jspに組込み)。
 *
 * custom/query_info.jsp に組み込むことで、全てのquery.jspに組込む事ができます。
 * 戻るボタン/リンクを表示するかどうかの条件判定は、
 * 　条件1：自分自身へ戻る機能はサポートできません。
 * 　条件2：BACK_GAMENID が存在するか、または、gamenId で指示された場合のみ表示。
 * 　条件3：command="NEW" で、キャッシュに設定しておく必要がある。
 *
 * @og.formSample
 * ●形式：&lt;og:backGamen keys="･･･" vals="･･･" &gt; ･･Body･･ &lt;/og:backGamen&gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:backGamen
 *       type               【TAG】ボタンのタイプ[link/button/relLink/relButton/historyBack]を指定します(初期値:link)
 *       command            【TAG】(通常は使いません)戻る時に指定する command を設定できます(初期値:RENEW)
 *       gamenId            【TAG】(通常は使いません)戻り先の画面をセットします(初期値:BACK_GAMENID)
 *       keys               【TAG】リンク先に渡すキーをCSV形式で複数指定します
 *       vals               【TAG】keys属性に対応する値をCSV形式で複数指定します
 *       lbl                【TAG】ラベルリソースのラベルIDを指定します
 *       href               【HTML】リンク先のURLを指定します
 *       target             【HTML】リンク先の表示ターゲットを指定します(初期値:CONTENTS)
 *       id                 【HTML】要素に対して固有の名前(id)をつける場合に設定します
 *       lang               【HTML】要素の内容と他の属性値の言語(lang,xml:lang)を指定します
 *       dir                【HTML】文字表記の方向(dir)を指定します
 *       title              【HTML】要素に対する補足的情報(title)を設定します
 *       style              【HTML】この要素に対して適用させるスタイルシート(style)を設定します
 *       tabindex           【HTML】タブの移動順(tabindex)を指定します(0 ～ 32767)
 *       accesskey          【HTML】アクセスキー(alt+キーで直接指定)を割り当てます(初期値:R)
 *       clazz              【HTML】要素に対して class 属性を設定します
 *       language           【TAG】タグ内部で使用する言語コード[ja/en/zh/…]を指定します
 *       onClick            【HTML】JavaScriptのイベント onClick を設定します(例:onClick="renew('query.jsp','QUERY');")
 *       onBlur             【HTML】JavaScriptのイベント onBlur を設定します(例:onBlur="this.value=value.toUpperCase();")
 *       onFocus            【HTML】JavaScriptのイベント onFocus を設定します
 *       ondblClick         【HTML】JavaScriptのイベント ondblClick を設定します
 *       onMouseDown        【HTML】JavaScriptのイベント onMouseDown を設定します
 *       onMouseUp          【HTML】JavaScriptのイベント onMouseUp を設定します
 *       onMouseMove        【HTML】JavaScriptのイベント onMouseMove を設定します
 *       onMouseOut         【HTML】JavaScriptのイベント onMouseOut を設定します
 *       onMouseOver        【HTML】JavaScriptのイベント onMouseOver を設定します
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:backGamen&gt;
 *
 * ●使用例
 *   &lt;og:backGamen keys=&quot;displayMsg,clear&quot; vals=&quot;MSG0065,true&quot; &gt;
 *       &lt;img src=&quot;{&#064;SYS.JSP}/image/back.gif&quot; alt=&quot;{&#064;BACK_GAMENID}&quot; /&gt;
 *       &lt;og:message lbl=&quot;MSG0049&quot; /&gt;
 *   &lt;/og:backGamen&gt;
 *
 * 7.3.1.0 (2021/02/02)
 *  リンクタグで、useBackLink 属性を使用することで、戻るﾘﾝｸをある程度制御できます。
 *  何も指定しない場合(null)は、従来通りです。
 * true：相手先に(条件が成立すれば)戻るﾘﾝｸを表示。条件が成立しない場合は、自身へのリンクが表示。
 * false:必ず表示しない
 * 未指定(null):従来通り…自分自身では戻るリンクを表示せず、別画面の場合のみ表示します。
 *
 * @og.rev 3.1.8.0 (2003/05/16) 新規作成
 * @og.group 画面制御
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class BackGamenTag extends HTMLTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "7.3.1.0 (2021/02/02)" ;
	private static final long serialVersionUID = 731020210202L ;

	// 4.0.0 (2005/05/31) JDK5.0 enum 対応
	/**
	 * type 属性として指定できる選択肢を定義します。
	 */
	private static final EnumType<String> CHECK_TYPE =
				new EnumType<>( "ボタンのタイプ","link" )
					.append( "link"			,"戻るリンクを作成します。"					)
					.append( "relLink"		,"戻るリンク(相対パス)を作成します。"		)
					.append( "button"		,"戻るボタンを作成します。"					)
					.append( "relButton"	,"戻るボタン(相対パス)を作成します。"		)
					.append( "historyBack"	,"通常のヒストリバックボタンを作成します。"	) ;

	// 6.9.4.1 (2018/04/09) FILEFILTER使用時(紙芝居作成時)に、true になります。
	private static final boolean USE_FILEFILTER = "true".equalsIgnoreCase( HybsSystem.sys( "USE_FILEFILTER" ) );	// null時は、false

	private String		type		= CHECK_TYPE.getDefault() ;
	private String		command		= "RENEW" ;
	private String		gamenId		;
	private String		target		= "CONTENTS";
	private String		accesskey	= "R";
	private String[]	keys		;
	private String[]	vals		;
	private String		body		;
	private String		backAddress	;			// 4.0.1.0 (2007/12/18)

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
	 */
	public BackGamenTag() { super(); }		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @return	後続処理の指示( EVAL_BODY_BUFFERED )
	 */
	@Override
	public int doStartTag() {
		return EVAL_BODY_BUFFERED ;	// Body を評価する。( extends BodyTagSupport 時)
	}

	/**
	 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		body = getBodyString();

		return SKIP_BODY ;
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 *
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		type		= CHECK_TYPE.getDefault() ;
		command		= "RENEW" ;
		gamenId		= null;
		target		= "CONTENTS";
		accesskey	= "R";
		keys		= null;
		vals		= null;
		body		= null;
		backAddress	= null;
	}

	/**
	 * 戻るボタン/戻るリンクを作成します。
	 *
	 * @og.rev 3.1.8.0 (2003/05/16) BACK_GAMENID のキャッシュの取り出し先を変更する。
	 * @og.rev 3.5.4.0 (2003/11/25) 履歴(history)オブジェクトのback() メソッドを利用した戻る機能を追加します。
	 * @og.rev 4.0.1.0 (2007/12/17) BackAddress対応
	 * @og.rev 5.0.2.0 (2009/11/01) 相対パスでの戻るリンク対応
	 *
	 * @return  戻るボタン/戻るリンク
	 */
	@Override
	protected String makeTag() {
		String rtn = "" ;

		if( gamenId == null ) {
			gamenId = getBackGamenId() ;
		}
		if( backAddress == null) { // 4.0.1.0 (2007/12/17)
			backAddress = getBackAddress();
		}

		// 4.0.0 (2005/05/31)
		if( "historyBack".equalsIgnoreCase( type ) ) {
			final String hb = getRequest().getParameter( "historyBack" );
			if( "1".equals( hb ) ) {
				rtn = makeHistoryBackTag();
			}
		}
		else {
			if( checkCondition( gamenId ) ) {
				set( "target" ,nval( get( "target" ), target ) );

				// 5.0.2.0 (2009/11/01) 相対パスでの戻る対応
				if( "link".equalsIgnoreCase( type ) || "relLink".equalsIgnoreCase( type ) ) {
					rtn = makeLinkTag();
				}
				else if( "button".equalsIgnoreCase( type ) || "relButton".equalsIgnoreCase( type ) ) {
					rtn = makeButtonTag();	// 3.8.1.2 (2005/12/19)
				}
				else {
					final String errMsg = "指定の type は、下記の範囲で指定してください。"
									+ "type=" + type + " : "
									+ CHECK_TYPE.toString();
					throw new HybsSystemException( errMsg );
				}
			}
		}

		return rtn ;
	}

	/**
	 * 戻るリンクを作成します。
	 *
	 * @og.rev 3.5.5.0 (2004/03/12) 戻るアドレスを、GUIInfoより取得するように変更。
	 * @og.rev 4.0.0.0 (2005/01/31) GUIInfoの実アドレスのパラメータを考慮する。
	 * @og.rev 3.7.0.3 (2005/03/01) 戻る行番号を、BACK_ROW_KEYより取得し、SEL_ROW で渡す。
	 * @og.rev 4.0.1.0 (2007/12/17) 戻るアドレスをbackAddressを使うように変更
	 * @og.rev 4.0.2.1 (2007/12/27) リクエスト部からGAMENIDを外していたが、二段階戻る場合に不具合が出たため元に戻す
	 * @og.rev 5.0.2.0 (2009/11/01) 相対パスでの戻るリンク対応
	 * @og.rev 6.9.4.1 (2018/04/09) FILEFILTER使用時(紙芝居作成時)は、相対ﾘﾝｸを出力するようにします。
	 *
	 * @return  戻るリンク
	 * @og.rtnNotNull
	 */
	private String makeLinkTag() {
		set( "body",getMsglbl( gamenId ) );
		String href = get( "href" );
		if( href == null) {
			// 3.5.5.0 (2004/03/12)
			// 5.0.2.0 (2009/11/01) 相対パスでの戻る対応
//			if( backAddress == null || "relLink".equalsIgnoreCase( type ) ) {					// 4.0.1.0 (2007/12/17) if文追加
			if( backAddress == null || "relLink".equalsIgnoreCase( type ) || USE_FILEFILTER ) {	// 6.9.4.1 (2018/04/09) FILEFILTER使用時は、相対ﾘﾝｸを出力
				final GUIInfo guiInfo = getGUIInfo( gamenId );									// 4.0.0 (2005/01/31)
				if( guiInfo == null ) { return ""; } // 見つからない場合は、アクセス不可
				final String address = guiInfo.getRealAddress( "index.jsp" );
				href = getRequestParameter( address );
			}
			else { // 4.0.1.0 (2007/12/17)
				href = backAddress;
			}
		}

		// 3.7.0.3 (2005/03/01) 戻る行番号を、BACK_ROW_KEYより取得し、SEL_ROW で渡す。
		final String rowkey = HybsSystem.BACK_ROW_KEY + getGUIInfoAttri( "KEY" );
		final String rowVal = (String)getSessionAttribute( rowkey );

		final String[] keys2 = new String[] { "command","GAMENID","SEL_ROW" };
		final String[] vals2 = new String[] {  command , gamenId , rowVal   };
		final String urlEnc2 = XHTMLTag.urlEncode( keys2,vals2 );
		href = XHTMLTag.addUrlEncode( href,urlEnc2 );

		final String urlEnc = XHTMLTag.urlEncode( keys,vals );
		href = XHTMLTag.addUrlEncode( href,urlEnc );

		set( "href",href );

		return XHTMLTag.link( getAttributes() ) ;
	}

	/**
	 * 戻るボタンのフォームを作成します。
	 *
	 * @og.rev 3.5.5.0 (2004/03/12) 戻るアドレスを、GUIInfoより取得するように変更。
	 * @og.rev 3.5.5.5 (2004/04/23) hidden の出力に、XHTMLTag.hidden を使用します。
	 * @og.rev 3.8.1.2 (2005/12/19) メソッド名変更、inputタグ⇒buttonタグ変更
	 * @og.rev 4.0.1.0 (2007/12/17) BACK_ADDRESS対応
	 * @og.rev 5.0.2.0 (2009/11/01) 相対パスでの戻るリンク対応
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 * @og.rev 6.9.4.1 (2018/04/09) FILEFILTER使用時(紙芝居作成時)は、相対ﾘﾝｸを出力するようにします。
	 *
	 * @return  戻るボタンのフォーム
	 * @og.rtnNotNull
	 */
	private String makeButtonTag() {

		final String href = get( "href" );
		if( href == null ) {
			// 3.5.5.0 (2004/03/12)
			// 5.0.2.0 (2009/11/01) 相対パスでの戻る対応
//			if( backAddress == null || "relButton".equalsIgnoreCase( type ) ) { // 4.0.1.0 (2007/12/18) if文化
			if( backAddress == null || "relButton".equalsIgnoreCase( type ) || USE_FILEFILTER ) {	// 6.9.4.1 (2018/04/09) FILEFILTER使用時は、相対ﾘﾝｸを出力
				final GUIInfo guiInfo = getGUIInfo( gamenId );
				final String address = guiInfo.getRealAddress();
				set( "action", address + "index.jsp" );
			}
			else {
				set( "action", backAddress ); // 4.0.1.0 (2007/12/18)
			}
		}
		else {
			set( "action",href ) ;
		}

		// 6.1.1.0 (2015/01/17) TagBufferの連結記述
		final String tag = new TagBuffer( "button" )
							.add( "type"		,"submit" )
							.add( "accesskey"	,get( "accesskey" ) )
							.addBody( getMsglbl( gamenId ) )
							.makeTag();

		final StringBuilder body = new StringBuilder( BUFFER_MIDDLE )
			.append( tag )										// 6.1.1.0 (2015/01/17)
			.append( CR )
			// command を hidden で作成します。
			.append( XHTMLTag.hidden( "command",command ) )		// hidden(name,value);
			.append( CR )
			// GAMENID を hidden で作成します。
			.append( XHTMLTag.hidden( "GAMENID",gamenId ) )		// hidden(name,value);
			.append( CR );

		// keys,vals を hidden で作成します。
		// 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
		if( keys != null && vals != null ) {
			if( keys.length != vals.length ) {
				final String errMsg = "キーとバリューの個数が異なります。"
							+ CR
							+ " keys.length=[" + keys.length + "]  vals.length=[" + vals.length + "]"
							+ " keys=" + StringUtil.array2csv( keys ) + CR
							+ " vals=" + StringUtil.array2csv( vals )  ;	// 5.1.8.0 (2010/07/01) errMsg 修正
				throw new HybsSystemException( errMsg );
			}

			for( int i=0; i<keys.length; i++ ) {
				body.append( XHTMLTag.hidden( keys[i],vals[i] ) )	// hidden(name,value);
					.append( CR );
			}
		}

		// 3.7.0.3 (2005/03/01) 戻る行番号を、BACK_ROW_KEYより取得し、SEL_ROW で渡す。
		final String rowkey = HybsSystem.BACK_ROW_KEY + getGUIInfo( "GUI.KEY" );
		final String rowVal = (String)getSessionAttribute( rowkey );
		// 3.7.0.5 (2005/04/11) null の時は、返さないように変更
		if( rowVal != null ) {
			body.append( XHTMLTag.hidden( "SEL_ROW",rowVal ) )	// hidden(name,value);
				.append( CR );
		}

		set( "body",body.toString() );

		return XHTMLTag.form( getAttributes() ) ;
	}

	/**
	 * 戻るリンク(historyBack)を作成します。
	 *
	 * @og.rev 3.5.4.0 (2003/11/25) 履歴(history)オブジェクトのback() メソッドを利用した戻る機能を追加します。
	 *
	 * @return  戻るリンク
	 * @og.rtnNotNull
	 */
	private String makeHistoryBackTag() {
		final StringBuilder link = new StringBuilder( BUFFER_MIDDLE )
			.append( "<a onClick=\"history.back()\">" )
			.append( getMsglbl( gamenId ) )
			.append( "</a>" );

		return link.toString() ;
	}

	/**
	 * BACK_GAMENID の値を取り出します。
	 *
	 * 値は、キャッシュではなく、session より HybsSystem.BACK_GAMENID_KEY をキーに
	 * 取り出します。
	 *
	 * @og.rev 3.1.8.0 (2003/05/16) BACK_GAMENID のキャッシュの取り出し先を変更する。
	 *
	 * @return  BACK_GAMENID の値
	 */
	private String getBackGamenId() {
		final String key = HybsSystem.BACK_GAMENID_KEY + getGUIInfoAttri( "KEY" );	// 4.0.0 (2005/01/31)
		return (String)getSessionAttribute( key );
	}

	/**
	 * BACK_ADDRESS の値を取り出します。
	 *
	 * 値は、キャッシュではなく、session より HybsSystem.BACK_ADDRESS_KEY をキーに
	 * 取り出します。
	 *
	 * @og.rev 4.0.1.0 (2007/12/17) メソッド追加
	 *
	 * @return  BACK_GAMENID の値
	 */
	private String getBackAddress() {
		final String key = HybsSystem.BACK_ADDRESS_KEY + getGUIInfoAttri( "KEY" );	// 4.0.0 (2005/01/31)

		return (String)getSessionAttribute( key );
	}

	/**
	 * 【TAG】ボタンのタイプ[link/button/relLink/relButton/historyBack]を指定します(初期値:link)。
	 *
	 * @og.tag
	 * button と設定すると、戻るボタンに、link と設定すると、戻るリンクになります。
	 * historyBack は、IE等の戻る操作と同じで、JavaScriptのヒストリーバックを行います。
	 * また、relButton、relLinkとすると、それぞれ相対パス(画面IDから飛び先のアドレスを元に生成)
	 * で戻り先のアドレスが生成されます。
	 * 初期値は、戻るリンク(link)です。
	 * ※ 6.9.4.1 (2018/04/09) FILEFILTER使用時(紙芝居作成時)は、相対ﾘﾝｸを出力します。
	 *
	 * <table class="plain">
	 *   <caption>ボタンのタイプ説明</caption>
	 *   <tr><th>タイプ		</th><th>説明						</th></tr>
	 *   <tr><td>link		</td><td>戻るリンク					</td></tr>
	 *   <tr><td>button		</td><td>戻るボタン					</td></tr>
	 *   <tr><td>relLink	</td><td>戻るリンク(相対パス)		</td></tr>
	 *   <tr><td>relButton	</td><td>戻るボタン(相対パス)		</td></tr>
	 *   <tr><td>historyBack</td><td>通常のヒストリバックボタン	</td></tr>
	 * </table>
	 *
	 * @og.rev 5.0.2.0 (2009/11/01) 相対パスでの戻るリンク対応
	 *
	 * @param   tp ボタンのタイプ [link/button/relLink/relButton/historyBack]
	 */
	public void setType( final String tp ) {
		type = CHECK_TYPE.nval( tp );
	}

	/**
	 * 【TAG】(通常は使いません)戻る時に指定する command を設定できます(初期値:RENEW)。
	 *
	 * @og.tag
	 * 通常は、RENEW で戻ります。
	 * (初期値は、RENEW なので設定不要です。)
	 *
	 * @param	cmd コマンド
	 */
	public void setCommand( final String cmd ) {
		command = nval( getRequestParameter( cmd ),command );
		if( command != null ) { command = command.toUpperCase(Locale.JAPAN); }
	}

	/**
	 * 【TAG】(通常は使いません)戻り先の画面をセットします(初期値:BACK_GAMENID)。
	 *
	 * @og.tag
	 * 通常は、自動的に、BACK_GAMENID の値がセットされますが、
	 * 先祖に戻る(画面Ａ⇒画面Ｂ⇒画面Ｃ のときに、画面Ａに戻る)場合や、
	 * 別の画面に、進む場合に、直接指定します。
	 * (初期値は、来た画面：BACK_GAMENID ですので、設定不要です。)
	 * 値は、キャッシュではなく、session より HybsSystem.BACK_GAMENID_KEY をキーに
	 * 取り出します。
	 * これは、command="NEW" で、BACK_GAMENID リクエストが存在し、BACK_GAMENID と
	 * 自分自身の画面IDが異なる場合のみ、RequestCacheTag#backGamenIdSet メソッドで
	 * session に登録されます。
	 *
	 * @param   id 戻り先の画面ID
	 */
	public void setGamenId( final String id ) {
		gamenId = nval( getRequestParameter( id ),gamenId );
	}

	/**
	 * 【TAG】リンク先に渡すキーをCSV形式で複数指定します。
	 *
	 * @og.tag
	 * 戻る時に、検索時のキャッシュに指定した引数以外に指定したり、別の値に置き換えたり
	 * する場合のキーを設定できます。CSV形式で複数指定できます。
	 * vals 属性には、キーに対応する値を、設定してください。
	 * 例:<b>keys="displayMsg,clear"</b> vals="MSG0065,true"
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @og.rev 3.5.6.2 (2004/07/05) CommonTagSupport#getCSVParameter を使用
	 *
	 * @param	key リンク先に渡すキー (例：keys="displayMsg,clear")
	 * @see		#setVals( String )
	 */
	public void setKeys( final String key ) {
		keys = getCSVParameter( key );
	}

	/**
	 * 【TAG】keys属性に対応する値をCSV形式で複数指定します。
	 *
	 * @og.tag
	 * キーに設定した値を、CSV形式で複数して出来ます。
	 * 指定順序は、キーと同じにしておいて下さい。
	 * 例:keys="displayMsg,clear" <b>vals="MSG0065,true"</b>
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @og.rev 3.5.6.2 (2004/07/05) CommonTagSupport#getCSVParameter を使用
	 *
	 * @param	val keys属性に対応する値 (例：vals="MSG0065,true")
	 * @see		#setKeys( String )
	 */
	public void setVals( final String val ) {
		vals = getCSVParameter( val );
	}

	/**
	 * 【HTML】リンク先の表示ターゲットを指定します(初期値:CONTENTS)。
	 *
	 * @og.tag
	 * リンク先の文書を表示させるフレーム、またはウィンドウの名前を指定します。
	 *
	 * @param	tgt リンク先の表示ターゲット
	 */
	public void setTarget( final String tgt ) {
		set( "target",getRequestParameter( tgt ) );
	}

	/**
	 * 【HTML】リンク先のURLを指定します。
	 *
	 * @og.tag リンク先のURLを指定します。
	 *
	 * @param	href リンク先のURL
	 */
	public void setHref( final String href ) {
		set( "href",getRequestParameter( href ) );
	}

	/**
	 * メッセージラベル(msglbl)をセットします。
	 *
	 * メッセージラベルは、meg属性か、lbl属性で登録された値を、
	 * それぞれのリソースに応じて各言語に変換した結果を格納しています。
	 * meg属性 と lbl属性は、同時登録できません。
	 *
	 * @og.rev 5.7.1.2 (2013/12/20) msg ⇒ msglbl 変更
	 *
	 * @param	 gamenId 画面ID
	 *
	 * @return   メッセージラベル
	 * @og.rtnNotNull
	 */
	private String getMsglbl( final String gamenId ) {
		final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
		final String msglbl = getMsglbl();	// 5.7.1.2 (2013/12/20) msg ⇒ msglbl 変更

		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
		if( msglbl == null ) {
			if( body == null || body.isEmpty() ) {
				final GUIInfo guiInfo = getGUIInfo( gamenId );		// 4.0.0 (2005/01/31)
				if( guiInfo != null ) {
					rtn.append( guiInfo.getLongName() );
				}
			}
			else {
				rtn.append( body );
			}
		}
		else {
			rtn.append( msglbl );
			set( "accesskey",nval( get( "accesskey" ),accesskey ) );
			rtn.append( '(' ).append( get( "accesskey" ) ).append( ')' ) ;		// 6.0.2.5 (2014/10/31) char を append する。
		}

		return rtn.toString() ;
	}

	/**
	 * 画面に戻るボタン/リンクを表示するかどうかを条件判定します。
	 * 引数の gamenId は、BACK_GAMENID の事で、このタグの属性定義で設定されて
	 * いない場合は、session より、BACK_GAMENID を取り出します。つまり、取り出す為には、
	 * command="NEW" で、キャッシュに設定しておく必要があります。
	 *
	 * 随時、条件を追加していきます。
	 *
	 * 条件1：自分自身へ戻る機能はサポートできません。
	 * 条件2：command="NEW" で、キャッシュに設定しておく必要がある。
	 *
	 * @og.rev 3.5.5.0 (2004/03/12) デバッグ情報を出力するように機能追加
	 * @og.rev 7.3.1.0 (2021/02/02) useBackLink 属性の値を使用する。
	 *
	 * @param	 gmnId 画面ID(BACK_GAMENID)
	 *
	 * @return   判定結果
	 */
	private boolean checkCondition( final String gmnId ) {
		// 7.3.1.0 (2021/02/02)
		final String useBkLink = getRequest().getParameter( "useBackLink" );
		if( "false".equalsIgnoreCase( useBkLink ) ) { return false; }			// false の場合は無条件でリンクを出さない。

		final String thisGamen = getGUIInfoAttri( "KEY" );	// 4.0.0 (2005/01/31)
		final boolean rtn = gmnId != null
						&& gmnId.length() > 0
						&& ! gmnId.equals( thisGamen ) ;

		// 7.3.1.0 (2021/02/02)
		if( !rtn && "true".equalsIgnoreCase( useBkLink ) ) {
			gamenId = thisGamen;							// true の場合は、gamenIdがnullだとリンクが出ない。
			return true;
		}

		// 3.5.5.0 (2004/03/12)
		if( isDebug() ) {
			final String cmd =pageContext.getRequest().getParameter( "command" );

			// 6.0.2.5 (2014/10/31) char を append する。
			final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
				.append( getDocumentLink() )		// 4.0.0 (2005/02/28)
				.append( "<pre>" )
				.append( "command  =[" ).append( cmd       ).append( ']' ).append( CR )
				.append( "type     =[" ).append( type      ).append( ']' ).append( CR )
				.append( "gamenId  =[" ).append( gmnId     ).append( ']' ).append( CR )
				.append( "thisGamen=[" ).append( thisGamen ).append( ']' ).append( CR )
				.append( "useBkLink=[" ).append( useBkLink ).append( ']' ).append( CR )			// 7.3.1.0 (2021/02/02)
				.append( "checkCondition=[" ).append( rtn  ).append( ']' )
				.append( "</pre>" );
			jspPrint( buf.toString() );
		}

		return rtn ;
	}
}
