/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * 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 woolpack.samples.gcrud;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import woolpack.fn.Fn;
import woolpack.sql.fn.PreparedStatementInfo;
import woolpack.sql.fn.SqlFnUtils;
import woolpack.sql.meta.SqlMetaUtils;
import woolpack.sql.meta.TableInfo;
import woolpack.sql.meta.TableInfoUtils;

/**
 * DB のメタ情報を利用して RDB にアクセスする CRUD 関数を生成するビルダです。
 * 生成する{@link Fn}の引数の内"tableName"をテーブル特定のために使用します。
 * @author nakamura
 *
 */
public class GcrudManager {
	private DataSource dataSource;
	private List<TableInfo> tableInfoList;
	private Map<String, TableInfo> tableInfoMap;
	
	public GcrudManager() {
	}
	public DataSource getDataSource() {
		return dataSource;
	}
	public void setDataSource(final DataSource dataSource) {
		this.dataSource = dataSource;
	}
	public List<TableInfo> getTableInfoList() {
		return tableInfoList;
	}
	public void setTableInfoList(final List<TableInfo> tableInfoList) {
		this.tableInfoList = tableInfoList;
	}
	public Map<String, TableInfo> getTableInfoMap() {
		return tableInfoMap;
	}
	
	private TableInfo getTableInfo(final Map<String, Object> c) {
		final TableInfo info = tableInfoMap.get(c.get("tableName"));
		info.getClass();
		return info;
	}
	
	private Fn<Map<String, Object>, PreparedStatementInfo> getFactory(
			final Fn<TableInfo, Fn<Collection<String>, PreparedStatementInfo>> factoryFactory) {
		return new Fn<Map<String, Object>, PreparedStatementInfo>() {
			public PreparedStatementInfo exec(final Map<String, Object> c) {
				return factoryFactory.exec(getTableInfo(c)).exec(c.keySet());
			}
		};
	}
	
	/**
	 * {@link TableInfoUtils#convertToMap(List)}を呼び出しその結果を保持します。
	 *
	 */
	public void init() {
		tableInfoMap = TableInfoUtils.convertToMap(tableInfoList);
	}
	
	/**
	 * ひとつのテーブルを検索してレコードの一覧を返す{@link Fn}を生成します。
	 * @return ひとつのテーブルを検索してレコードの一覧を返す{@link Fn}。
	 */
	public Fn<Map<String, Object>, List<Map<String, Object>>> createSelectListFn() {
		return SqlFnUtils.inputMap(
				dataSource,
				getFactory(SqlMetaUtils.SELECT_FACTORY_FACTORY),
				SqlFnUtils.getList(SqlFnUtils.getMapResult()));
	}
	
	/**
	 * ひとつのテーブルを検索してレコードの情報を返す{@link Fn}を生成します。
	 * @return ひとつのテーブルを検索してレコードの情報を返す{@link Fn}。
	 */
	public Fn<Map<String, Object>, Map<String, Object>> createSelectOneFn() {
		return SqlFnUtils.inputMap(
				dataSource,
				getFactory(SqlMetaUtils.SELECT_FACTORY_FACTORY),
				SqlFnUtils.getOne(SqlFnUtils.getMapResult()));
		
	}
	
	/**
	 * レコードを登録する{@link Fn}を生成します。
	 * @return レコードを登録する{@link Fn}。
	 */
	public Fn<Map<String, Object>, Integer> createInsertFn() {
		return SqlFnUtils.inputMap(
			dataSource,
			getFactory(SqlMetaUtils.INSERT_FACTORY_FACTORY),
			SqlFnUtils.GET_COUNT);
	}
	
	/**
	 * レコードを更新する{@link Fn}を生成します。
	 * @return レコードを更新する{@link Fn}。
	 */
	public Fn<Map<String, Object>, Integer> createUpdateFn() {
		return SqlFnUtils.inputMap(
			dataSource,
			getFactory(SqlMetaUtils.UPDATE_FACTORY_FACTORY),
			SqlFnUtils.GET_COUNT);
	}
	
	/**
	 * レコードを削除する{@link Fn}を生成します。
	 * @return レコードを削除する{@link Fn}。
	 */
	public Fn<Map<String, Object>, Integer> createDeleteFn() {
		return SqlFnUtils.inputMap(
			dataSource,
			new Fn<Map<String, Object>, PreparedStatementInfo>() {
				public PreparedStatementInfo exec(final Map<String, Object> c) {
					return SqlMetaUtils.DELETE_FACTORY.exec(getTableInfo(c));
				}
			},
			SqlFnUtils.GET_COUNT);
	}
}
