/*
 * 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 static org.opengion.fukurou.util.StringUtil.nval ;
import org.opengion.fukurou.util.XHTMLTag;

/**
 * TagSupport から継承されたサブクラスです。
 *
 * 汎用属性 のsetterメソッドを持っています。
 * それ以外に、{&#064;XXXX} 変数の対応と、lang属性のメソッドも用意しています。
 *
 * ロケールは、ユーザー情報の lang 属性をデフォルトで使用し、
 * セットされていない場合は、リクエスト情報のロケールから取得します。
 *
 * 各属性は、{&#064;XXXX} 変数が使用できます。
 * これは、ServletRequest から、XXXX をキーに値を取り出し,この変数に
 * 割り当てます。つまり、このXXXXをキーにリクエストすれば、
 * この変数に値をセットすることができます。
 *
 * http://localhost/query.jsp?KEY1=VLA1&amp;KEY2=VAL2
 *
 * のようなリクエストで、{&#064;KEY1} とすれば、 VAL1 がセットされます。
 *
 * このタグは、ラベル部分と入力フィールド部分がテーブルタグの&lt;td&gt;
 * により左右に分割されます。HTML 表示時は、前後に&lt;tr&gt;タグで囲って,
 * 整形できます。
 *
 * @og.group 画面部品
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
abstract class HTMLTagSupport extends CommonTagSupport {
	// 5.2.1.0 (2010/10/01) must , mustAny 属性を自動化します。
	private String	mustType	= null;		// 5.2.1.0 (2010/10/01)

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 4.0.0.0 (2005/11/30) ロール を考慮します。
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
	 *
	 * @return	後続処理
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		// 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
		if( useTag() ) {
			// 4.0.0 (2005/11/30) 指定のロールが、アクセス許可の場合は、出力します。
	//		if( getUser().isAccess( get( "roles" ) ) ) {
	//			jspPrint( makeTag() );
	//		}

			// 4.3.0.0 (2008/07/04) ロールモードマルチ対応
			if( getUser().isAccess( get( "roles" ) ) ) {
				jspPrint( makeTag() );
			}
		}
		return(EVAL_PAGE);
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) mustType 属性を追加。
	 */
	@Override
	protected void release2() {
		super.release2();
		mustType	= null;		// 5.2.1.0 (2010/10/01)
	}

	/**
	 * ボタンを作成します。
	 *
	 * &lt;button type="submit" name="名前" value="値"&gt;
	 *
	 * @return  ボタンタグ文字列
	 */
	abstract protected String makeTag() ;

	/**
	 * 【HTML】要素に対して固有の名前(id)をつける場合に設定します。
	 *
	 * @og.tag
	 * 特別な使用方法として、id="FOCUS" とすることで、フィールド系要素に
	 * フォーカスを移動させます。これは、そのページ内で唯一の id 属性として使用ください。
	 *
	 * @param   id 固有の名前
	 */
	@Override
	public void setId( final String id ) {
		set( "id",getRequestParameter( id ) );
	}

	/**
	 * 【HTML】要素に対して class 属性を設定します。
	 *
	 * @og.tag
	 * Javaの言語使用上、class で作成できないため、代用として
	 * clazz を使用しています。
	 * html で作成される属性は、 class で作成されます。
	 *
	 * @og.rev 3.5.0.0 (2003/09/17) set ではなく、add を利用します。
	 *
	 * @param   cls classを表す文字列
	 */
	public void setClazz( final String cls ) {
		add( "class",getRequestParameter( cls ) );	// 3.5.5.9 (2004/06/07) セパレータ引数付きのメソッドに変更
	}

	/**
	 * 【HTML】要素の内容と他の属性値の言語(lang,xml:lang)を指定します。
	 *
	 * @og.tag
	 * HTMLの言語属性に使われます。指定する値は、ISO 639で規定されている「言語コード」です。
	 * [ja/en/zh/…]などのほかに、en-US:アメリカ英語、en-cockney:コックニー英語 など、
	 * 副言語を指定する方法も定められています。
	 * ここでは、lang と xml:lang の両方に同じ値がセットされます。
	 * タグの language 属性とは使用用途が異なります。
	 *
	 * @og.tag lang セット
	 *
	 * @param   lang 言語[ja/en/zh/…]
	 */
	public void setLang( final String lang ) {
		String lng = getRequestParameter( lang );
		if( lng != null ) {
			set( "lang",lng );
			set( "xml:lang",lng );
		}
	}

	/**
	 * 【HTML】文字表記の方向(dir)を指定します。
	 *
	 * @og.tag
	 * 当該要素の書字方向を指定する属性です。
	 * ltr で、左から右に、rtl で、右から左に並べます。
	 *
	 * @param   dir (ltr:左から右、rtl:右から左 )
	 */
	public void setDir( final String dir ) {
		set( "dir",getRequestParameter( dir ) );
	}

	/**
	 * 【HTML】要素に対する補足的情報(title)を設定します。
	 *
	 * @og.tag
	 * title セットは、ボタンなどに適用すると、マウスオーバーによりこのメッセージが
	 * チップスのように表示されます。これを利用して、説明文を登録することが可能です。
	 * ここに登録した文字列が、メッセージリソースに存在する場合は、そのメッセージを
	 * 存在しない場合は、そのままの値を設定します。
	 *
	 * @og.rev 3.5.5.8 (2004/05/20) メッセージリソースから読み込んだ文字を使用します。
	 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage > getResource().getLabel )
	 *
	 * @param   title 補足的情報(title)
	 */
	public void setTitle( final String title ) {
		String str = nval( getRequestParameter( title ),null );
		if( str != null ) {
//			set( "title",getResource().getMessage( str ) );
			set( "title",getResource().getLabel( str ) );
		}
	}

	/**
	 * 【HTML】この要素に対して適用させるスタイルシート(style)を設定します。
	 *
	 * @og.tag
	 * タグにstyle属性を設定します。これは、キー:値; のセットを複数記述できます。
	 * 通常は、class属性や、id属性で登録しておき、&lg;style type="text/css"&gt; で
	 * 外部から指定する方がソースは読みやすくなります。
	 *
	 * @param   style スタイルシート(style="color:red; font-size:24pt;" など)
	 */
	public void setStyle( final String style ) {
		set( "style",getRequestParameter( style ) );
	}

	/**
	 * 【TAG】その部品に対して変更が出来ないように(readonly)指定します(サーバーに送信される)。
	 *
	 * @og.tag
	 * INPUT/TEXTAREA 系に対して、指定可能です。
	 * readonly="readonly" , readonly="true" が指定された場合は、有効です。
	 * false も指定値としては、有効です。(大文字小文字の区別も不要)
	 * それ以外の指定は、エラーとします。
	 *
	 * @og.rev 3.7.1.0 (2005/04/26) readonly,true,false が指定できるように変更。
	 *
	 * @param   ronly 読み取り専用属性[readonly/true/false]
	 */
	public void setReadonly( final String ronly ) {
		String readonly = nval( getRequestParameter( ronly ),null );
		if( readonly != null ) {
			if( readonly.equalsIgnoreCase( "readonly" ) ||
				readonly.equalsIgnoreCase( "true"     ) ) {
					set( "readonly","readonly" );
			}
			else if( ! readonly.equalsIgnoreCase( "false" ) ) {
				String errMsg = "readonly には、[readonly,true,false]以外の文字は指定できません。"
								+ " readonly=[" + readonly + "]" + HybsSystem.CR ;
				throw new HybsSystemException( errMsg );
			}
		}
	}

	/**
	 * 【TAG】その部品に対して、選択や変更が出来ないように(disabled)指定します(サーバーに送信されない)。
	 *
	 * @og.tag
	 * BUTTON/INPUT/OPTGROUP/OPTION/SELECT/TEXTAREA 系に対して、指定可能です。
	 * disabled="disabled" , disabled="true" が指定された場合は、有効です。
	 * false も指定値としては、有効です。(大文字小文字の区別も不要)
	 * それ以外の指定は、エラーとします。
	 *
	 * @og.rev 3.7.1.0 (2005/04/26) disabled,true,false が指定できるように変更。
	 *
	 * @param   dis 選択や変更が出来ないようにするかどうか[disabled/true/false]
	 */
	public void setDisabled( final String dis ) {
		String disabled = nval( getRequestParameter( dis ),null );
		if( disabled != null ) {
			if( disabled.equalsIgnoreCase( "disabled" ) ||
				disabled.equalsIgnoreCase( "true"     ) ) {
					set( "disabled","disabled" );
			}
			else if( ! disabled.equalsIgnoreCase( "false" ) ) {
				String errMsg = "disabled には、[disabled/true/false]以外の文字は指定できません。"
								+ " disabled=[" + disabled + "]" + HybsSystem.CR ;
				throw new HybsSystemException( errMsg );
			}
		}
	}

	/**
	 * 【HTML】タブの移動順(tabindex)を指定します(0 ～ 32767)。
	 *
	 * @og.tag
	 * Tabキーを押したときに要素が選択される順番を指定します。
	 * 値には、選択させたい順番を数値で記述します。
	 *
	 * @param	tabindex	タブの移動順(0 ～ 32767)
	 */
	public void setTabindex( final String tabindex ) {
		set( "tabindex",getRequestParameter( tabindex ) );
	}

	/**
	 * 【HTML】アクセスキー(alt+キーで直接指定)を割り当てます。
	 *
	 * @og.tag
	 * アクセスキーは、マウスの使えない環境でも、リンクにジャンプする、ボタンを押す、入力フォームに
	 * フォーカスを移すなどの操作を簡単に行うことができるように考慮されたものです。
	 * Windows の「ファイル(F)」メニューについている、F と同じような働きをします。
	 *
	 * @param   accesskey アクセスキー
	 */
	public void setAccesskey( final String accesskey ) {
		set( "accesskey",getRequestParameter( accesskey ) );
	}

	/**
	 * 【TAG】JavaScript などの HTML基本タグ以外の属性を、そのままタグとして使用します。
	 *
	 * @og.tag
	 * JavaScript などの HTML基本タグ以外の属性を、そのまま
	 * タグとして使用します。<del>そのときに、(')は、(")に置き換えます。</del>
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) (')を(")に置き換え処理していたのを止める。
	 *
	 * @param   optionAttributes HTML基本タグ以外の属性
	 */
	public void setOptionAttributes( final String optionAttributes ) {
		String optAttri = getRequestParameter( optionAttributes );
		if( optAttri != null && optAttri.length() > 0 ) {
			set( "optionAttributes",optAttri );
		}
	}

	/**
	 * 【HTML】JavaScriptのイベント onClick を設定します(例:onClick="renew('query.jsp','QUERY');")。
	 *
	 * @og.tag
	 * onClick をセットします。
	 * 例えば、&lt;og:column name="KBSAKU" onClick="renew('query.jsp','QUERY');" /&gt;
	 * のように指定することで、プルダウンメニューの絞込み検索が可能になります。
	 *
	 * @og.rev 3.5.0.0 (2003/09/17) 新規追加
	 * @og.rev 3.5.5.9 (2004/06/07) セパレータ付きの追加メソッドに変更
	 *
	 * @param	onClick	onClickイベント(例:onClick="renew('query.jsp','QUERY');")
	 */
	public void setOnClick( final String onClick ) {
		add( "onClick",getRequestParameter( onClick ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onChange を設定します(例:onChange="renew('query.jsp','QUERY');")。
	 *
	 * @og.tag
	 * onChange をセットします。
	 * 例えば、&lt;og:column name="KBSAKU" onChange="renew('query.jsp','QUERY');" /&gt;
	 * のように指定することで、プルダウンメニューの絞込み検索が可能になります。
	 *
	 * @og.rev 3.5.0.0 (2003/09/17) 新規追加
	 * @og.rev 3.5.5.9 (2004/06/07) セパレータ付きの追加メソッドに変更
	 *
	 * @param   onChange	onChangeイベント(例:onChange="renew('query.jsp','QUERY');")
	 */
	public void setOnChange( final String onChange ) {
		add( "onChange",getRequestParameter( onChange ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onBlur を設定します(例:onBlur="this.value=value.toUpperCase();")。
	 *
	 * @og.tag
	 * onBlur は、フォーカスが離れたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onBlur	onBlurイベント(例:onBlur="this.value=value.toUpperCase();")
	 */
	public void setOnBlur( final String onBlur ) {
		add( "onBlur",getRequestParameter( onBlur ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onFocus を設定します。
	 *
	 * @og.tag
	 * onFocus は、フォーカスされたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onFocus	onFocusイベント
	 */
	public void setOnFocus( final String onFocus ) {
		add( "onFocus",getRequestParameter( onFocus ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onSelect を設定します。
	 *
	 * @og.tag
	 * onSelect は、テキストフィールド/テキストエリアのテキストが
	 * 選択されたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onSelect	onSelectイベント
	 */
	public void setOnSelect( final String onSelect ) {
		add( "onSelect",getRequestParameter( onSelect ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント ondblClick を設定します。
	 *
	 * @og.tag
	 * ondblClick は、マウスでダブルクリックされたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   ondblClick	ondblClickイベント
	 */
	public void setOndblClick( final String ondblClick ) {
		add( "ondblClick",getRequestParameter( ondblClick ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onMouseDown を設定します。
	 *
	 * @og.tag
	 * onMouseDown は、マウスダウンされたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onMouseDown	onMouseDownイベント
	 */
	public void setOnMouseDown( final String onMouseDown ) {
		add( "onMouseDown",getRequestParameter( onMouseDown ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onMouseUp を設定します。
	 *
	 * @og.tag
	 * onMouseUp は、マウスアップされたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onMouseUp	onMouseUpイベント
	 */
	public void setOnMouseUp( final String onMouseUp ) {
		add( "onMouseUp",getRequestParameter( onMouseUp ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onMouseMove を設定します。
	 *
	 * @og.tag
	 * onMouseMove は、マウスが移動されたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onMouseMove	onMouseMoveイベント
	 */
	public void setOnMouseMove( final String onMouseMove ) {
		add( "onMouseMove",getRequestParameter( onMouseMove ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onMouseOut を設定します。
	 *
	 * @og.tag
	 * onMouseOut は、マウスが離れたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onMouseOut	onMouseOutイベント
	 */
	public void setOnMouseOut( final String onMouseOut ) {
		add( "onMouseOut",getRequestParameter( onMouseOut ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onMouseOver を設定します。
	 *
	 * @og.tag
	 * onMouseOver は、マウスが重なったときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onMouseOver	onMouseOverイベント
	 */
	public void setOnMouseOver( final String onMouseOver ) {
		add( "onMouseOver",getRequestParameter( onMouseOver ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onKeydown を設定します。
	 *
	 * @og.tag
	 * onKeydown は、キーが押されたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onKeydown	onKeydownイベント
	 */
	public void setOnKeydown( final String onKeydown ) {
		add( "onKeydown",getRequestParameter( onKeydown ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onKeypress を設定します。
	 *
	 * @og.tag
	 * onKeypress は、キーが押され続けていたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onKeypress	onKeypressイベント
	 */
	public void setOnKeypress( final String onKeypress ) {
		add( "onKeypress",getRequestParameter( onKeypress ),";" );
	}

	/**
	 * 【HTML】JavaScriptのイベント onKeyup を設定します。
	 *
	 * @og.tag
	 * onKeyup は、キーが押された状態から離されたときに発生するイベントです。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   onKeyup	onKeyupイベント
	 */
	public void setOnKeyup( final String onKeyup ) {
		add( "onKeyup",getRequestParameter( onKeyup ),";" );
	}

	/**
	 * 【TAG】ロールをセットします。
	 *
	 * @og.tag
	 * ここで指定したカラムロールを元に、ユーザー毎のアクセス許可がチェックされます。
	 * アクセス許可されないと、表示されません。
	 * このロールを指定しない場合は、カラムリソースのロールが使用されます。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param	roles ロール
	 */
	public void setRoles( final String roles ) {
		set( "roles",getRequestParameter( roles ) );
	}

	/**
	 * 【TAG】必須入力を表す色に変えるかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * 初期値は、必須でない("false") です。
	 *
	 * &lt;og:input name="PN" must="true" /&gt;
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) 新規追加
	 *
	 * @param	flag	必須入力色に変えるかどうか[true:必須入力/それ以外:必須でない]
	 */
	public void setMust( final String flag ) {
		mustType = nval( getRequestParameter( flag ),null );
		if( "true".equalsIgnoreCase( mustType ) ) {
			mustType = "must";
			add( "class","must" );
		}
	}

	/**
	 * 【TAG】選択必須入力(どれかひとつ必須)を表す色[true/mustAny/その他]を指定します(初期値:無指定)。
	 *
	 * @og.tag
	 * 複数のカラムのうち、どれかひとつを必須とする選択必須入力を示す色を指定します。
	 * true または、mustAny を設定すると、class属性に、mustAny がセットされます。
	 * mustAny は、CSSファイルに初期設定されています。true または、mustAny 以外の値をセット
	 * すると、その値がそのまま、class属性にセットされますので、選択必須のグループ化が
	 * 可能です。
	 * なお、実際の選択必須入力チェックは、ここではなく、columnCheck タグで指定が必要です。
	 * 自動処理は、mustAny="true" 指定の場合のみ有効です。
	 * 初期値は、無指定です。
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) 新規追加
	 *
	 * @param	flag 選択必須入の指定[true/mustAny/その他]
	 */
	public void setMustAny( final String flag ) {
		if( mustType == null ) {	// must 属性と同時設定時には、must 属性を優先します。
			mustType = nval( getRequestParameter( flag ),null );
			if( "true".equalsIgnoreCase( mustType ) ) {
				mustType = "mustAny";
			}
			add( "class",mustType );	// mustType == null の場合は、add されません。
		}
	}

	/**
	 * mustType 属性を取得します。
	 *
	 * must , mustAny 属性を設定する場合に、mustType 属性を設定します。
	 * その設定された値を取り出します。
	 * 何も設定されていない状態では、null を返します。
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) 新規追加。
	 *
	 * @return	mustType属性
	 */
	protected String getMustType() {
		return mustType ;
	}

	/**
	 * must , mustAny 属性を自動化するためのhiddenタグを生成します。
	 *
	 * HybsSystem.MUST_KEY + mustType をキーに、指定のカラム名を値として
	 * hidden を作成します。この値を columnChack タグで拾って must 処理します。
	 * なお、must , mustAny 属性を使用していない場合は、null を返します。
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) 新規追加。
	 *
	 * @param	name	must指定するカラム等の名称
	 *
	 * @return	自動化するためのhiddenタグ
	 */
	protected String makeMustHidden( final String name ) {
		String rtn = null;
		if( mustType != null ) {
			rtn = XHTMLTag.hidden( HybsSystem.MUST_KEY + mustType, name );
		}
		return rtn;
	}
}
