package project.check;

import java.util.Arrays;
import java.util.Optional;

import core.config.Factory;
import core.util.bean.Pair;
import online.context.check.ItemCheckBase;
import online.context.check.KeepCheckException;
import online.context.check.NoMoreCheckException;
import project.common.master.Msg;
import project.master.MsgUtil;

/**
 * チェック作成用親
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public abstract class BaseCheck extends ItemCheckBase {

	/**
	 * チェック対象判断
	 *
	 * @param loc 位置
	 * @return チェック対象の場合 true を返す。
	 */
	protected boolean isTarget(final int loc) {
		return getPredicate() == null || getPredicate().test(loc);
	}

	/**
	 * トップメッセージ追加
	 *
	 * @param mid メッセージID
	 * @param prms パラメタ
	 */
	protected void addTopMessage(final String mid, final String... prms) {
		final var msg = Factory.create(Msg.class);
		getMessageList().add(msg.getMessage(mid, prms));
		getStatusList().add(msg.getStatus(mid));
	}

	/**
	 * メッセージ設定
	 * @param item 項目名
	 * @param loc 位置
	 * @param mid メッセージID
	 * @param prm メッセージパラメタ
	 */
	protected void setMessage(final String item,
			final int loc, final String mid, final String... prm) {
		if (!MsgUtil.hasItemMessage(getUniModel(), item)) {
			addTopMessage(mid, prm);
		}
		if (!MsgUtil.hasItemMessage(getUniModel(), item, loc)) {
			MsgUtil.putItemMessage(getUniModel(), item, loc, mid, prm);
		}
	}

	/**
	 * 例外メッセージ取得
	 * @param item 項目名
	 * @param loc 位置
	 * @return 例外メッセージ
	 */
	private String getExceptionMessage(final String item, final Integer loc) {
		return String.join(":", this.getClass().getName(), item, String.valueOf(loc));
	}

	/**
	 * KeepCheckException
	 * @param p Pair
	 */
	protected void throwKeepCheckException(final Pair<String, Integer> p) {
		throw new KeepCheckException(getExceptionMessage(p.left(), p.right()));
	}

	/**
	 * NoMoreCheckException
	 * @param p Pair
	 */
	protected void throwNoMoreCheckException(final Pair<String, Integer> p) {
		throw new NoMoreCheckException(getExceptionMessage(p.left(), p.right()));
	}

	/**
	 * 複製作成
	 *
	 * @param <T> ジェネリックス
	 * @param array 配列
	 * @return 複製配列
	 */
	protected static <T> T[] copyOf(final T[] array) {
		return copyOf(array, null);
	}

	/**
	 * 複製作成
	 *
	 * @param <T> ジェネリックス
	 * @param array 配列
	 * @param def デフォルト値
	 * @return 複製配列
	 */
	protected static <T> T[] copyOf(final T[] array, final T[] def) {
		return Optional.ofNullable(array).map(T[]::clone).orElse(def);
	}

	/**
	 * 配列拡張
	 * @param base 配列
	 * @param vals 拡張する値
	 * @return 拡張配列
	 */
	protected final String[] extend(final String[] base, final String... vals) {
		var ret = Optional.ofNullable(base).orElse(vals);
		if (base != null && vals != null) {
			ret = Arrays.copyOf(base, base.length + vals.length);
			System.arraycopy(vals, 0, ret, base.length, vals.length);
		}
		return ret;
	}
}
