package project.check.range;

import java.nio.charset.Charset;
import java.util.Objects;
import java.util.Optional;

import core.util.bean.Pair;
import online.context.check.ItemCheck;
import online.model.ModelUtil;
import project.check.BaseCheck;
import project.common.CheckUtil;

/**
 * 指定バイト数範囲内チェック
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class ByteRangeCheck extends BaseCheck implements ItemCheck {

	/** 最大バイト数 */
	private final int maxlen;
	/** 最小バイト数 */
	private final int minlen;
	/** エンコード */
	private final Charset enc;
	/** メッセージID */
	private final String mid;
	/** メッセージパラメータ */
	private final String[] prm;

	/**
	 * コンストラクタ
	 *
	 * @param min 指定最小バイト数
	 * @param max 指定最大バイト数
	 * @param charset エンコード
	 */
	public ByteRangeCheck(final int min, final int max, final Charset charset) {
		this.minlen = min;
		this.maxlen = max;
		this.enc = charset;
		this.mid = null;
		this.prm = null;
	}

	/**
	 * コンストラクタ
	 *
	 * @param min 指定最小バイト数
	 * @param max 指定最大バイト数
	 * @param charset エンコード
	 * @param msgId メッセージID
	 * @param param メッセージパラメータ
	 */
	public ByteRangeCheck(final int min, final int max, final Charset charset,
			final String msgId, final String... param) {
		this.minlen = min;
		this.maxlen = max;
		this.enc = charset;
		this.mid = msgId;
		this.prm = extend(param, String.valueOf(max), String.valueOf(min));
	}

	/**
	 * @see online.context.check.ItemCheck#check(java.lang.String...)
	 */
	@Override
	public void check(final String... items) {
		Optional<Pair<String, Integer>> check = Optional.empty();
		for (final var item : items) {
			final var val = getArrayParameter(item);
			for (var j = 0; val != null && j < val.length; j++) {
				if (!isTarget(j)) {
					val[j] = ModelUtil.getValueAsString(getUniModel(), item, j);
				} else if (!Objects.toString(val[j], "").isEmpty()) {
					final var len = Math.min(this.maxlen, Integer.MAX_VALUE - 1);
					if (!CheckUtil.isLessByte(val[j], len + 1, this.enc)
							|| CheckUtil.isLessByte(val[j], this.minlen, this.enc)) {
						setMessage(item, j, this.mid, this.prm);
						check = Optional.of(check.orElse(Pair.of(item, j)));
					}
				}
			}
		}

		check.ifPresent(this::throwKeepCheckException);
	}
}
