/*
 * 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.system.OgBuilder ;					// 6.4.4.1 (2016/03/18)
import org.opengion.fukurou.util.StringUtil ;
import org.opengion.fukurou.util.ToString;						// 6.1.1.0 (2015/01/17)

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

/**
 * {&#064;XXXX} 変数の特殊処理を、動的に実行するタグです。
 *
 * このタグの目的は、{&#064;XXXX} 変数の使い方をドキュメント化することにあります。
 * 通常は、動的な編集処理を行う必要はありません。
 *
 * 通常のリクエスト変数は、{&#064;XXXX} で取り出すことが可能です。ところが、
 * {&#064;SYS.XXXX} 、{&#064;USER.XXXX} 、{&#064;GUI.XXXX}、 などのシステム予約の
 * 変数を取り出す場合に、XXXX 部分を動的に変更することは出来ません。
 * このタグは、簡易的に、XXXX を引数に取り、動的に取り出すことができるようにします。
 *
 * @og.formSample
 * ●形式：
 *    &lt;og:requestValue
 *        sys       = "XXXX"       システムパラメータ の値を取得
 *        user      = "ID"         UserInfoオブジェクトの値を取得(og:userInfo)
 *        gui       = "KEY"        GUIInfoオブジェクトの値を取得
 *        mem       = "XXXX"       REQUEST_CACHE の値を取得
 *        lbl       = "XXXX"       ラベルリソースの値を取得
 *        msg       = "XXXX"       メッセージリソースの値を取得
 *        db        = "COUNT"      データベース実行結果を取得
 *        session   = "XXXX"       session Attribute の値を取得
 *        date      = "XXXX"       日付関係の値を取得
 *        nvar      = "XXXX"       Unicode文字列の値を HTML のエスケープ記号(&amp;#xZZZZ;)に変換します。
 *    &gt;
 * ●body：なし
 *
 * ●Tag定義：
 *   &lt;og:requestValue
 *       sys                【TAG】{&#064;SYS.XXXX} と同等のシステムパラメータ の値を取得します
 *       user               【TAG】{&#064;USER.XXXX} と同等のUserInfoオブジェクトの値を取得します
 *       gui                【TAG】{&#064;GUI.XXXX} と同等のGUIInfoオブジェクトの値を取得します
 *       mem                【TAG】{&#064;MEM.XXXX} と同等のREQUEST_CACHE の値を取得します
 *       lbl                【TAG】{&#064;LBL.XXXX} と同等のラベルリソースの値を取得します
 *       db                 【TAG】データベース実行結果を取得します
 *       session            【TAG】session Attribute の値を取得します
 *       date               【TAG】日付関係の値を取得します
 *       nvar               【TAG】Unicode文字列の値を HTML のエスケープ記号(&amp;#xZZZZ;)に変換します
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   /&gt;
 *
 *
 * @og.rev 3.8.0.2 (2005/07/11) 新規作成
 * @og.group 画面部品
 *
 * @version  0.9.0  2000/10/17
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class RequestValueTag extends CommonTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.4.1 (2016/03/18)" ;
	private static final long serialVersionUID = 644120160318L ;

	private String	sys		;
	private String	user	;
	private String	gui 	;
	private String	mem 	;
	private String	lbl 	;
	private String	db		;
	private String	session ;
	private String	date	;
	private String	nvar	;

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

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
	 * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)

		final OgBuilder buf = new OgBuilder()
				.appendIf( sys	 	!= null , sys		, v -> sys(						v.trim() ) )
				.appendIf( user		!= null , user		, v -> getUserInfo(				v.trim() ) )
				.appendIf( gui		!= null , gui		, v -> getGUIInfoAttri(			v.trim() ) )
				.appendIf( mem		!= null , mem		, v -> getRequestCacheData(		v.trim() ) )
				.appendIf( lbl		!= null , lbl		, v -> getLabel(				v.trim() ) )
				.appendIf( db		!= null , db		, v -> getRequestParameter( "{@DB." + v.trim() + "}" ) )
				.appendIf( session	!= null , session	, v -> getSessionAttribute(		v.trim() ) )
				.appendIf( date		!= null , date		, v -> getDateFormat(			v.trim() ) )
				.appendIf( nvar		!= null , nvar		, v -> StringUtil.getUnicodeEscape( getRequestValue( v.trim() ) ) );

		jspPrint( buf.toString() );

		return EVAL_PAGE ;		// ページの残りを評価する。

//		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
//
//		if( sys != null ) {
//			buf.append( sys( sys.trim() ) );
//		}
//		else if( user != null ) {
//			buf.append( getUserInfo( user.trim() ) );
//		}
//		else if( gui != null ) {
//			buf.append( getGUIInfoAttri( gui.trim() ) );
//		}
//		else if( mem != null ) {
//			buf.append( getRequestCacheData( mem.trim() ) );
//		}
//		else if( lbl != null ) {
//			buf.append( getLabel( lbl.trim() ) );
//		}
//		else if( db != null ) {
//			buf.append( getRequestParameter( "{@DB." + db.trim() + "}" ) );
//		}
//		else if( session != null ) {
//			buf.append( getSessionAttribute( session.trim() ) );
//		}
//		else if( date != null ) {
//			buf.append( getDateFormat( date.trim() ) );
//		}
//		else if( nvar != null ) {
//			buf.append( StringUtil.getUnicodeEscape( getRequestValue( nvar.trim() ) ) );
//		}
//
//		jspPrint( buf.toString() );
//
//		return EVAL_PAGE ;		// ページの残りを評価する。
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 *
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		sys 	= null;
		user	= null;
		gui 	= null;
		mem 	= null;
		lbl 	= null;
		db		= null;
		session = null;
		date	= null;
		nvar	= null;
	}

	/**
	 * 【TAG】{&#064;SYS.XXXX} と同等のシステムパラメータ の値を取得します。
	 *
	 * @og.tag
	 * 本来は、システムパラメータ の値を取得できますが、システム的な共有値も
	 * 取得できるように機能追加しています。
	 * また、ユーザー個別にシステムパラメータを変更できます。この取得は、
	 * システムパラメータとして取得します。(値はユーザー個別値を返します。)
	 *
	 * SERVER_NAME     このTomcatが実行しているサーバー名             localhost 等
	 * SERVER_URL      Portも含むURLアドレス                          http://localhost:8823/
	 * CONTEXT_URL     実行しているコンテキストのURLアドレス          http://localhost:8823/dbdef2/
	 * REAL_PATH       / ルートに対応する物理ディレクトリ             d:/webapps/dbdef2/ 等
	 * CONTEXT_NAME    コンテキスト名(webapps 直下の仮想フォルダ名)   dbdef 等
	 * DATE            YMDH とほぼ同じですが、'yyyy/MM/dd HH:mm:ss' の形式で取得できます。
	 * 任意            ユーザーパラメータ(GE16) の値/システムパラメータ(GE12)の値を取得
	 *
	 * {&#064;SYS.COOKIE.カラム名}で、Cookie の読み込みを行えます。
	 * 上記以外に、予約語や、システムパラメータ の値の読取が可能です。
	 *
	 * @param	val ｼｽﾃﾑID
	 */
	public void setSys( final String val ) {
		sys = nval( getRequestParameter( val ),sys );
	}

	/**
	 * 【TAG】{&#064;USER.XXXX} と同等のUserInfoオブジェクトの値を取得します。
	 *
	 * @og.tag
	 * ユーザーパラメータとは異なります。
	 *
	 * 以下の値は UserInfo オブジェクトの項目から取得します。
	 *
	 * ・JNAME     ユーザー日本語名称
	 * ・ID        ユーザーＩＤ
	 * ・IDNO      USER.ID が５Byte以上の時のみ先頭１文字を除いたユーザーＩＤ
	 * ・INFO      ユーザー情報(ユーザーID：日本語名称)
	 * ・LANG      言語
	 * ・ROLES     ロール
	 * ・IPADDRESS IPアドレス
	 * ・LOGINTIME ログイン時刻
	 *
	 * 以下の値はあらかじめ、動的に作成されます。
	 *
	 * ・YMD       ８byte の今日のシステム日付
	 * ・YMDH    １４byte の今日のシステム日時
	 *
	 * それ以外は、外部より設定された値です。
	 *
	 * @param	val ﾕｰｻﾞｰID
	 */
	public void setUser( final String val ) {
		user = nval( getRequestParameter( val ),user );
	}

	/**
	 * 【TAG】{&#064;GUI.XXXX} と同等のGUIInfoオブジェクトの値を取得します。
	 *
	 * @og.tag
	 * GUIInfo オブジェクトで定義されている属性情報を取り出すことが出来ます。
	 * 引数は、"XXXX ID" という状態で受け取ります。(GUI. ははずした形)
	 * XXXXには、画面情報(GUIInfo)の属性キーを指定します。IDが指定されない場合は、
	 * 実行中の自分自身の画面が指定されたことになります。
	 * これは、session 登録項目 の HybsSystem#GUIINFO_KEY キー の値で取得します。
	 * この値は,画面が呼び出される毎に毎回設定されており、リクエスト毎に
	 * 所得し直す必要があります。
	 *
	 * ID に、画面IDを指定した場合は、&#064; 指定によるリクエスト引数の値を適用できます。
	 * {&#064;GUI.&#064;XXXX ID} や、{&#064;GUI.XXXX &#064;ID} です。(同時指定も可能)
	 *
	 * ・KEY           画面ID
	 * ・ADDRESS       実行アドレス
	 * ・REALADDRESS   実行実アドレス
	 * ・SEQUENCE      表示順
	 * ・GROUPS        メニュグループ
	 * ・CLASSIFY      メニュ分類
	 * ・LEVEL         メニュ階層番号
	 * ・LABEL         画面名称
	 * ・NAME          画面名称(=SNAME)
	 * ・SNAME         画面名称(short)
	 * ・LNAME         画面名称(long)
	 * ・ROLES         ロールズ
	 * ・MODE          アクセスモード列(mr,mw,-r,-w の羅列)
	 * ・TARGET        ターゲット
	 * ・PARAM         設定値(パラメータ)
	 * ・KBLINK        リンク区分
	 * ・DESCRIPTION   概要説明
	 *
	 * @param	val 画面ID
	 */
	public void setGui( final String val ) {
		gui = nval( getRequestParameter( val ),gui );
	}

	/**
	 * 【TAG】{&#064;MEM.XXXX} と同等のREQUEST_CACHE の値を取得します。
	 *
	 * @og.tag
	 * 検索時の request 情報をキャッシュしているメモリ上から値を取り出します。
	 * 通常は、query_init.jsp で定義されている GAMENID付の
	 * リクエストキャッシュ情報を取り出します。
	 *
	 * @param	val ﾒﾓﾘｷｰ
	 */
	public void setMem( final String val ) {
		mem = nval( getRequestParameter( val ),mem );
	}

	/**
	 * 【TAG】ラベルリソースのラベルIDを指定します。
	 *
	 * @og.tag
	 * {&#064;LBL.XXXX} と同等のラベルリソースの値を取得します。
	 * ラベルリソースのロケールは、ログインユーザーのロケールになります。
	 * これは、{&#064;LBL.XXXX Y} 引数処理をおこなうための、サポートメソッドです。
	 * 引数は、"XXXX Y" という状態で受け取ります。(LBL. ははずした形)
	 * ラベルには、通常のラベル(Label)以外に、Short,Tips,Comment の情報を持っています。
	 * {&#064;LBL.XXXX Y} の Y に、先のLabel,Short,Tips,Comment の頭文字('L','S','T','C')を
	 * 指定することで、それぞれの状態を取得することが可能になります。
	 * Y を指定しない場合({&#064;LBL.XXXX}) は、'L' が指定された場合と同じ効果があります。
	 * Y は、先頭文字１文字で判断していますので、{&#064;LBL.XXXX Short}と記述できます。
	 * Y 引数には、&#064;で始まるリクエスト引数が指定できます。例えば、{&#064;LBL.XXXX &#064;ZZ}
	 * とすると、ZZ のリクエスト引数の値が Y に適用されます。
	 * ラベルキーそのものをパラメータ化することが出来ます。
	 * これは、{&#064;LBL.&#064;XXXX}という形式になります。引数は、先の説明と同じです。
	 * この場合は、XXXX をキーにリクエスト引数の値が、ラベルリソースのキーになります。
	 *
	 * @param	val ﾗﾍﾞﾙID
	 */
	@Override
	public void setLbl( final String val ) {
		lbl = nval( getRequestParameter( val ),lbl );
	}

	/**
	 * 【TAG】データベース実行結果を取得します。
	 *
	 * @og.tag
	 * 検索結果の件数を、"DB.COUNT" キーでリクエストにセットしています。
	 * 検索結果を、"DB.ERR_CODE" キーでリクエストにセットしています。
	 * これらは、リクエストのアトリビュートへセットしている為、query タグや、
	 * directWriteTable タグの処理以降のリクエストスコープ中での取得になります。
	 *
	 * @param	val 取得ｷｰ
	 */
	public void setDb( final String val ) {
		db = nval( getRequestParameter( val ),db );
	}

	/**
	 * 【TAG】session Attribute の値を取得します。
	 *
	 * @og.tag
	 * session スコープに登録されているアトリビュートオブジェクトの値を
	 * 取り出します。
	 *
	 * @param	val ｾｯｼｮﾝｷｰ
	 */
	public void setSession( final String val ) {
		session = nval( getRequestParameter( val ),session );
	}

	/**
	 * 【TAG】日付関係の値を取得します。
	 *
	 * @og.tag
	 * これは、{&#064;DATE.XXXX AA BB} 引数処理をおこなうための、サポートメソッドです。
	 * 引数は、"XXXX AA BB" という状態で受け取ります。(DATE. ははずした形)
	 * "XXXX" は、日付処理を行うキー文字列で予約語になっています。
	 * ・YMD　　：８文字の日付データ(200X年XX月XX日)を扱います。
	 * ・Y2MD　 ：６文字の日付データ(0X年XX月XX日)を扱います。
	 * ・YM　　 ：６文字の日付データ(200X年XX月)を扱います。
	 * ・HMS　　：６文字の時刻データ(XX時XX分XX秒)を扱います。
	 * ・YMDHMS ：１４文字の日付データ(200X年XX月XX日XX時XX分XX秒)を扱います。
	 * ・EEE　　：曜日をデフォルトロケールで表示します。
	 *
	 * F付きは、フォーマットされた日付を返します。
	 * ・YMDF　 ：８文字の日付データ(200X年XX月XX日)を扱います。
	 * ・Y2MDF　：６文字の日付データ(0X年XX月XX日)を扱います。
	 * ・YMF　　：６文字の日付データ(200X年XX月)を扱います。
	 * ・HMSF　 ：６文字の時刻データ(XX時XX分XX秒)を扱います。
	 * ・YMDHMSF：１４文字の日付データ(200X年XX月XX日XX時XX分XX秒)を扱います。
	 *
	 * AA 引数は、基準となる日付を、YYYYMMDD形式で指定します。無指定の場合は、
	 * 処理時刻を基準にした、同一タグ内での同一日付(年月日時分秒)を使用して値を取得します。
	 * 指定できる日付は、必ず、YYYYMMDD形式とし、時分秒は ゼロにリセットされた状態になります。
	 * AA には、数字で始まる(20050701など)実日付と&#064;で始まるパラメータが使用できます。
	 * &#064;ZZ と記述することで、{&#064;ZZ}で指定する場合と同様のリクエストパラメータが使用できます。
	 * このパラメータの値は、YYYYMMDD形式の数字か、null(またはゼロストリング)です。nullの
	 * 場合は、なにも指定されていないと判断して、処理時刻を使用します。
	 * 第２引数は、(数字か、&#064;)以外の場合は、省略されたと判断されます。
	 *
	 * BB 引数は、日付についての加減算処理を行います。
	 * 省略すると、なにも加減算処理を行いません。
	 * ・SD ：当月の最初の日付にセットします。(当月１日)
	 * ・ED ：当月の最後の日付にセットします。(当月月末)
	 * ・SM ：本年の最初の月にセットします。(本年１月)
	 * ・EM ：本年の最後の月にセットします。(本年１２月)
	 * ・SW ：日付処理の週初め(月曜日)にセットします。日付は当日より前に移動します。
	 * ・EW ：日付処理の週末(日曜日)にセットします。日付は当日より後ろに移動します。
	 * ・D1 ～ DXXX ：日を指定の分だけ進めます。D1なら翌日、D200 なら200日後
	 * ・M1 ～ MXXX ：月を指定の分だけ進めます。M1なら翌月、M6 なら半年後
	 *
	 * @param	val 日付ｷｰ
	 */
	public void setDate( final String val ) {
		date = nval( getRequestParameter( val ),date );
	}

	/**
	 * 【TAG】Unicode文字列の値を HTML のエスケープ記号(&amp;#xZZZZ;)に変換します。
	 *
	 * @og.tag
	 * HTMLでのエスケープ文字を使用して、Unicodeを文字列化して登録する為の変換を行います。
	 * ここでは、入力文字を、キャラクタ(char)型に分解し、(&amp;#xZZZZ;)に変換していきます。
	 * よって、通常に１文字(Shift-JISで２Byte,UTF-8で３Byte)が、８Byteになります。
	 * この変換された文字列を、HTML上でそのまま取り出すと、元のUnicode文字に戻る為、
	 * 通常のShift-JISでは、扱えない文字(中国語など)でも表示可能になります。
	 *
	 * @param	val Unicode文字列
	 */
	public void setNvar( final String val ) {
		nvar = nval( getRequestParameter( val ),nvar );
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"		,VERSION	)
				.println( "sys"			,sys 		)
				.println( "user"		,user		)
				.println( "gui"			,gui 		)
				.println( "mem"			,mem 		)
				.println( "lbl"			,lbl 		)
				.println( "db"			,db			)
				.println( "session"		,session	)
				.println( "date"		,date		)
				.println( "nvar"		,nvar		)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
