/*
 * 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.fukurou.util.ToString;

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

/**
 * IorQueryTag と IorUpdateTag にﾊﾟﾗﾒｰﾀｰを渡す為のﾀｸﾞｸﾗｽです。
 *
 * ｷｰは、SQL文のselect句／where句／group by句／order by句が指定できます。
 * 値は、value 属性で指定するか、なければ BODY 部に記述します。
 *
 * @og.formSample
 * ●形式：
 *     &lt;og:iorParam key="where_lk" value="{'PN':'{&#064;PN}%','TANI':'{&#064;TANI}'}" /&gt;
 *
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:iorParam
 *       key              ○【TAG】ﾊﾟﾗﾒｰﾀとして渡すｷｰ情報を指定します (必須)
 *       value              【TAG】ﾊﾟﾗﾒｰﾀとして渡す設定値を指定します (初期値:null)
 *       quotCheck          【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します (初期値:USE_SQL_INJECTION_CHECK[=true])
 *       xssCheck           【TAG】ﾘｸｴｽﾄ情報の HTMLTag開始/終了文字(&gt;&lt;) 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
 *       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;   ... Body ...
 *   &lt;/og:iorParam&gt;
 *
 * ●使用例
 *     &lt;og:iorQuery
 *         url           = "http://･･･ "
 *         authURL       = "http://･･･ "
 *         authUserPass  = "admin:******"
 *         appliName     = "ﾃﾞｰﾀﾃｰﾌﾞﾙ名"
 *         callMethod    = "getReportInfo"
 *     &gt;
 *         &lt;og:iorParam
 *             key  = "select_cols"  value  = "PN,TANI,count(*) as CNT"  /&gt;
 *         &lt;og:iorParam
 *             key  = "where_lk"     value  = "{'PN':'{&#064;PN}%','TANI':'{&#064;TANI}'}"  /&gt;
 *     &lt;/og:iorQuery&gt;
 *
 * @og.rev 8.0.2.0 (2021/11/30) 新規作成
 * @og.group その他部品
 *
 * @version  8.0
 * @author   LEE.M
 * @since    JDK17.0,
 */
public class IorParamTag extends CommonTagSupport {
	/** このﾌﾟﾛｸﾞﾗﾑのVERSION文字列を設定します。 {@value} */
	private static final String VERSION = "8.0.2.0 (2021/11/30)" ;
	private static final long serialVersionUID = 802020211130L ;

	/** ｷｰ情報 */
	private String	key			;
	/** 設定値 */
	private String	value		;
	/** ｸｵｰﾄﾁｪｯｸ */
	private boolean	quotCheck	= HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );
	/** XSSﾁｪｯｸ */
	private boolean	xssCheck	= HybsSystem.sysBool( "USE_XSS_CHECK" );

	/**
	 * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
	 */
	public IorParamTag() { super(); }	// これも、自動的に呼ばれるが、空のﾒｿｯﾄﾞを作成すると警告されるので、明示的にしておきます。

	/**
	 * Taglibの開始ﾀｸﾞが見つかったときに処理する doStartTag() を ｵｰﾊﾞｰﾗｲﾄﾞします。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doStartTag() {
		if( useTag() ) {
			useQuotCheck( quotCheck );
			useXssCheck( xssCheck );

			value = getRequestParameter( value );

			if( value == null || value.isEmpty() ) {
				return EVAL_BODY_BUFFERED;										// Body を評価する。( extends BodyTagSupport 時)
			}
		}
		return SKIP_BODY;														// Body を評価しない
	}

	/**
	 * Taglibのﾀｸﾞ本体を処理する doAfterBody() を ｵｰﾊﾞｰﾗｲﾄﾞします。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		value = getBodyString();
		return SKIP_BODY;
	}

	/**
	 * Taglibの終了ﾀｸﾞが見つかったときに処理する doEndTag() を ｵｰﾊﾞｰﾗｲﾄﾞします。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();
		if( useTag() ) {
			final IorQueryTag iorQuery = (IorQueryTag)findAncestorWithClass( this,IorQueryTag.class );
			if( iorQuery == null ) {
				final String errMsg = "<b>" + getTagName() + "ﾀｸﾞは、Ior関連Tagの内側(要素)に記述してください。</b>";
				throw new HybsSystemException( errMsg );
			}
			iorQuery.addParam( key, value );
		}
		return EVAL_PAGE;
	}

	/**
	 * ﾀｸﾞﾘﾌﾞｵﾌﾞｼﾞｪｸﾄをﾘﾘｰｽします。
	 * ｷｬｯｼｭされて再利用されるので、ﾌｨｰﾙﾄﾞの初期設定を行います。
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		key			= null;														// ｷｰ情報
		value		= null;														// 設定値
		quotCheck	= HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );			// ｸｵｰﾄﾁｪｯｸ
		xssCheck	= HybsSystem.sysBool( "USE_XSS_CHECK" );					// XSSﾁｪｯｸ
	}

	/**
	 * 【TAG】ﾊﾟﾗﾒｰﾀとして渡すｷｰ情報を指定します。
	 *
	 * @og.tag
	 * IorQueryTag と IorUpdateTag に渡すﾊﾟﾗﾒｰﾀのｷｰ情報です。
	 * 値は、value 属性で指定するか、なければ BODY 部に記述します。
	 *
	 * ｷｰは、SQL文のselect句／where句／group by句／order by句が指定できます。
	 *
	 * 処理対象を特定するｶﾗﾑ名(select句)が指定できます。
	 *   SQL文:  select  PN,TANI,count(*) as CNT
	 *   使用文: key="select"  value="PN,TANI,count(*) as CNT"
	 *
	 * 処理対象を特定するｷｰ条件(where句)が指定できます。
	 *   (1) SQL文:  where  PN LIKE 'GEN%'  and  TANI = 'KG'
	 *       使用文: key="where"     value="{'PN':'GEN%','TANI':'KG'}"
	 *   (2) SQL文:  where  DYSET &gt;= '20211101'
	 *       使用文: key="where_ge"  value="{'DYSET':'20211101'}"
	 *   (3) SQL文:  where  DYSET &lt;= '20211101'
	 *       使用文: key="where_le"  value="{'DYSET':'20211101'}"
	 *
	 * 処理対象を特定する集計条件(group by句)が指定できます。
	 *   SQL文:  group by  PN,TANI
	 *   使用文: key="group by"  value="PN,TANI"
	 *
	 * 処理対象の並び替えを指定するｷｰﾜｰﾄﾞ(order by句)が指定できます。
	 *   SQL文:  order by  PN,TANI
	 *   使用文: key="order_by"  value="PN,TANI"
	 *
	 * @param	prmKey	ｷｰ情報
	 */
	public void setKey( final String prmKey ) {
		key = nval( getRequestParameter( prmKey ),key );
		if( key == null ) {
			final String errMsg = "key がｾｯﾄされていません。";
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】ﾊﾟﾗﾒｰﾀとして渡す設定値を指定します(初期値:null)。
	 *
	 * @og.tag
	 * IorQueryTag と IorUpdateTag に渡すﾊﾟﾗﾒｰﾀの設定値です。
	 * 値は、value 属性で指定するか、なければ BODY 部に記述します。
	 * BODY 部に記述された場合は、文字列を trim() します。
	 * 設定値は、value 属性が優先です。ここの値が、null の場合は、
	 * BODY 要素を値として使用します。
	 *
	 * @param	val	設定値
	 * @see		#setKey( String )
	 */
	public void setValue( final String val ) {
		value = nval( getRequestParameter( val ),value );
	}

	/**
	 * 【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
	 *        (初期値:USE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。
	 *
	 * @og.tag
	 * SQLｲﾝｼﾞｪｸｼｮﾝ対策の一つとして、暫定的ではありますが、SQLのﾊﾟﾗﾒｰﾀに
	 * 渡す文字列にｼﾝｸﾞﾙｸｫｰﾄ(') を許さない設定にすれば、ある程度は防止できます。
	 * 数字ﾀｲﾌﾟの引数には、 or 5=5 などのｼﾝｸﾞﾙｸｫｰﾄを使用しないｺｰﾄﾞを埋めても、
	 * 数字ﾁｪｯｸで検出可能です。文字ﾀｲﾌﾟの場合は、必ず (')をはずして、
	 * ' or 'A' like 'A のような形式になる為、(')ﾁｪｯｸだけでも有効です。
	 * (') が含まれていたｴﾗｰにする(true)／かﾉｰﾁｪｯｸか(false)を指定します。
	 * (初期値:ｼｽﾃﾑ定数のUSE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。
	 *
	 * @param	flag ｸｫｰﾄﾁｪｯｸ [true:する/それ以外:しない]
	 * @see		org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK
	 */
	public void setQuotCheck( final String flag ) {
		quotCheck = nval( getRequestParameter( flag ),quotCheck );
	}

	/**
	 * 【TAG】ﾘｸｴｽﾄ情報の HTMLTag開始/終了文字(&gt;&lt;) 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
	 *        (初期値:USE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
	 *
	 * @og.tag
	 * ｸﾛｽｻｲﾄｽｸﾘﾌﾟﾃｨﾝｸﾞ(XSS)対策の一環としてless/greater than signについてのﾁｪｯｸを行います。
	 * (&gt;&lt;) が含まれていたｴﾗｰにする(true)／かﾉｰﾁｪｯｸか(false)を指定します。
	 * (初期値:ｼｽﾃﾑ定数のUSE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
	 *
	 * @param	flag	XSSﾁｪｯｸ [true:する/false:しない]
	 * @see		org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
	 */
	public void setXssCheck( final String flag ) {
		xssCheck = nval( getRequestParameter( flag ),xssCheck );
	}

	/**
	 * このｵﾌﾞｼﾞｪｸﾄの文字列表現を返します。
	 * 基本的にﾃﾞﾊﾞｯｸﾞ目的に使用します。
	 *
	 * @return	このｸﾗｽの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"		,VERSION	)
				.println( "key"			,key		)
				.println( "value"		,value		)
				.println( "quotCheck"	,quotCheck	)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
