/*
 * 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.html.ViewCrossTableParam;

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

// import java.io.ObjectOutputStream;
// import java.io.ObjectInputStream;
// import java.io.IOException;

/**
 * viewタグの viewFormType が HTMLCrossTable の場合にパラメータを設定します。
 *
 * クロス集計を行う、ViewForm_HTMLCrossTable クラスに対して、各種パラメータを
 * 設定します。
 * パラメータが設定されていない場合は、ViewCrossTableParam の初期値が使用されます。
 * (パラメータを使用するには、viewタグのuseParam 属性をtrueに設定する必要があります。)
 *
 * SELECT文は、CROSS集計機能を利用して求めます。そのときのフォーマットは、
 * ヘッダー1..N,縦,横,計1..N になります。
 * ヘッダー部は、複数指定できますが、デフォルトではヘッダーNがキーブレイクすると
 * 合計用のヘッダーが挿入されます。また、ヘッダーは、前段と同じ値の場合は、表示しません。
 * 合計は、複数並べることができますが、sumNumber で指定しておく必要があります。
 *
 * 各属性は、{&#064;XXXX} 変数が使用できます。
 * これは、ServletRequest から、XXXX をキーに値を取り出し,この変数に割り当てます。
 * つまり、このXXXXをキーにリクエストすれば、この変数に値をセットすることができます。
 *
 * http://localhost/query.jsp?KEY1=VLA1&amp;KEY2=VAL2
 *
 * のようなリクエストで、{&#064;KEY1} とすれば、 VAL1 がセットされます。
 *
 * @og.formSample
 * ●形式：&lt;og:crossParam breakColumn="ZZZ" noGroupColumns="AAA,BBB" sumNumber="2" /&gt;
 * ●body：なし
 *
 * ●Tag定義：
 *   &lt;og:crossParam
 *       cubeXColumn        【TAG】CUBE計算の１つ目(X)カラムを指定します
 *       cubeYColumn        【TAG】CUBE計算の２つ目(Y)カラムを指定します
 *       sumNumber          【TAG】合計値のカラム数を設定します
 *       breakColumn        【TAG】ブレークによりヘッダー部を出力させるカラム名をセットします(初期値:ヘッダーN)
 *       noGroupColumns     【TAG】カラム値を前段と比較して同じ場合でも表示させるカラム名をセットします
 *       shokeiLabel        【TAG】列小計のカラムに表示するラベルIDを指定します(初期値:空文字列)
 *       gokeiLabel         【TAG】列合計のカラムに表示するラベルIDを指定します(初期値:空文字列)
 *       cubeSortType       【TAG】CUBE Y の列ヘッダーのソート方式を指定します(初期値:LOAD)
 *       gokeiSortDir       【TAG】合計行のソート有無とその方向[true:正方向/false:逆方向/null:ソートしない]を指定します(初期値:null)
 *       useHeaderColumn    【TAG】ヘッダーカラムにレンデラー、エディターを適用するかを指定します(初期値:false)
 *       useClassAdd        【TAG】各列情報のclass属性に、カラム名などを付与するかどうかを指定します(初期値:false)
 *       firstClmGokei      【TAG】合計列をCUBEの先頭部分に出すかどうか[true/false]を指定します(初期値:false)
 *       saveTableId        【TAG】クロス集計結果の DBTableModel をセーブするセッションキーワードを指定します
 *       saveScope          【TAG】クロス集計結果の DBTableModel をセーブする scope を指定します
 *       useHeaderResource  【TAG】ヘッダー表示にラベルリソースを適用するかどうかを指定します(初期値:false)
 *       headerCodeColumn   【TAG】ヘッダー表示に利用するコードを持つカラムを指定します(初期値:空文字列)
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   /&gt;
 *
 * ●使用例
 *     ViewFormTag の viewFormType が、HTMLCrossTable の場合に使用します。
 *     useParam 属性を設定しておかないと、使用されません。
 *     &lt;og:view
 *         viewFormType = &quot;HTMLCrossTable&quot;
 *         command      = &quot;{&#064;command}&quot;
 *         startNo      = &quot;0&quot;
 *         pageSize     = &quot;20&quot;
 *         <b>useParam     = &quot;true&quot;</b>
 *     &gt;
 *         &lt;og:crossParam
 *             breakColumn    = "ZZZ"       : ブレークによりヘッダー部を出力させるカラム名
 *             noGroupColumns = "AAA,BBB"   : カラム値を前段と比較して同じ場合でも表示させるカラム名
 *             cubeXColumn    = "CUBE_X"    : CUBE計算の１つ目(X)カラムを指定
 *             cubeYColumn    = "CUBE_Y"    : CUBE計算の２つ目(Y)カラムを指定
 *             shokeiLabel    = "SHOKEI"    : 列小計のカラムに表示するラベルID(初期値:SHOKEI)
 *             gokeiLabel     = "GOKEI"     : 列合計のカラムに表示するラベルID(初期値:GOKEI)
 *             sumNumber      = "2"         : 合計値のカラム数(初期値１)
 *             cubeSortType   = "NUMBER"    : CUBE Y の列ヘッダーのソート方式を指定[STRING/NUMBER/LOAD]
 *             gokeiSortDir   = "false"     : 合計行のソート有無とその方向(正方向/逆方向)を指定[true/false/null]
 *             firstClmGokei  = "true"      : 合計列をCUBEの先頭部分に出すかどうかを指定[false/true/null]
 *             useHeaderColumn= "true"      : ヘッダーカラムにレンデラー、エディターを適用するかどうかを指定[false/true/null]
 *             saveTableId    = "DEFAULT"   : クロス集計結果の DBTableModel をセーブするセッションキーワードを指定
 *             useClassAdd    = "true"      : String 各列情報のclass属性に、カラム名などを付与するかどうかを指定[false/true/null]
 *        /&gt;
 *     &lt;/og:view &gt;
 *
 * @og.group 画面表示
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
// public class ViewCrossParamTag extends ViewParamTag {
public class ViewCrossParamTag extends ViewParamImpl {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.2.0 (2016/01/29)" ;
	private static final long serialVersionUID = 642020160129L ;

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

	/**
	 * 【TAG】ブレークによりヘッダー部を出力させるカラム名をセットします(初期値:ヘッダーN)。
	 *
	 * @og.tag
	 * CROSS集計で求めたフォーマットは、『ヘッダー1..N,縦,横,計1..N 』です。
	 * ヘッダー部は、複数指定できますが、デフォルトではヘッダーNがキーブレイクすると
	 * 合計用のヘッダーが挿入されます。
	 * このヘッダーNそのものが、集計フィールドでなく、単なる属性の場合は、
	 * キーブレイクして欲しくない為、breakColumn="ヘッダーN-1" を指定します。
	 * 初期値は、"ヘッダーN" です。
	 *
	 * @param	clm ブレークカラム
	 */
	public void setBreakColumn( final String clm ) {
		putParam( ViewCrossTableParam.BREAK_COLUMN_KEY,
				  nval( getRequestParameter( clm ),null ) );
	}

	/**
	 * 【TAG】カラム値を前段と比較して同じ場合でも表示させるカラム名をセットします。
	 *
	 * @og.tag
	 * CROSS集計で求めたフォーマットは、『ヘッダー1..N,縦,横,計1..N 』です。
	 * ヘッダー部は、キーブレイクする都度、ヘッダーを出力します。それまでは、
	 * 各ヘッダーの値が、前段(同一カラムの先の値)と同じ場合は、空白にします。
	 * こうする事で、値のグループ化が一目で判ります。(初期設定)
	 * このヘッダーが、集計フィールドでなく、単なる属性の場合は、
	 * 空白ではなく、値として表示したい為、グループ化しない事を指定します。
	 *
	 * @param	clms 非グループ化カラム (CSV形式)
	 */
	public void setNoGroupColumns( final String clms ) {
		putParam( ViewCrossTableParam.NO_GROUP_COLUMNS_KEY,
				  nval( getRequestParameter( clms ),null ) );
	}

	/**
	 * 【TAG】合計値のカラム数を設定します(初期値:１)。
	 *
	 * @og.tag
	 * CROSS集計で求めたフォーマットは、『ヘッダー1..N,縦,横,計1..N 』です。
	 *  合計は、複数並べることができますが、sumNumber で指定しておく必要があります。
	 * 初期値は、1 です。
	 *
	 * @param	no 合計値カラム数 (初期値１)
	 */
	public void setSumNumber( final String no ) {
		putParam( ViewCrossTableParam.SUM_NUMBER_KEY,
				  nval( getRequestParameter( no ),"1" ) );
	}

	/**
	 * 【TAG】列小計のカラムに表示するラベルIDを指定します(初期値:空文字列)。
	 *
	 * @og.tag
	 * 各列の小計のラベルIDを登録します。登録する文字列は、ラベルリソースに
	 * 定義しておいて下さい。
	 * 初期値は、空文字列("")です。
	 *
	 * @og.rev 3.7.1.1 (2005/05/31) 初期値を "SHOKEI" に設定します。
	 *
	 * @param	id 小計ラベルID
	 */
	public void setShokeiLabel( final String id ) {
		final String label = nval( getRequestParameter( id ),"SHOKEI" );
		putParam( ViewCrossTableParam.SHOKEI_LABEL_KEY, getLabel( label ) );
	}

	/**
	 * 【TAG】列合計のカラムに表示するラベルIDを指定します(初期値:空文字列)。
	 *
	 * @og.tag
	 * 各列の合計のラベルIDを登録します。登録する文字列は、ラベルリソースに
	 * 定義しておいて下さい。
	 * 初期値は、空文字列("")です。
	 *
	 * @og.rev 3.7.1.1 (2005/05/31) 初期値を "GOKEI" に設定します。
	 *
	 * @param	id 合計ラベルID
	 */
	public void setGokeiLabel( final String id ) {
		final String label = nval( getRequestParameter( id ),"GOKEI" );
		putParam( ViewCrossTableParam.GOKEI_LABEL_KEY, getLabel( label ) );
	}

	/**
	 * 【TAG】CUBE計算の１つ目(X)カラムを指定します。
	 *
	 * @og.tag
	 * 列方向のキーとなるカラム名を指定します。
	 * 初期値は、互換性の関係より、sumNumber より逆計算します。
	 *
	 * @og.rev 3.5.5.9 (2004/06/07) 新規追加
	 *
	 * @param	cubeX 列(X)ラベルID
	 */
	public void setCubeXColumn( final String cubeX ) {
		putParam( ViewCrossTableParam.CUBE_X_COLUMN_KEY,
				  nval( getRequestParameter( cubeX ),null ) );
	}

	/**
	 * 【TAG】CUBE計算の２つ目(Y)カラムを指定します。
	 *
	 * @og.tag
	 * 行方向のキーとなるカラム名を指定します。
	 * 初期値は、互換性の関係より、sumNumber より逆計算します。
	 *
	 * @og.rev 3.5.5.9 (2004/06/07) 新規追加
	 *
	 * @param	cubeY 行(Y)ラベルID
	 */
	public void setCubeYColumn( final String cubeY ) {
		putParam( ViewCrossTableParam.CUBE_Y_COLUMN_KEY,
				  nval( getRequestParameter( cubeY ),null ) );
	}

	/**
	 * 【TAG】CUBE Y の列ヘッダーのソート方式を指定します(初期値:LOAD)。
	 *
	 * @og.tag
	 * CUBEのヘッダーに対応するカラム列をソート表示する場合の方式を指定します。
	 * 種類として、[STRING/NUMBER/LOAD] があります。
	 * 初期値(指定無し)は、LOAD(取り込み順にセット)です。
	 *
	 * @og.rev 3.5.6.3 (2004/07/12) 新規追加
	 *
	 * @param	cubeSortType 列ヘッダーソート方式 [STRING/NUMBER/LOAD]
	 */
	public void setCubeSortType( final String cubeSortType ) {
		putParam( ViewCrossTableParam.CUBE_SORT_TYPE_KEY,
				  nval( getRequestParameter( cubeSortType ),null ) );
	}

	/**
	 * 【TAG】合計行のソート有無とその方向[true:正方向/false:逆方向/null:ソートしない]を指定します(初期値:null)。
	 *
	 * @og.tag
	 * 最も最後の合計カラムにソートを行うかどうか、その時の方向を指定します。
	 * true/false 以外の文字列では、ソートを行いません。trueは、正方向(昇順)で、
	 * falseが逆方向(降順)になります。
	 * 初期値(指定無し)は、ソートしない(null)です。
	 *
	 * @og.rev 3.5.6.3 (2004/07/12) 新規追加
	 *
	 * @param	gokeiSortDir 合計行ソート処理 [true:正方向/false:逆方向/null:ソートしない]
	 */
	public void setGokeiSortDir( final String gokeiSortDir ) {
		putParam( ViewCrossTableParam.GOKEI_SORT_DIR_KEY,
				  nval( getRequestParameter( gokeiSortDir ),null ) );
	}

	/**
	 * 【TAG】合計列をCUBEの先頭部分に出すかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * 合計列を最終列に出力するか、CUBEの先頭列に出力するかを指定します。
	 * trueが指定された場合はCUBEの先頭列に出力します。
	 * 初期値(false)は合計列を最終列に出力します。
	 *
	 * @og.rev 5.0.0.3 (2009/09/22) 新規追加
	 *
	 * @param	firstClmGokei	合計列の出力場所 [true:先頭列に出力/false:最終列に出力]
	 */
	public void setFirstClmGokei( final String firstClmGokei ) {
		putParam( ViewCrossTableParam.FIRST_CLM_GOKEI_KEY,
				  nval( getRequestParameter( firstClmGokei ),"false" ) );
	}

	/**
	 * 【TAG】ヘッダーカラムにレンデラー、エディターを適用するかを指定します(初期値:false)。
	 *
	 * @og.tag
	 * ヘッダーカラムにレンデラー、エディターを適用するかを指定します。
	 * trueが指定された場合は、ヘッダー部分の値そのものをカラム名として扱います。
	 * リソースが存在しない場合は、ラベルのみを各カラムの値で置き換えます。
	 * 初期値(指定無し)は、レンデラー、エディターを適用しない(false)です。
	 *
	 * @og.rev 4.0.0.0 (2007/11/27) 新規追加
	 * @og.rev 5.2.2.0 (2010/11/01) キーに、ViewCrossTableParam.USE_HEADER_COLUMN を使用するように修正
	 *
	 * @param	useHeaderColumn	適用可否 [true:適用する/false:適用しない]
	 */
	public void setUseHeaderColumn( final String useHeaderColumn ) {
		putParam( ViewCrossTableParam.USE_HEADER_COLUMN,
				  nval( getRequestParameter( useHeaderColumn ),"false" ) );
	}

	/**
	 * 【TAG】各列情報のclass属性に、カラム名などを付与するかどうかを指定します(初期値:false)。
	 *
	 * @og.tag
	 * 列情報の集計列に対して、class 属性を付与するかどうかを指定します。
	 * class属性は、その列のオリジナルの属性名と、ラベル名の文字列を設定します。
	 * 例えば、集計行の計カラムが複数ある場合は、それぞれに色を指定して、ゼブラ模様を
	 * 設定できます。また、ラベル(表示ヘッダー)も設定されるので、特別な列のみ指定することも
	 * 可能になります。
	 * ※ 特殊対応：cssなどで指定できるIDやCLASS属性は、先頭文字が数字の場合は、
	 * 無効になります。(つまり、効きません。)
	 * 表示ヘッダーは、年月や、社員番号(数字)などのケースもあります。そこで、先頭が数字の
	 * 場合は、"x"(小文字のx)を自動的に頭に追加します。この処理は、ViewForm_HTMLCrossTable
	 * で行います。
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
	 *
	 * @param	useClassAdd	付与するかどうか [true:する/false:しない]
	 */
	public void setUseClassAdd( final String useClassAdd ) {
		putParam( ViewCrossTableParam.USE_CLASS_ADD,
				  nval( getRequestParameter( useClassAdd ),"false" ) );
	}

	/**
	 * 【TAG】クロス集計結果の DBTableModel をセーブするセッションキーワードを指定します。
	 *
	 * @og.tag
	 * 検索のみの場合は、何も設定しません。EXCEL等外部にクロス集計の形で
	 * 取り出したい場合に、設定します。
	 * "DEFAULT" という文字列を指定すると、内部では、HybsSystem.TBL_MDL_KEY が
	 * 設定されます。(DEFAULT という文字列に設定されるわけではありません。)
	 * なお、DEFAULT を使用する場合は、検索結果の DBTbleModel をつぶすことになります
	 * ので、NEXT 等は使えません。DBTableModel のデータを利用した forward 等も
	 * 使用できませんので、十分ご注意ください。
	 * DEFAULT 以外の文字列の場合は、指定した文字列そのものがキーになります。
	 * 他のセッションキーと同じにすると動作が不安定になりますので、使用する場合は、
	 * "CROSS_TABLE_SAVE_KEY" を推奨致します。
	 * 指定しない場合は、セッションにセーブされません。(検索されたまま)
	 * 通常、EXCEL出力等を行う場合は、DBTableModel をセーブする必要がありますが、
	 * scope="session" にセーブすると、PREV,NEXT が使えなくなります。これは、
	 * クロス集計時に元のカラムが表形式の別のカラムに置き換えられるためです。
	 * scope="request" では、エラーは発生しなくなりますが、外部に取り出せなくなります。
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) キーに、ViewCrossTableParam.SAVE_TABLEID_KEY を使用するように修正
	 *
	 * @param	id セッション登録ID
	 */
	public void setSaveTableId( final String id ) {
		String tableId = nval( getRequestParameter( id ),null );
		if( "DEFAULT".equals( tableId ) ) {
			tableId = HybsSystem.TBL_MDL_KEY;
		}
		putParam( ViewCrossTableParam.SAVE_TABLEID_KEY , tableId );
	}

	/**
	 * 【TAG】クロス集計結果の DBTableModel をセーブする scope を指定します。
	 *
	 * @og.tag
	 * スコープは (request,page,session,applicaton) がありますが、request か session が
	 * 通常選択されます。
	 * また、この設定が有効になるには、saveTableId を指定する必要があります。
	 * saveTableId を指定しないと、そもそも書き出されないため、scope は無視されます。
	 *
	 * scope="session" にセーブすると、PREV,NEXT が使えなくなります。これは、
	 * クロス集計時に元のカラムが表形式の別のカラムに置き換えられるためです。
	 * scope="request" では、エラーは発生しなくなりますが、外部に取り出せなくなります。
	 * 何も指定しない場合は、viewタグに指定されたオリジナルのスコープに書き出されます。
	 * そうで無い場合は、指定のスコープに書き出されます。
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
	 *
	 * @param	scope scope指定 [request/page/session/applicaton]
	 * @see		#setSaveTableId( String )
	 */
	public void setSaveScope( final String scope ) {
		putParam( ViewCrossTableParam.SAVE_SCOPE_KEY,
				  nval( getRequestParameter( scope ), null ) );
	}

	/**
	 * 【TAG】ヘッダーカラムにラベルリソースを利用するかを指定します(初期値:false)。
	 *
	 * @og.tag
	 * HTMLCrossTableViewで、ヘッダーカラムの表示にラベルリソースを利用するかどうかを指定します。
	 * trueが指定された場合は、ヘッダー部の値のラベルで表示します。
	 * 初期値(指定無し)は、利用しない(false)です。
	 *
	 * @og.rev 5.5.5.0 (2012/07/28) 新規追加
	 *
	 * @param	useHeaderResource	リソース使用可否 [true:する/false:しない]
	 */
	public void setUseHeaderResource( final String useHeaderResource ) {
		putParam( ViewCrossTableParam.USE_HEADER_RSC,
				  nval( getRequestParameter( useHeaderResource ),"false" ) );
	}

	/**
	 * 【TAG】ヘッダーのラベルに利用するコードリソースを指定します。
	 *
	 * @og.tag
	 * この値を指定すると上部ヘッダーの表示を対象カラムのコードに対応するラベルで表示します。
	 * カラムリソースがMENUや、DBMENUのようにSelectionを返す形である必要があります。
	 * 初期値はnullです。
	 *
	 * @og.rev 5.5.5.0 (2012/07/28) 新規追加
	 *
	 * @param	headerCode コードリソースのキー
	 */
	public void setHeaderCodeColumn( final String headerCode ) {
		putParam( ViewCrossTableParam.HEADER_CODE_KEY,
				  nval( getRequestParameter( headerCode ),null ) );
	}

	/**
	 * タグの名称を、返します。
	 * 自分自身のクラス名より、自動的に取り出せないため、このメソッドをオーバーライドします。
	 *
	 * @og.rev 4.0.0.0 (2005/01/31) 新規追加
	 *
	 * @return  タグの名称
	 * @og.rtnNotNull
	 */
	@Override
	protected String getTagName() {
		return "crossParam" ;
	}

//	/**
//	 * シリアライズ用のカスタムシリアライズ書き込みメソッド。
//	 *
//	 * @og.rev 4.0.0.0 (2006/09/31) 新規追加
//	 * @serialData 一部のオブジェクトは、シリアライズされません。
//	 *
//	 * @param	strm	ObjectOutputStreamオブジェクト
//	 * @throws IOException	入出力エラーが発生した場合
//	 */
//	private void writeObject( final ObjectOutputStream strm ) throws IOException {
//		strm.defaultWriteObject();
//	}

//	/**
//	 * シリアライズ用のカスタムシリアライズ読み込みメソッド
//	 *
//	 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
//	 *
//	 * @og.rev 4.0.0.0 (2006/09/31) 新規追加
//	 * @serialData 一部のオブジェクトは、シリアライズされません。
//	 *
//	 * @param	strm	ObjectInputStreamオブジェクト
//	 * @see #release2()
//	 * @throws IOException	シリアライズに関する入出力エラーが発生した場合
//	 * @throws ClassNotFoundException	クラスを見つけることができなかった場合
//	 */
//	private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
//		strm.defaultReadObject();
//	}
}
