/*
 * 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.resource.GUIInfo;
import org.opengion.hayabusa.resource.UserInfo;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.DBColumn;
import org.opengion.hayabusa.db.DBTableModelUtil;

import org.opengion.fukurou.util.ToString;						// 6.1.1.0 (2015/01/17)
import static org.opengion.fukurou.util.StringUtil.nval ;

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

/**
 * 画面リソースのオブジェクトを検索し、DBTableModel にセットするタグです。
 *
 * ファイルの検索結果は、GUIKEY,ADDRESS,REALADDRESS,SEQNO,GROUPS,CLASSIFY,LEVEL,
 * NAME_JA,SNAME,LNAME,ROLES,RWMODE,TARGET,PARAM,KBLINK,DESCRIPTION,DYUPD のカラムを持つ
 * DBTableModel にセット されます。このカラムは、固定です。
 * 並び替え、および、画面リソースの選別(where 条件)は、固定で、指定できません。
 *
 * [カラム名]      検索するオブジェクトの属性は、以下のカラム名で作成されます。(固定)
 *     GUIKEY        画面ID
 *     ADDRESS       実行アドレス
 *     REALADDRESS   実行実アドレス
 *     SEQNO         表示順
 *     GROUPS        メニュグループ
 *     CLASSIFY      メニュ分類
 *     LEVEL         メニュ階層番号
 *     NAME_JA       画面名称
 *     SNAME         画面名称(short)
 *     LNAME         画面名称(long)
 *     ROLES         ロールズ
 *     MODE          アクセスモード列(mr,mw,-r,-w の羅列)
 *     TARGET        ターゲット
 *     PARAM         設定値(パラメータ)
 *     KBLINK        リンク区分
 *     DESCRIPTION   概要説明
 *     DYUPD         更新日時
 *
 * [roles 属性]      画面リソースの選別となる、ROLES 属性
 *
 * @og.formSample
 * ●形式：&lt;og:guiQuery command="…" roles="…" /&gt;
 * ●body：なし
 *
 * ●Tag定義：
 *   &lt;og:guiQuery
 *       roles              【TAG】画面リソースの条件となるロールズを指定します
 *       level              【TAG】画面リソースの条件となるレベルを指定します
 *       rwmode             【TAG】画面リソースの条件となるRWモードを指定します
 *       command            【TAG】コマンド (NEW,RENEW)をセットします(PlsqlUpdateTag,UpdateTag の場合は、ENTRY)
 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:guiQuery&gt;
 *
 * ●使用例
 *         &lt;og:guiQuery
 *                command = "NEW"
 *                roles   = "AA|BB|CC"
 *         /&gt;
 *
 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
 * @og.group その他入力
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class GuiQueryTag extends QueryTag {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "5.3.3.0 (2011/03/01)" ;

	private static final long serialVersionUID = 533020110301L ;

	private static final String[] SELECT =
				new String[] { "GUIKEY","ADDRESS","REALADDRESS","SEQNO","GROUPS","CLASSIFY","LEVEL",
							"NAME_JA","SNAME","LNAME","ROLES","RWMODE","TARGET","PARAM","KBLINK","DESCRIPTION","DYUPD" };

	private static final int GUIKEY      = 0;
	private static final int ADDRESS     = 1;
	private static final int REALADDRESS = 2;
	private static final int SEQNO       = 3;
	private static final int GROUPS      = 4;
	private static final int CLASSIFY    = 5;
	private static final int LEVEL       = 6;
	private static final int NAME_JA     = 7;
	private static final int SNAME       = 8;
	private static final int LNAME       = 9;
	private static final int ROLES       = 10;
	private static final int RWMODE      = 11;
	private static final int TARGET      = 12;
	private static final int PARAM       = 13;
	private static final int KBLINK      = 14;
	private static final int DESCRIPTION = 15;
	private static final int DYUPD       = 16; // 5.3.3.0 (2011/03/01) 更新日時追加

	private String	roles		;
	private String	level		;
	private String	rwmode		;

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * 通常の QueryTagでは、Body を評価する(EVAL_BODY_BUFFERED)を返しますが、
	 * GuiQueryでは BODYを評価しない為、SKIP_BODY を返します。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doStartTag() {
		super.doStartTag();

		// DBTableModel の初期化
		table = initDBTable();

		// 実行
		execute() ;

		return SKIP_BODY ;				// Body を評価しない
	}

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

	/**
	 * guiQuery を実行します。
	 *
	 */
	protected void execute() {
		final UserInfo userInfo = new UserInfo( "XX","ja","DUMMY",roles,null,"GF","127.0.0.1",null );

		getResource().makeGUIInfos( userInfo );

		final GUIInfo[] guiInfos = userInfo.getGUIInfos();

		for( int i=0; i<guiInfos.length; i++ ) {
			addGUIInfo( guiInfos[i] );
		}
		executeCount = table.getRowCount();
	}

	/**
	 * 初期化された DBTableModel を返します。
	 *
	 * @return	テーブルモデル
	 */
	private DBTableModel initDBTable() {
		final DBTableModel tbl = DBTableModelUtil.newDBTable();

		tbl.init( SELECT.length );
		for( int i=0; i<SELECT.length; i++ ) {
			final DBColumn dbColumn = getDBColumn( SELECT[i] );
			tbl.setDBColumn( i,dbColumn );
		}

		return tbl ;
	}

	/**
	 * DBTableModel に、ファイル情報をセットします。
	 * ファイルの検索結果は、GUIKEY,ADDRESS,REALADDRESS,SEQNO,GROUPS,CLASSIFY,LEVEL,
	 * NAME_JA,SNAME,LNAME,ROLES,RWMODE,TARGET,PARAM,KBLINK,DESCRIPTION,DYUPD のカラムを持つ
	 * DBTableModel にセット されます。このカラムは、固定です。
	 *
	 * @og.rev 5.3.3.0 (2011/03/01) 更新日時追加、分類を名称でセット
	 *
	 * @param	guiInfo	セットする画面リソース
	 */
	private void addGUIInfo( final GUIInfo guiInfo ) {
		final String guiLevel = String.valueOf( guiInfo.getLevel() );
		if( level != null && !level.equals( guiLevel ) ) { return; }

		final String guiMode  = guiInfo.getMode();
		if( rwmode != null && guiMode != null && !guiMode.startsWith( rwmode ) ) { return; }

		String[] data = new String[ SELECT.length ];

		data[GUIKEY     ] = guiInfo.getKey();
		data[ADDRESS    ] = guiInfo.getAddress();
		data[REALADDRESS] = guiInfo.getRealAddress();
		data[SEQNO      ] = String.valueOf( guiInfo.getSequence() );
		data[GROUPS     ] = guiInfo.getGroups();
		data[CLASSIFY   ] = getResource().getLabel( guiInfo.getClassify() );
		data[LEVEL      ] = guiLevel;
		data[NAME_JA    ] = guiInfo.getLabel();
		data[SNAME      ] = guiInfo.getName();
		data[LNAME      ] = guiInfo.getLongName();
		data[ROLES      ] = guiInfo.getRoles();
		data[RWMODE     ] = guiMode;
		data[TARGET     ] = guiInfo.getTarget();
		data[PARAM      ] = guiInfo.getParam();
		data[KBLINK     ] = guiInfo.getKblink();
		data[DESCRIPTION] = guiInfo.getDescription();
		data[DYUPD      ] = guiInfo.getDyupd();

		table.addColumnValues( data );
	}

	/**
	 * 【TAG】画面リソースの条件となるロールズを指定します。
	 *
	 * @og.tag
	 * ロールズ判定は、ダミーユーザーを作成して通常の処理と同様の判定方式で
	 * 有効な画面リソースをピックアップします。
	 *
	 * @param	rols	ロールズ
	 */
	public void setRoles( final String rols ) {
		roles = nval( getRequestParameter( rols ),roles );
	}

	/**
	 * 【TAG】画面リソースの条件となるレベルを指定します。
	 *
	 * @og.tag
	 * レベル判定は、文字列レベルの判定を行います。
	 * 画面リソースの階層番号(レベル)は、
	 * 　0:グループ分類メニュー(class="GUI_GRP"のtdタグで囲われます)
	 * 　1:トップ階層(【分類名称】)
	 * 　2:選択階層(通常の折りたたみメニュー)
	 * 　3:選択非表示(通常は、隠してあります)
	 * です。
	 *
	 * ロール等の他の条件でピックアップされたリソースと AND 処理されます。
	 * 何も指定しなければ、すべてを対象とします。
	 *
	 * @param	lvl	ロールズ
	 */
	public void setLevel( final String lvl ) {
		level = nval( getRequestParameter( lvl ),level );
	}

	/**
	 * 【TAG】画面リソースの条件となるRWモードを指定します。
	 *
	 * @og.tag
	 * RWモード判定は、文字列レベルの判定を行います。(通常のRW判定と異なります)
	 * RWモードの代表的な記述は、mw,mr,-w,-r です。ここでは、特殊な検索は出来ないため、
	 * 上記文字列そのままで、一致するか、m,- の前方一致で判断するかのどちらかです。
	 *
	 * ロール等の他の条件でピックアップされたリソースと AND 処理されます。
	 * 何も指定しなければ、すべてを対象とします。
	 *
	 * @param	mode	RWモード
	 */
	public void setRwmode( final String mode ) {
		rwmode = nval( getRequestParameter( mode ),rwmode );
	}

	/**
	 * シリアライズ用のカスタムシリアライズ書き込みメソッド。
	 *
	 * @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();
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"		,VERSION	)
				.println( "roles"		,roles	)
				.fixForm().toString()
			+ CR
			+ super.toString() ;
	}
}
