/*********************************************************************
*   All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JKKejbDBABase
*	ソースファイル名：JKKejbDBABase.java
*	作成者			：富士通
*	日付			：2012年05月01日
*＜機能概要＞
*	データベースアクセス共通部品のスーパークラス（契約用）
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2012/05/01	富士通		新規作成
*
**********************************************************************/

package eo.ejb.common.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.fujitsu.futurity.common.JCMTraceLog;
import com.fujitsu.futurity.model.base.CAANJDBCUtil;
import com.fujitsu.futurity.model.base.CAANLog;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;

/**
 * <p>
 * データベースアクセス共通部品のスーパークラスです。<br>
 * メインタイプのDBABaseはこちらのクラスを継承してください。<Br>
 * </p>
 * @author 富士通
 */
public abstract class JKKejbDBABase extends JPCejbDBABase
{
	
	/**
	 * <p>
	 * 新しいJKKejbDBABaseを作成します。
	 * </p>
	 */
	public JKKejbDBABase()
	{
	}

	/**
	 * <p>
	 * 新しいJKKejbDBABaseを作成します。
	 * @param arg0 スキーマ名
	 * </p>
	 */
	public JKKejbDBABase(String arg0)
	{
		super(arg0);
	}

	/**
	 * <p>
	 * カレントレコードの検索処理を行います（１世代前カレント同時取得版）。
	 * </p>
	 * @param inMsg カレントレコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	protected CAANMsg[] findByCurrentSecond(CAANMsg inMsg)
	{
		CAANLog.println(CAANLog.LEVEL_FW, "CALL: JKKejbDBABase#findByCurrentSecond");
		JCMTraceLog.logging("JKKejbDBABase#findByCurrentSecond");

		Connection cnct = null;
		PreparedStatement pstmt = null;
		ResultSet rslt = null;

		try
		{
			// コネクションの取得
			cnct = getConnection(getTableName());

			String[][] selList = getSelectColumnList();
			String[][] keyList = getKeyColumnList();
			String[][] updKeyList = getPrimaryKeyList(inMsg, keyList);

			StringBuffer sql = new StringBuffer();

			// 対象テーブルの全カラムを検索
			sql.append(" select ").append(getSelectColumnListString(selList[1]));
			sql.append(" from ").append(getTableName());

			// カレントレコードを抽出する条件設定
			sql.append(" where rowid in ");
			sql.append(" ( select row_id from ( select rowid as row_id ");
			sql.append(" from ").append(getTableName());
			sql.append(" where ").append(getWhereKeyColumnListString(updKeyList[1]));

			if (isReserveMgr())
			{
				// 予約を管理するエンティティは予約適用基準日を条件に設定
				sql.append(" and ").append(getCurrentColumn()).append("<=?");
			}

			if (isReserveStateMgr())
			{
				// 予約状態を管理するエンティティは予約状態を条件に設定
				sql.append(" and ").append(getReserveStateColumn()).append("='2'");
			}

			sql.append(" and ").append(getInvalidColumn()).append("='0'");
			sql.append(" order by ");

			if (isReserveMgr())
			{
				sql.append(getCurrentColumn()).append(" desc,");
			}

			sql.append(getGenerationColumn()).append(" desc)");
			sql.append(" where rownum between 1 and 2 )");
			sql.append(" order by ");
			
			if (isReserveMgr())
			{
				sql.append(getCurrentColumn()).append(" desc,");
			}
			
			sql.append(getGenerationColumn()).append(" desc");

			CAANLog.println(CAANLog.LEVEL_FW, "sql = [" + sql + "]");
			pstmt = cnct.prepareStatement(sql.toString());

			// 検索条件設定
			setParameters(pstmt, 0, updKeyList[0], inMsg);

			if (isReserveMgr())
			{
				// カレント判定項目の検索値設定
				CAANJDBCUtil.setParam(pstmt, updKeyList[0].length + 1, inMsg.getString(getCurrentColumn()));
			}

			// SQLの実行
			rslt = pstmt.executeQuery();

			// ResultSetの値をメッセージキャリアに転記
			return mapMessageList(rslt, selList[0], getSchemaName(), 0);
 
		}
		catch (SQLException e)
		{
			throw new CAANRuntimeException(e);
		}
		finally
		{
			// このメソッドで確保した資源の解放
			try
			{
				if (rslt != null)
				{
					rslt.close();
				}
				if (pstmt != null)
				{
					pstmt.close();
				}
				if (cnct != null)
				{
					closeConnection(cnct);
				}
			}
			catch (SQLException e)
			{
				throw new CAANRuntimeException(e);
			}
		}
	}

	/**
	 * <p>
	 * エンティティのプライマリキーのリストを取得します。<br>
	 * プライマリキーに世代管理カラム名が存在する場合は、リストには含めません。
	 * </p>
	 * @param inMsg エンティティの情報を格納したメッセージキャリア
	 * @param keyList プライマリキー項目のスキーマ項目名とDBカラム名のリスト
	 * @return プライマリキーとなるリスト
	 */
	private String[][] getPrimaryKeyList(CAANMsg inMsg, String[][] keyList)
	{
		ArrayList<String> msgList = new ArrayList<String>(keyList.length);
		ArrayList<String> dbList = new ArrayList<String>(keyList.length);

		for (int i = 0; i < keyList[0].length; i++)
		{
			if (keyList[0][i].equals(getGenerationColumn()))
			{
				continue;
			}

			if (keyList[0][i].equals(getCurrentColumn()))
			{
				continue;
			}

			if (inMsg.containsKeyOfMsgData(keyList[0][i]))
			{
				msgList.add(keyList[0][i]);
				dbList.add(keyList[1][i]);
			}
		}

		String[] msgClm = msgList.toArray(new String[0]);
		String[] dbClm = dbList.toArray(new String[0]);
		return new String[][] { msgClm, dbClm };
	}

	/**
	 * SQL文bufに対して、検索条件マップsearchJknMapで指定された、個別の検索条件を付与します。
	 * @param buf SQL文
	 * @param tableNm テーブル名(SQLで指定する別名)
	 * @param searchJknMap 検索条件マップ(key：項目名、value：項目値リスト)
	 * @param searchJknFlg 検索条件値の指定方法を判別するフラグ<br>
	 *         true：テーブル名.検索項目名 IN (検索項目値リスト)、false：テーブル名.検索項目名 NOT IN (検索項目値リスト)
	 * @return 検索条件を付与したSQL文
	 */
	protected StringBuffer addSearchJknSql(StringBuffer buf, String tableNm,
			HashMap<String, String[]> searchJknMap, boolean searchJknFlg)
	{
		if (searchJknMap == null)
		{
			return buf;
		}
		
		// 検索条件マップが設定されている場合
		for (Map.Entry<String, String[]> searchJkn : searchJknMap.entrySet())
		{
			// 検索項目名
			String key = searchJkn.getKey();
			// 検索項目値リスト
			String[] valList = searchJkn.getValue();
			
			if (valList.length <= 0)
			{
				continue;
			}
			
			if (searchJknFlg)
			{
				// テーブル名.検索項目名 IN (検索項目値リスト)
				buf.append(" AND ").append(tableNm).append(".").append(key).append(" IN ( ");
			}
			else
			{
				// テーブル名.検索項目名 NOT IN (検索項目値リスト)
				buf.append(" AND ").append(tableNm).append(".").append(key).append(" NOT IN ( ");
			}
			
			// 検索項目値リストの値をカンマ区切りで複数指定
			for (int i = 0; i < valList.length; i++)
			{
				if (i > 0)
				{
					buf.append(" , ");
				}
				buf.append(" ? ");
			}
			buf.append(" ) ");
		}
		
		return buf;
	}

	/**
	 * バインド変数設定値リストarraylistに対して、検索条件マップsearchJknMapの検索項目値を設定します。
	 * @param arraylist バインド変数設定値リスト
	 * @param searchJknMap 検索条件マップ(key：項目名、value：項目値リスト)
	 * @return 検索項目値を設定したバインド変数設定値リスト
	 */
	protected ArrayList<Object> addSearchJknParam(ArrayList<Object> arraylist, HashMap<String, String[]> searchJknMap)
	{
		if (searchJknMap == null)
		{
			return arraylist;
		}
		
		// 検索条件マップが設定されている場合
		for (Map.Entry<String, String[]> searchJkn : searchJknMap.entrySet())
		{
			// 検索項目値リスト
			String[] valList = searchJkn.getValue();
			for (int i = 0; i < valList.length; i++)
			{
				// バインド変数設定値リストに検索項目値を設定
				arraylist.add(valList[i]);
			}
		}
		
		return arraylist;
	}

	/**
	 * <p>
	 * SQL文buf、バインド変数設定値リストarraylistに対して、検索項目値リストvalListの値を付与します。
	 * </p>
	 * @param buf SQL文
	 * @param arraylist バインド変数設定値リスト
	 * @param valList 検索項目値リスト
	 */
	protected void setSomeSearchVal(StringBuffer buf, ArrayList<Object> arraylist, String[] valList)
	{
		// 検索項目値リストの値をカンマ区切りで複数指定
		for (int i = 0; i < valList.length; i++)
		{
			if (i > 0)
			{
				buf.append(" , ");
			}
			buf.append(" ? ");
			arraylist.add(valList[i]);
		}
	}

}
