#% DAOJavaソースファイル作成用の雛型ファイル
#% 2010/04/19 By S.Ito

#% === DAO =====================================================================
#! dao package
package #package#;

#! header postgreSQL
import org.postgresql.util.PGobject;
import java.util.HashSet;

#! header
#loggerComment#import org.apache.log4j.Logger;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;

/**
 * #nameJp# データベースアクセスクラス（モデル検索用）
 *
 * @author
 *
 */
@SuppressWarnings("serial")
public class #className# extends DaoBase implements RecordSearch, RecordAction, Serializable {

	// ロガー
	#loggerComment#private static Logger logger = Logger.getLogger(#className#.class);

	//	検索キー名称よりテーブルのフィールド名称、パラメータのデータ型を取得するMAP
	private static HashMap<String, FieldInfo> keyName2TableFieldName = new HashMap<String, FieldInfo>();
	static{
#! header put key
		keyName2TableFieldName.put("#keyNmae#", new FieldInfo("#tableFieldName#", #classObject#.class));
#! header 2
	}

	// 検索用SQL
	protected static final String searchSql = "select " //
#! sql search fields
			+ "#fields#" //
#! sql search from
			+ "from #tableName#" //
#! sql search join
			+ "  left join #tableName# on #on#" //
#%#! sql search join;
#%			+ "  left join #tableName# on #on#";
#! sql search list
			;

	// 並び順
	protected String searchOrderSql = "#orderBy#";

	// 検索用のリスト
	private List<#voName#> searchList;

#! sql search postgreSQL
	// ビットフィールドの名前セット
	private static HashSet<String> searchBitMap;
	static{
		searchBitMap = new  HashSet<String>();
#! sql search postgreSQL field
		searchBitMap.add("#fieldNmae#");
#! sql search postgreSQL end
	}

#! constructor
	/**
	 * コンストラクタ<BR>
	 * 単独で使用するとき
	 */
	public #className#() {
		super();
	}

	/**
	 * コンストラクタ<BR>
	 * 複数のDAOを同一トランザクション内で使用するとき
	 *
	 * @param daoTransaction
	 *            DAO用トランザクション
	 */
	public #className#(DaoTransaction daoTransaction) {
		super(daoTransaction);
	}

	/**
	 * #nameJp#検索
	 *
	 * @return 検索された#nameJp#のレコードリスト
	 * @throws SQLException
	 */
	public List<#voName#> search() throws Exception {
		try {
			searchList = new LinkedList<#voName#>();
	
			search(this);
	
			List<#voName#> list = searchList;
			searchList = null;
	
			#loggerComment#logger.debug("select 結果 = "+list.size());
			return list;
		} catch(Exception e) {
			#loggerComment#logger.fatal("データベースへのレコード検索処理でエラーが発生しました", e);
			throw e;
		}
	}

	@Override
	public void initAction() throws Exception{
		//	何もしない
	}

	@Override
	public void action(Object record) throws Exception {
		searchList.add((#voName#) record);
	}

	@Override
	public void closeAction() throws Exception {
		//	何もしない
	}

	/**
	 * #nameJp#検索
	 *
	 * @throws SQLException
	 */
	public void search(RecordAction searchAction) throws Exception {
		try {
			searchAction.initAction();

			try {
				String orderBy = makeSearchOrder();
				String sql = searchSql + makeSearchWhere() + " " + (orderBy.length() > 0 ? orderBy : searchOrderSql);
				#loggerComment#logger.debug(sql);
				#loggerComment#logger.debug(getSearchParam());
				PreparedStatement stmt = prepareStatement(sql);
				setSearchWhere(stmt);

				ResultSet res = null;

				try {
					res = stmt.executeQuery();

					while (res.next()) {

						#voName# rec = new #voName#();

#! search ResultSet String
						rec.#setMethod#(#change#(res.getString("#name#"), res.wasNull()));
#! search ResultSet Int
						rec.#setMethod#(#change#(res.getInt("#name#"), res.wasNull()));
#! search ResultSet Long
						rec.#setMethod#(#change#(res.getLong("#name#"), res.wasNull()));
#! search ResultSet BigDecimal
						rec.#setMethod#(#change#(res.getBigDecimal("#name#"), res.wasNull()));
#! search ResultSet Boolean h2
						rec.#setMethod#(#change#(res.getBoolean("#name#"), res.wasNull()));
#! search ResultSet Boolean oracle
						rec.#setMethod#(#change#(res.getInt("#name#") == 1, res.wasNull()));
#! search ResultSet Date
						rec.#setMethod#(#change#(res.getDate("#name#"), res.wasNull()));
#! search ResultSet Time
						rec.#setMethod#(#change#(res.getTime("#name#"), res.wasNull()));
#! search ResultSet Timestamp
						rec.#setMethod#(#change#(res.getTimestamp("#name#"), res.wasNull()));
#! search ResultSet byte[]
						rec.#setMethod#(#change#(res.getBytes("#name#"), res.wasNull()));
#! search footer

						// レコード毎の処理を呼び出す
						searchAction.action(rec);
					}

				} finally {
					if (res != null) {
						res.close();
					}
				}

			} finally {
				closeConnection();
			}
		} finally {
			searchAction.closeAction();
		}
	}


#! footer postgreSQL
	/**
	 * 検索用SQLのWHERE区の1項目にパラメータ値を設定する
	 *
	 * @param stmt
	 * @param parameterIndex
	 * @param searcKeyValue
	 * @throws SQLException
	 */
	@Override
	protected void setSearchWhere(PreparedStatement stmt, int parameterIndex, SearcKeyValue searcKeyValue) throws SQLException {

		if (!searchBitMap.contains(searcKeyValue.keyName)) {
			super.setSearchWhere(stmt, parameterIndex, searcKeyValue);
			return;
		}

		SearcKeyValue bitKeyValue = new SearcKeyValue(searcKeyValue.keyName, searcKeyValue.searchMode, changeBitObject(
				(String) searcKeyValue.value, false, ((String) searcKeyValue.value).length()));
		super.setSearchWhere(stmt, parameterIndex, bitKeyValue);
	}

	/**
	 * postgreSQL・bit、varbitフィールドの変換
	 *
	 * @param value
	 *            ビット値（1,0の連続文字列）
	 * @param modeFlag
	 *            true=固定、false=可変
	 * @param length
	 *            最大フィールド長
	 * @return 変換されたオブジェクト
	 * @throws SQLException
	 */
	protected static PGobject changeBitObject(String value, boolean modeFlag, int length) throws SQLException {

		if (value == null) {
			value = "";
		}

		StringBuilder sb = new StringBuilder();
		int valueLength = value.length();

		for (int i = 0; i < length; i++) {
			if (i < valueLength) {
				char c = value.charAt(i);
				if (c == '1') {
					sb.append(c);
				} else {
					sb.append('0');
				}
			} else {
				if (modeFlag) {
					sb.append('0');
				} else {
					break;
				}
			}
		}

		PGobject object = new PGobject();
		object.setType("bit");
		object.setValue(sb.toString());

		return object;
	}

#! footer
	/**
	 * 検索用パラメータを追加する
	 *
	 * @param keyNmae
	 * @param mode
	 * @param value
	 */
	@Override
	public void addSearchParameter(String keyName, int mode, Object value) {

		String keyNameLow = keyName.toLowerCase();
		if(!keyName2TableFieldName.containsKey(keyNameLow)){
			throw new RuntimeException("検索キーとして指定されたフィールド名が見つかりません " + keyName);
		}

		FieldInfo fieldInfo = keyName2TableFieldName.get(keyNameLow);
		super.addSearchParameter(fieldInfo.getName(), mode, changeObject(value, fieldInfo.getClassObject()));
	}

	/**
	 * ソート昇順パラメータを追加する
	 *
	 * @param fieldName フィールド名
	 */
	@Override
	public void addSortAscParameter(String fieldName) {

		String fieldNameLow = fieldName.toLowerCase();
		if(!keyName2TableFieldName.containsKey(fieldNameLow)){
			throw new RuntimeException("昇順ソートに指定されたフィールド名が見つかりません " + fieldNameLow);
		}

		FieldInfo fieldInfo = keyName2TableFieldName.get(fieldNameLow);
		super.addSortAscParameter(fieldInfo.getName());
	}

	/**
	 * ソート降順パラメータを追加する
	 *
	 * @param fieldName フィールド名
	 */
	@Override
	public void addSortDescParameter(String fieldName) {
		String fieldNameLow = fieldName.toLowerCase();
		if(!keyName2TableFieldName.containsKey(fieldNameLow)){
			throw new RuntimeException("降順ソートに指定されたフィールド名が見つかりません " + fieldNameLow);
		}

		FieldInfo fieldInfo = keyName2TableFieldName.get(fieldNameLow);
		super.addSortDescParameter(fieldInfo.getName());
	}

	/**
	 * フィールド情報クラス
	 */
	static class FieldInfo {
		private String name;
		private Class<?> classObject;

		public FieldInfo(String name, Class<?> classObject) {
			this.name = name;
			this.classObject = classObject;
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @return the classObject
		 */
		public Class<?> getClassObject() {
			return classObject;
		}
	}
}
