/*
 * 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 java.io.IOException;

import javax.mail.internet.MimeUtility;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.opengion.fukurou.security.HybsCryptography;			// 5.10.11.0 (2019/05/03)
import org.opengion.fukurou.system.LogWriter;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.XHTMLTag;
import org.opengion.fukurou.util.ToString;						// 6.1.1.0 (2015/01/17)
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.resource.GUIInfo;

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

/**
 * 制御を別の画面にフォワードする場合に使用するタグです(通常は、entry.jsp で使用します)。
 *
 * フォワード時に、指定の引数をセットできます。
 *
 * @og.formSample
 * ●形式：&lt;og:forward page="…" gamenId="[…]" /&gt;
 * ●body：なし
 *
 * ●Tag定義：
 *   &lt;og:forward
 *       gamenId            【TAG】gamenId 属性を登録します
 *       page             ○【TAG】転送先URLを指定します(必須)。
 *       keys               【TAG】キーを CSV形式でセットします
 *       vals               【TAG】キーに対応する値を CSV形式でセットします
 *       dbkeys             【TAG】DBキーをCSV形式でセットします
 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
 *       useRedirect        【TAG】response.sendRedirect するかどうか[true/false]を指定します(初期値:false)
 *       target             【TAG】サブミット先の文書を表示させるフレーム、またはウィンドウの名前を指定します
 *       filename           【TAG】ファイル転送時にファイル名の別名を指定します(初期値:null)
 *       disposition        【TAG】ファイル転送時のヘッダー情報として、Content-Dispositionに設定する値を指定します(初期値:CONTENT_DISPOSITION[={@og.value SystemData#CONTENT_DISPOSITION}])。
 *       noTransition       【TAG】(通常は使いません)画面遷移を行わない形式の登録方法を使用するかを指定します
 *       useAjaxSubmit      【TAG】(通常は使いません)ajaxを利用したsubmitを利用するかどうかを指定します
 *       redirectEncode     【TAG】(通常は使いません)useRedirect=true時に 日本語を含む転送先(page)をバイナリ変換するときのコード名[UTF-8/Windows-31J]など(初期値:null)
 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   /&gt;
 *
 * ※ 6.4.3.0 (2016/02/05) disposition 追加
 *    以前は、inline 固定でしたが、引数で指定できるようにします。
 *
 * ●使用例
 *       &lt;og:forward
 *          page          = "転送先URLを指定します(必須)。"
 *          dbkeys        = "DBキーをCSV形式でセットします。"
 *          keys          = "キーを CSV形式でセットします。"
 *          vals          = "キーに対応する値を CSV形式でセットします。"
 *          scope         = "キャッシュする場合のスコープ(request,page,session,application)を指定します(初期値:session)。"
 *          gamenId       = "gamenId 属性を登録します。"
 *          useRedirect   = "useRedirect 属性を登録します。"
 *          filename      = "ファイル転送時にファイル名を指定する場合に設定します。"
 *          target        = "taregt 属性を登録します。"
 *          noTransition  = "実際にforwardせずに、id="forwardUrl"属性のbody部分に遷移先のURLを出力します。(画面遷移なしモード時に使用します)"
 *       /&gt;
 *
 * @og.group 画面制御
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class ForwardTag extends CommonTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.9.8.0 (2018/05/28)" ;
	private static final long serialVersionUID = 698020180528L ;

	private	transient DBTableModel	table 	;
	private	String		tableId		= HybsSystem.TBL_MDL_KEY;
	private	String		page		;
	private	String		keys		;
	private	String		dbkeys		;
	private	String[]	vals		;
	private	String		gamenId		;						// 3.5.4.9 (2004/02/25) 追加
	private	boolean		useRedirect ;						// 3.5.6.6 (2004/08/23) 追加
	private String		target		;						// 3.8.0.4 (2005/08/08) 追加
	private String		filename	;						// 4.0.0   (2005/11/30) 追加
	private String		disposition	= HybsSystem.sys( "CONTENT_DISPOSITION" );		// 6.4.3.0 (2016/02/05) 追加
	private boolean 	noTransition;						// 4.3.3.0 (2008/10/01) 追加
	private boolean 	useAjaxSubmit	;					// 4.3.8.0 (2009/08/01) 追加
	private String	 	redirectEncode	;					// 5.6.5.0 (2013/06/07) 追加
	// urlCheck関係 5.10.11.0 (2019/05/03) 追加
	private boolean		useURLCheck		= HybsSystem.sysBool( "LINK_URL_CHECK" );
	private long		urlCheckTime	= 1000*60*60*24;							// 5.10.11.0 (2019/05/03)
	private String		urlCheckCrypt	= HybsSystem.sys( "URL_CHECK_CRYPT" );

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

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 2.1.0.0 (2002/10/11) 戻り値の先頭の "?" を追加しないように変更。
	 * @og.rev 3.0.1.3 (2003/03/11) 直接転送した場合の整合性を取る為の対応。
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.1.2.0 (2003/04/07) ソースコード中の固定値を、定義ファイルを使用するように変更する。
	 * @og.rev 3.5.4.9 (2004/02/25) gamenId を指定して、フォワードできるようにします。
	 * @og.rev 3.5.6.6 (2004/08/23) useRedirect 属性を追加します。
	 * @og.rev 4.3.3.0 (2008/10/01) noTransition 属性を追加します。
	 * @og.rev 4.3.7.1 (2009/06/08) target属性に絶対パス及び"_"で始まる予約語を指定できるようにします。
	 * @og.rev 4.3.8.0 (2009/08/01) useAjaxSubmit対応、noTransition値取得メソッド名変更
	 * @og.rev 5.0.0.4 (2009/10/01) 画面遷移なし登録で戻った際に最終行が選択されるバグを修正
	 * @og.rev 5.1.3.0 (2010/02/01) noTransition、ajaxSubmitのコントロールは、requestで行う。
	 * @og.rev 5.1.6.0 (2010/05/01) IE以外は、MIMEエンコードする。(RFC2231に従う)
	 * @og.rev 5.1.7.0 (2010/06/01) 画面IDをパラメーターに付加する。
	 * @og.rev 5.1.7.0 (2010/06/01) 遷移先がJSP以外の場合は、フォワードページのキャッシュをしない。
	 * @og.rev 5.1.8.0 (2010/07/01) httpが指定されていた場合に、自身の画面IDが付加されるバグを修正
	 * @og.rev 5.3.8.0 (2011/08/01) ファイル名指定でIEの場合、URLエンコードすると途中で切れるため(IE7のバグ)、Shift_JIS(WIndows-31J)で直接指定する。
	 * @og.rev 5.6.5.0 (2013/06/07) redirectEncode 属性を追加します。
	 * @og.rev 5.7.4.1 (2014/03/14) 日本語ファイル名が正しく処理できない件を修正(IE11のMSIE関連)
	 * @og.rev 6.0.2.5 (2014/10/31) debug="true" を設定したときは、forward も sendRedirect も行わない。
	 * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
	 * @og.rev 6.4.0.2 (2015/12/11) 飛び先の画面が見つからない(アクセス権がない)場合、転送先URL を null にする。
	 * @og.rev 6.9.0.0 (2018/01/31) Windows10 の Edge で、ﾌｧｲﾙの文字化け対応(FileDownload servletと同じ対応を入れます)。
	 * @og.rev 6.9.8.0 (2018/05/28) debug="true" 時は、画面遷移は行わない。
	 * @og.rev 5.10.11.0 (2019/05/03) URLチェック対応を追加
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();									// 4.0.0 (2005/02/28)
		if( !useTag() ) { return EVAL_PAGE ; }			// 6.3.4.0 (2015/08/01)

		// noTransition = isNoTransitionRequest() || noTransition; // 4.3.3.0 (2008/10/01) 追加
		noTransition  = isNoTransitionRequest();		// 5.1.3.0 (2010/02/01)
		useAjaxSubmit = isAjaxSubmitRequest();			// 5.1.3.0 (2010/02/01)

		final String fwdUrl = makeGamenLink();			// 3.5.4.9 (2004/02/25)
		if( fwdUrl == null ) { return EVAL_PAGE ; }		// 6.4.0.2 (2015/12/11)

		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
		final String urlEnc = getUrlEncode();
		final HttpServletResponse response = (HttpServletResponse)pageContext.getResponse();
		try {
			String url = response.encodeRedirectURL( fwdUrl );	// 3.5.4.9 (2004/02/25)
			// 5.1.7.0 (2010/06/01) 画面IDをパラメーターに付加する。
			// 5.1.8.0 (2010/07/01) httpが指定されていた場合に、自身の画面IDが付加されるバグを修正
			// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
			if( filename == null ) {
				if( !page.startsWith( "http" ) && page.endsWith( ".jsp" ) ) {
					if( keys == null || keys.isEmpty() || ( "," + keys + "," ).indexOf( ",GAMENID," ) < 0 ) {
						if( gamenId != null && gamenId.length() > 0 ) {
							url = XHTMLTag.addUrlEncode( url, "GAMENID=" + gamenId );
						}
						// useRedirect=trueでGAMENIDを指定せず、../GF9100/index.jsp等と書かれている場合の対応
						else if( !useRedirect ) {
							url = XHTMLTag.addUrlEncode( url, "GAMENID=" + getGUIInfoAttri( "KEY" ) );
						}
					}
				}
			}
			else {
				final String newFilename	= filename;
				final String newFilenameEnc	= StringUtil.urlEncode( newFilename );		// 5.9.29.0 (2018/02/02)

				// 5.1.6.0 (2010/05/01) IE以外は、MIMEエンコードする。(RFC2231に従う)
				// 5.7.4.1 (2014/03/14) 日本語ファイル名が正しく処理できない件を修正(IE11のMSIE関連)
				// 条件を反転させた上でIE11対応を行う
				final String reqHeader = ((HttpServletRequest)pageContext.getRequest()).getHeader( "User-Agent" );
//				if( reqHeader.indexOf( "MSIE" ) >= 0 || reqHeader.indexOf( "Trident" ) >= 0 ) {
				if( reqHeader.indexOf( "MSIE" ) >= 0 || reqHeader.indexOf( "Trident" ) >= 0 || reqHeader.indexOf( "Edge" ) >= 0 ) {		// 6.9.0.0 (2018/01/31)
					filename = new String( filename.getBytes("Windows-31J"), "ISO-8859-1" );
				}
				else {
					filename = MimeUtility.encodeWord( filename, "UTF-8", "B" );
				}

//				response.setHeader( "Content-Disposition",disposition + "; filename=\"" + filename + "\"" );		// 6.4.3.0 (2016/02/05)
				response.setHeader( "Content-disposition",disposition + "; filename=\"" + newFilename
						+ "\"; filename*=UTF-8''" + newFilenameEnc );													// 5.9.29.0 (2018/02/02)　RFC6266方式を併記
			}

			// 3.5.6.6 (2004/08/23) useRedirect 属性を追加
			String url2 = XHTMLTag.addUrlEncode( url , urlEnc );
			// 4.3.3.0 (2008/10/01) 追加
			// if( noTransition ) {
			if( noTransition || useAjaxSubmit ) { // 4.3.8.0 (2009/08/01) useAjaxSubmitと共用
				// 5.0.0.4 (2009/10/01)
				if( noTransition ) {
					final int selRow = nval( getRequestValue( "SEL_ROW" ),-1 );
					if( selRow > 0 ) {
						url2 = XHTMLTag.addUrlEncode( url2, "SEL_ROW=" + selRow );
					}
				}
				if( useURLCheck ) { // 5.10.11.0 (2019/05/03) useURLCheck追加
					url2 = addURLCheck(url2);
				}
				// 6.9.8.0 (2018/05/28) debug="true" 時は、画面遷移は行わない。
				final String script = "<div id=\"noTransitionUrl\">" + url2 + "</div>" + 
									  "<div id=\"noTransitionTarget\">" + target + "</div>" ;

//				jspPrint( "<div id=\"noTransitionUrl\">" + url2 + "</div>" );
//				jspPrint( "<div id=\"noTransitionTarget\">" + target + "</div>" );
				if( isDebug() ) {
					final String debugMsg = "<pre>debug=\"true\" 時には、画面遷移を行いません。" + CR
											+ " noTransition=" + noTransition + " , useAjaxSubmit=" + useAjaxSubmit + CR
											+ " URL=" + url2 + CR
											+ "</pre>" + CR;
					jspPrint( debugMsg );
				}
				else {
					jspPrint( script );
				}
			}
			// 3.8.0.4 (2005/08/08) target 属性を追加します。
			else if( target != null && target.length() > 0 ) {
				// 4.3.7.1 (2009/06/08)
				String src = null;
				if( useURLCheck ) { // 5.10.11.0 (2019/05/03) useURLCheck追加
					url2 = addURLCheck(url2);
				}

				if( target.startsWith( "_b" ) ) { // "_blank"
					src = "window.open(\"" + url2 + "\", \"_blank\") ";
				}
				else {
					String frameTop = "";
					if( target.indexOf('.') < 0 ) { frameTop = "top."; }
					src = frameTop + target + ".location.href=\"" + url2 + "\"" + CR;
				}
				final String script = "<script type=\"text/javascript\" ><!-- " + CR
								+ src + CR
								+ "// --></script>" ;
				// 6.9.8.0 (2018/05/28) debug="true" 時は、画面遷移は行わない。
				if( isDebug() ) {
					final String debugMsg = "<pre>debug=\"true\" 時には、画面遷移を行いません。" + CR
											+ " target=" + target + CR
											+ " src=" + src + CR
											+ "</pre>" + CR;
					jspPrint( debugMsg );
				}
				else {
					jspPrint( script );
				}
			}
			else if( useRedirect ) {
				if( useURLCheck ) { // 5.10.11.0 (2019/05/03) useURLCheck追加
					url2 = addURLCheck(url2);
				}

				// 5.6.5.0 (2013/06/07) redirectEncode 属性追加
				if( redirectEncode != null ) {
					url2 = new String( url2.getBytes( redirectEncode ), "ISO-8859-1" );
				}

				// 6.0.2.5 (2014/10/31) debug="true" を設定したときは、forward も sendRedirect も行わない。
				if( isDebug() ) {
					final String debugMsg = "<pre>debug=\"true\" 時には、forward も sendRedirect も行いません。"
											+ CR
											+ "Redirect URL=" + url2 + CR
											+ "</pre>" + CR;
					jspPrint( debugMsg );
				}
				else {
					response.sendRedirect( url2 );
				}
			}
			else {
				// 6.0.2.5 (2014/10/31) debug="true" を設定したときは、forward も sendRedirect も行わない。
				if( isDebug() ) {
					final String debugMsg = "<pre>debug=\"true\" 時には、forward も sendRedirect も行いません。"
											+ CR
											+ "Forward URL=" + url2  + CR
											+ "</pre>" + CR;
					jspPrint( debugMsg );
				}
				else {
					pageContext.forward( url2 );
				}
			}
		} catch( final IOException ex ) {
			final String errMsg = "フォワード/リダイレクトでIOエラーが発生しました。"
								+ CR
								+ fwdUrl + "?" + urlEnc ;
			throw new HybsSystemException( errMsg,ex );		// 3.5.5.4 (2004/04/15) 引数の並び順変更
		} catch( final ServletException ex) {
			final String errMsg = "フォワード/リダイレクトでServletエラーが発生しました。"
								+ CR
								+ fwdUrl + "?" + urlEnc ;
			throw new HybsSystemException( errMsg,ex );		// 3.5.5.4 (2004/04/15) 引数の並び順変更
		}

		// 3.0.1.3 (2003/03/11) forward で直接転送した場合の整合性を取る為の対応。
		// 5.1.7.0 (2010/06/01) 遷移先がJSP以外の場合は、フォワードページのキャッシュをしない。
		// 6.9.8.0 (2018/05/28) FindBugs:null でないことがわかっている値の冗長な null チェック
//		if( fwdUrl != null && fwdUrl.endsWith( ".jsp" ) ) {
		if( fwdUrl.endsWith( ".jsp" ) ) {								// fwdUrl は、nullチェック済み
			setSessionAttribute( HybsSystem.FORWARD_PAGE_KEY, fwdUrl );	// 3.5.4.9 (2004/02/25)
		}

		return SKIP_PAGE ;		// ページの残りの処理を行わない。
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.5.4.9 (2004/02/25) 画面ID属性(gamenId)を追加
	 * @og.rev 3.8.5.0 (2006/03/06) filename 属性を追加します。
	 * @og.rev 4.3.3.0 (2008/10/01) noTransition 属性を追加します。
	 * @og.rev 5.6.5.0 (2013/06/07) redirectEncode 属性を追加します。
	 * @og.rev 6.4.3.0 (2016/02/05) disposition属性、新規追加。
	 * @og.rev 5.10.11.0 (2019/05/03) urlCheck対応
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		tableId			= HybsSystem.TBL_MDL_KEY;
		page			= null;
		keys			= null;
		dbkeys			= null;
		vals			= null;
		table 			= null;
		gamenId			= null;
		useRedirect		= false;				// 3.5.6.6 (2004/08/23) 追加
		target			= null;					// 3.8.0.4 (2005/08/08) 追加
		filename		= null;
		disposition		= HybsSystem.sys( "CONTENT_DISPOSITION" );		// 6.4.3.0 (2016/02/05) 追加
		noTransition	= false;				// 4.3.3.0 (2008/10/01) 追加
		useAjaxSubmit	= false;				// 4.3.8.0 (2009/08/01) 追加
		redirectEncode	= null;					// 5.6.5.0 (2013/06/07) 追加
		useURLCheck		= HybsSystem.sysBool( "LINK_URL_CHECK" ); // 5.10.11.0 (2019/05/03)
	}

	/**
	 * keys 属性 を元に、request情報より values の値を取り込む。
	 *
	 * keys属性は キー情報がCSV形式になっている為,ばらして
	 * values属性の配列に一つづつ設定していきます。
	 *
	 * @og.rev 3.1.7.0 (2003/05/02) 戻るボタン用のBACK_GAMENID を、引数に追加します。
	 * @og.rev 3.1.8.0 (2003/05/16) 戻るボタン用のBACK_GAMENID の自動登録を廃止します。
	 * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 *
	 * @return	URLエンコードされた文字列
	 */
	private String getUrlEncode() {
		final String[] dbkey = StringUtil.csv2Array( dbkeys );
		final String[] key   = StringUtil.csv2Array( keys );

		final int dbCount = dbkey.length;
		final int count   = key.length  ;

		String[] allKey = new String[ dbCount + count ];
		String[] allval = new String[ dbCount + count ];

		final int[] rowNo = getParameterRows();		// 4.0.0 (2005/01/31)
		if( dbCount > 0 && dbkey[0] != null && dbkey[0].length() > 0 && rowNo.length > 0 ) {
			table = (DBTableModel)getObject( tableId );
			if( table != null ) {
				for( int i=0; i<dbCount; i++ ) {
					allKey[i] = dbkey[i];
					allval[i] = table.getValue(rowNo[0],table.getColumnNo( dbkey[i] ));
				}
			}
		}

		// 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
		if( count > 0 && vals != null && vals.length == count ) {
			for( int i=0; i<count; i++ ) {
				allKey[i+dbCount] = key[i];
				allval[i+dbCount] = vals[i];
			}
		}

		return XHTMLTag.urlEncode( allKey,allval );
	}

	/**
	 * 【TAG】転送先URLを指定します。
	 *
	 * @og.tag 転送先URLを指定します。
	 *
	 * @param	url 転送先URL
	 */
	public void setPage( final String url ) {
		page = getRequestParameter( url );
	}

	/**
	 * 【TAG】DBキーをCSV形式でセットします。
	 *
	 * @og.tag
	 * URI の引数にセットするキーを CSV形式でセットします。
	 * ここの指定は,DBTableModel 上のデータを取り込みます。
	 *
	 * @param	key DBキー(CSV形式)
	 */
	public void setDbkeys( final String key ) {
		dbkeys = getRequestParameter( key ) ;
	}

	/**
	 * 【TAG】キーを CSV形式でセットします。
	 *
	 * @og.tag
	 * URI の引数にセットするキーを CSV形式でセットします。
	 *
	 * @param	key キー(CSV形式)
	 */
	public void setKeys( final String key ) {
		keys = getRequestParameter( key ) ;
	}

	/**
	 * 【TAG】キーに対応する値を CSV形式でセットします。
	 *
	 * @og.tag
	 * URI の引数にセットする値を CSV形式でセットします。
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @og.rev 3.5.6.2 (2004/07/05) CommonTagSupport#getCSVParameter を使用
	 *
	 * @param	val 値(CSV形式)
	 */
	public void setVals( final String val ) {
		vals = getCSVParameter( val );

		// 先に分解しないとデータ自身にカンマを持っている場合に分解をミスる。
	}

	/**
	 * 画面ＩＤとpage から、フォワードするＵＲＬを作成します。
	 * page が null の場合は、index.jsp に転送されます。
	 *
	 * @og.rev 3.5.4.9 (2004/02/25) 新規追加
	 * @og.rev 3.5.5.0 (2004/03/12) URLを求めるのに、GUIInfo#getRealAddress() を使用する。
	 * @og.rev 4.0.0.0 (2005/01/31) GUIInfoの実アドレスのパラメータを考慮する。
	 * @og.rev 6.4.0.2 (2015/12/11) 飛び先の画面が見つからない(アクセス権がない)場合、転送先URL を null にする。
	 *
	 * @return	フォワードするＵＲＬ(転送先URL)
	 */
	private String makeGamenLink() {
		if( page == null ) { page = "index.jsp"; }

		if( gamenId == null || gamenId.isEmpty() ) { return page; }

		final GUIInfo guiInfo = getGUIInfo( gamenId );
		if( guiInfo == null ) {					// 見つからない場合は、転送しない
			LogWriter.log( "Forward[" + gamenId + "]先にはアクセス不可です。" );
			return null;						// 6.4.0.2 (2015/12/11)
		}

		final String address = guiInfo.getRealAddress( page );
		final String link    = getRequestParameter( address );

		// Ver 4.0.0 (2007/06/12) gamenId を使用する場合は、useRedirect = true をセット
		useRedirect = true;
		return link;
	}

	/**
	 * 【TAG】画面ID を指定します。
	 *
	 * @og.tag
	 * gamenId 属性は、画面IDをキーに、実アドレスを求めるのに使用します。
	 * 画面IDが指定された場合は、実アドレスに変換する。指定されない場合は、
	 * page 属性をそのままリダイレクトアドレスとします。
	 * gamenId を指定した場合は、このuseRedirect属性に関係なく、Redirect されます。
	 *
	 * @og.rev 3.5.4.9 (2004/02/25) 新規追加
	 *
	 * @param   id 画面ID
	 * @see		#setUseRedirect( String )
	 */
	public void setGamenId( final String id ) {
		gamenId = nval( getRequestParameter( id ),gamenId );
	}

	/**
	 * 【TAG】response.sendRedirect するかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * useRedirect 属性は、URLの転送方式を指定できます。
	 * 通常は、pageContext.forward しますが、この属性に true を
	 * 設定すると、response.sendRedirect します。
	 * gamenId を指定した場合は、この属性に関係なく、Redirect されます。
	 * 初期値は、false (forward) です。
	 *
	 * @og.rev 3.5.6.6 (2004/08/23) 新規追加
	 *
	 * @param   flag リダイレクト転送か [true:redirect/false:forwrd]
	 * @see		#setGamenId( String )
	 */
	public void setUseRedirect( final String flag ) {
		useRedirect = nval( getRequestParameter( flag ),useRedirect );
	}

	/**
	 * 【TAG】サブミット先の文書を表示させるフレーム、またはウィンドウの名前を指定します。
	 *
	 * @og.tag サブミット先のフレーム名(ターゲット属性)を設定します。
	 *
	 * @og.rev 3.8.0.4 (2005/08/08) 新規追加
	 *
	 * @param	name フレーム名(ターゲット属性)
	 */
	public void setTarget( final String name ) {
		target = nval( getRequestParameter( name ),target );
	}

	/**
	 * 【TAG】ファイル転送時にファイル名の別名を指定します(初期値:null)。
	 *
	 * @og.tag
	 * ファイルを転送する場合に、オープンさせるファイル名を指定します。
	 * 指定しない場合は、フォラード前に呼び出されたアドレスがそのまま使用されます。
	 *
	 * ※ useRedirect="true"時(つまり、リダイレクトする場合)は、ファイル名の指定が
	 * できません。(少なくとも私の知識では出来ませんでした。)
	 *
	 * @param   name ファイル名
	 */
	public void setFilename( final String name ) {
		filename = nval( getRequestParameter( name ),filename );
	}

	/**
	 * 【TAG】ファイルダウンロードさせる場合に、Content-Disposition に設定する値
	 *		(初期値:CONTENT_DISPOSITION[={@og.value SystemData#CONTENT_DISPOSITION}])。
	 *
	 * @og.tag
	 * inline(そのまま開く) を指定すると、PDF などは直接ダウンロードが始まります。
	 * attachment(ダウンロードダイアログを表示する) を指定すると、保存のダイアログを表示しますが
	 * EXCEL などの場合、inline にしても、ダイアログが表示され、開くをクリックしても
	 * ダウンロードが始まらなかったり、EXCELが開いたあと、ブラウザの操作が出来なくなったり、
	 * よくわからないため、選択できるようにします。
	 * (初期値:システム定数のCONTENT_DISPOSITION[={@og.value SystemData#CONTENT_DISPOSITION}])。
	 *
	 * @og.rev 6.4.3.0 (2016/02/05) disposition属性、新規追加。
	 *
	 * @param   dispos Content-Dispositionに設定する値(inline/attachment)
	 */
	public void setDisposition( final String dispos ) {
		final String temp = nval( getRequestParameter( dispos ),disposition );

		if( "inline".equals( temp ) || "attachment".equals( temp ) ) {
			disposition = temp;
		}
		else {
			final String errMsg = "disposition 属性は、[inline/attachment] から、指定してください。"
								+ " disposition=[" + dispos + "]" + CR ;
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】(通常は使いません)画面遷移を行わない形式の登録方法を使用するかを指定します。
	 *
	 * @og.tag
	 * 画面遷移なしの登録を行うかどうかを指定します。
	 * trueが指定された場合、forwardタグでは、実際の画面遷移は行わずに、forward先の
	 * URLを<div id="noTransitionUrl">[URL]</div>の形でHTMLとして出力し、JavaScript側で
	 * 実際の画面遷移を発生させます。target属性は<div id="noTransitionTarget">[TARGET]</div>で
	 * 出力されます。
	 *
	 * この値は、og:headタグで設定値、または前画面からの値を継承するため、通常、この属性ではセットしません。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 新規追加
	 * @og.rev 5.1.3.0 (2010/02/01) noTransition、ajaxSubmitのコントロールは、requestで行う。
	 *
	 * @param   noTrnstn 画面遷移を行わない登録か [true:画面遷移を伴わない/false:伴う]
	 */
	public void setNoTransition( final String noTrnstn ) {
		setNoTransitionRequest( nval( getRequestParameter( noTrnstn ), isNoTransitionRequest() ) );
	}

	/**
	 * 【TAG】(通常は使いません)ajaxを利用したsubmitを利用するかどうか[true:利用する/false:利用しない]を指定します。
	 *
	 * @og.tag
	 * ajaxを利用したSubmit処理を行うかどうかを指定します。
	 * setNoTransitionをtrueにした場合と同様の処理を行います。
	 * (forwardせずにURLをDIVタグで出力する)
	 *
	 * この値は、og:headタグで設定値、または前画面からの値を継承するため、通常、この属性ではセットしません。
	 *
	 * @og.rev 4.3.8.0 (2009/08/01) 新規追加
	 * @og.rev 5.1.3.0 (2010/02/01) noTransition、ajaxSubmitのコントロールは、requestで行う。
	 *
	 * @param   ajaxSubmit ajaxを利用したsubmitを利用するか [true:利用する/false:利用しない]
	 */
	public void setUseAjaxSubmit( final String ajaxSubmit ) {
		setAjaxSubmitRequest( nval( getRequestParameter( ajaxSubmit ), isAjaxSubmitRequest() ) );
	}

	/**
	 * 【TAG】(通常は使いません)useRedirect=true時に 日本語を含む転送先(page)をバイナリ変換するときのコード名[UTF-8/Windows-31J]など(初期値:null)。
	 *
	 * @og.tag
	 * 日本語ファイル名を持つ URL を useRedirect で転送する場合に、転送先(page)をバイナリ変換しないと、転送できないケースがあります。
	 * このあたりは、ブラウザにも依存するので、既存の処理に影響しない様に、このパラメータを使用する場合のみ
	 * 処理を実行します。
	 * IEでの日本語ファイル転送で、うまくいかない場合の、暫定処置です。
	 * IEの場合は、redirectEncode="UTF-8" で、日本語ファイルを転送できます。
	 * ただし、useRedirect=true時に filename 属性によるファイル名の書き換え処理はできませんので、ご注意ください。
	 * 初期値は、null で、バイナリエンコードしません。（互換性ありの状態です。）
	 *
	 * @og.rev 5.6.5.0 (2013/06/07) 新規追加
	 *
	 * @param   redEnc 転送先(page)の変換文字コード名 (UTF-8/Windows-31Jなど)
	 */
	public void setRedirectEncode( final String redEnc ) {
		redirectEncode = nval( getRequestParameter( redEnc ), redirectEncode );
	}

	/**
	 * 【TAG】リンクアドレスにURLチェック用の確認キーを付加するかどうか[true/false]を指定します。
	 *
	 * @og.tag
	 * この属性は、URLCheckFilter(org.opengion.hayabusa.filter.URLCheckFilter)と合わせて使用します。
	 * trueが指定された場合、リンクURLのパラメーターに、URL確認用のパラメーターが出力されます。
	 * このパラメーターを、URLCheckFilterが復号化し、正式なアクセスであるかどうかの判定を行います。
	 *
	 * 初期値は、 システムリソースのLINK_URL_CHECK です。
	 *
	 * @og.rev 5.10.11.0 (2019/05/03) 新規追加
	 *
	 * @param	flag 暗号化するかかどうか [true:暗号化する/false:しない]
	 * @see org.opengion.hayabusa.filter.URLCheckFilter
	 */
	public void setUseURLCheck( final String flag ) {
		useURLCheck = nval( getRequestParameter( flag ),useURLCheck );
	}

	/**
	 * urlCheckのパラメータを付加します。 
	 * 
	 * @og.rev 5.10.11.0 (2019/05/03) 新規追加
	 * 
	 * @param url 元のアドレス
	 * @return urlCheckを付加したアドレス
	 */
	private String addURLCheck( final String url ) {
		HybsCryptography criptCls = null;
		if( urlCheckCrypt != null && urlCheckCrypt.length() > 0 ){
			criptCls = new HybsCryptography( urlCheckCrypt );
		}
		return XHTMLTag.addURLCheckKey( url, HybsSystem.URL_CHECK_KEY, getUser().getUserID(), System.currentTimeMillis() + urlCheckTime, criptCls );
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"			,VERSION		)
				.println( "tableId"			,tableId		)
				.println( "page"			,page			)
				.println( "keys"			,keys			)
				.println( "dbkeys"			,dbkeys			)
				.println( "vals"			,vals			)
				.println( "gamenId"			,gamenId		)
				.println( "useRedirect" 	,useRedirect	)
				.println( "target"			,target			)
				.println( "filename"		,filename		)
				.println( "disposition"		,disposition	)
				.println( "noTransition"	,noTransition	)
				.println( "useAjaxSubmit"	,useAjaxSubmit	)
				.println( "redirectEncode"	,redirectEncode	)
				.println( "useURLCheck"		,useURLCheck	)		// 5.10.11.0 (2019/05/03)
				.println( "Other..."		,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
