package project.svc.generic.db;

import java.io.IOException;
import java.io.Serializable;
import java.io.UncheckedIOException;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

import common.db.dao.DaoUtil;
import core.config.Factory;
import core.util.bean.CamelCase;


/**
 * テーブル情報
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
final class EntityInfo {

	/** jsonマップ */
	private static final TableInfo INFO;

	static {
		try (var is = EntityInfo.class.getResourceAsStream("tableinfo.json")) {
			INFO = new ObjectMapper().readValue(is, TableInfo.class);
		} catch (final IOException ex) {
			throw new UncheckedIOException(ex);
		}
	}

	/** テーブル名 */
	private final String table;

	/**
	 * コンストラクタ
	 * @param val テーブル名
	 */
	EntityInfo(final String val) {
		this.table = val;
	}

	/**
	 * テーブル名設定
	 * @return テーブル名
	 */
	public String getTable() {
		return this.table;
	}

	/**
	 * 論理削除判断
	 * @return 論理削除の場合 true を返す。
	 */
	public boolean isLogicalDelete() {
		return Boolean.parseBoolean(getInfo("LogicalDelete"));
	}

	/**
	 * DAOクラス取得
	 * @param <T> Type
	 * @return DAOクラス
	 */
	public <T extends Serializable> Class<T> getDaoClass() {
		final var cls = getInfo("DaoPackage") + "." + CamelCase.convert(this.table);
		return Factory.loadClass(cls);
	}

	/**
	 * 更新版項目名取得
	 * @return 更新版項目名
	 */
	public String getVersionName() {
		return getInfo("Version");
	}

	/**
	 * 作成者項目名取得
	 * @return 作成者項目名
	 */
	public String getCreatorName() {
		return getInfo("CreateUserId");
	}

	/**
	 * 作成日時項目名取得
	 * @return 作成日時項目名
	 */
	public String getCreatedName() {
		return getInfo("CreateDateTime");
	}

	/**
	 * 更新者項目名取得
	 * @return 更新者項目名
	 */
	public String getUpdaterName() {
		return getInfo("UpdateUserId");
	}

	/**
	 * 更新日時項目名取得
	 * @return 更新日時項目名
	 */
	public String getUpdatedName() {
		return getInfo("UpdateDateTime");
	}

	/**
	 * 設定情報取得
	 *
	 * @param val キー値
	 * @return 設定情報
	 */
	private String getInfo(final String val) {
		return INFO.getInfo(this.table, val);
	}

	/**
	 * 汎用情報
	 * @author Tadashi Nakayama
	 * @version 1.0.0
	 */
	public static final class TableInfo {
		/** 共通部 */
		private Common common;
		/** テーブル情報保持マップ */
		private final Map<String, Table> map = new HashMap<>();

		/**
		 * テーブル情報取得
		 * @param key1 キー1
		 * @param key2 キー2
		 * @return テーブル情報
		 */
		public String getInfo(final String key1, final String key2) {
			final var tbl = this.map.get(key1);
			if (tbl != null) {
				final String ret = DaoUtil.getValue(tbl, key2);
				if (ret != null) {
					return ret;
				}
			}
			return DaoUtil.getValue(this.common, key2);
		}

		/**
		 * @return the common
		 */
		public Common getCommon() {
			return this.common;
		}

		/**
		 * @param val the common to set
		 */
		public void setCommon(final Common val) {
			this.common = val;
		}

		/**
		 * @return the table
		 */
		public Table[] getTable() {
			throw new UnsupportedOperationException();
		}

		/**
		 * @param val the table to set
		 */
		public void setTable(final Table[] val) {
			final var table = (val != null) ? val.clone() : null;

			this.map.clear();
			if (table != null) {
				for (final var tbl : table) {
					this.map.put(tbl.getName(), tbl);
				}
			}
		}
	}

	/**
	 * テーブル情報
	 * @author Tadashi Nakayama
	 * @version 1.0.0
	 */
	public static class Table extends Common {
		/** テーブル名 */
		private String name;

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

		/**
		 * @param val the name to set
		 */
		public void setName(final String val) {
			this.name = val;
		}
	}

	/**
	 * 共通情報
	 * @author Tadashi Nakayama
	 * @version 1.0.0
	 */
	public static class Common {
		/** DAOパッケージ */
		private String daoPackage;
		/** 論理削除 */
		private String logicalDelete;
		/** 作成ユーザカラム名 */
		private String createUserId;
		/** 作成日時カラム名 */
		private String createDateTime;
		/** 更新ユーザカラム名 */
		private String updateUserId;
		/** 更新日時カラム名 */
		private String updateDateTime;
		/** バージョンカラム名 */
		private String version;

		/**
		 * @return the daoPackage
		 */
		public String getDaoPackage() {
			return this.daoPackage;
		}

		/**
		 * @param val the daoPackage to set
		 */
		public void setDaoPackage(final String val) {
			this.daoPackage = val;
		}

		/**
		 * @return the logicalDelete
		 */
		public String getLogicalDelete() {
			return this.logicalDelete;
		}

		/**
		 * @param val the logicalDelete to set
		 */
		public void setLogicalDelete(final String val) {
			this.logicalDelete = val;
		}

		/**
		 * @return the createUserId
		 */
		public String getCreateUserId() {
			return this.createUserId;
		}

		/**
		 * @param val the createUserId to set
		 */
		public void setCreateUserId(final String val) {
			this.createUserId = val;
		}

		/**
		 * @return the createDateTime
		 */
		public String getCreateDateTime() {
			return this.createDateTime;
		}

		/**
		 * @param val the createDateTime to set
		 */
		public void setCreateDateTime(final String val) {
			this.createDateTime = val;
		}

		/**
		 * @return the updateUserId
		 */
		public String getUpdateUserId() {
			return this.updateUserId;
		}

		/**
		 * @param val the updateUserId to set
		 */
		public void setUpdateUserId(final String val) {
			this.updateUserId = val;
		}

		/**
		 * @return the updateDateTime
		 */
		public String getUpdateDateTime() {
			return this.updateDateTime;
		}

		/**
		 * @param val the updateDateTime to set
		 */
		public void setUpdateDateTime(final String val) {
			this.updateDateTime = val;
		}

		/**
		 * @return the version
		 */
		public String getVersion() {
			return this.version;
		}

		/**
		 * @param val the version to set
		 */
		public void setVersion(final String val) {
			this.version = val;
		}
	}
}
