package common.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import common.db.JdbcSource;
import common.db.jdbc.Jdbc;
import core.exception.ThrowableUtil;

/**
 * DB検索処理クラス
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class SelectorImpl implements Selector {

	/** 取得サイズ */
	private int fetchsize = 100;
	/** 最大レコード */
	private int maxrows = 0;
	/** コネクション */
	private Connection con = null;

	/**
	 * コネクション設定
	 *
	 * @param val コネクション
	 */
	@Override
	public void setConnection(final Connection val) {
		this.con = val;
	}

	/**
	 * 取得サイズ設定
	 *
	 * @param size サイズ
	 */
	@Override
	public void setFetchSize(final int size) {
		if (0 < size) {
			this.fetchsize = size;
		}
	}

	/**
	 * 最大レコード数設定
	 *
	 * @param size レコード数
	 */
	@Override
	public void setMaxRows(final int size) {
		if (0 < size) {
			this.maxrows = size;
		}
	}

	/**
	 * データ検索
	 *
	 * @param sels クエリオブジェクト
	 * @return レコードが存在した場合 true を返す。
	 */
	@Override
	public boolean search(final SelectQuery... sels) {
		if (this.con != null) {
			return search(this.con, sels);
		}

		try (Jdbc conn = JdbcSource.getConnection()) {
			return search(conn, sels);
		}
	}

	/**
	 * 結果セットの取得と格納
	 *
	 * @param conn コネクションオブジェクト
	 * @param sels SelectQueryオブジェクト
	 * @return レコードが存在した場合 true を返す。
	 */
	private boolean search(final Connection conn, final SelectQuery... sels) {
		boolean ret = false;
		if (sels != null) {
			for (final SelectQuery sel : sels) {
				if (search(sel, conn)) {
					ret = true;
				}
			}
		}
		return ret;
	}

	/**
	 * 結果セットの取得と格納
	 *
	 * @param sel SelectQueryオブジェクト
	 * @param conn コネクションオブジェクト
	 * @return レコードが存在した場合 true を返す。
	 */
	private boolean search(final SelectQuery sel, final Connection conn) {

		try (PreparedStatement psmt = QueryUtil.createStatement(
				sel.makeQuery(), sel.makeParam(), Jdbc.wrap(conn)::readonlyStatement)) {
			if (psmt != null) {
				setStatementParameters(psmt);

				try (ResultSet rs = psmt.executeQuery()) {
					return sel.callback(rs);
				}
			}
			return false;
		} catch (final SQLException ex) {
			ThrowableUtil.warn(ex);
			return false;
		}
	}

	/**
	 * ステートメントパラメタ設定
	 *
	 * @param stmt ステートメント
	 * @throws SQLException SQL例外
	 */
	private void setStatementParameters(final Statement stmt) throws SQLException {
		// フェッチサイズ
		if (0 < this.fetchsize) {
			stmt.setFetchSize(this.fetchsize);
		}
		// 最大レコード
		if (0 < this.maxrows) {
			stmt.setMaxRows(this.maxrows);
		}
	}
}
