package online.view.tag;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

import javax.servlet.jsp.JspException;

/**
 * チェックボックス、ラジオボタン設定タグライブラリ
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class CheckTag extends BaseTag {
	/** serialVersionUID */
	private static final long serialVersionUID = -7928611683846476569L;

	/** 選択文字列 */
	private static final String STR_CHECKED = "checked";

	/** 変数用変数 */
	private String var = null;
	/** 選択項目用変数 */
	private String name = null;
	/** 選択対象用変数 */
	private String value = null;
	/** デフォルト値用変数 */
	private String def = null;

	/**
	 * リリース処理
	 */
	@Override
	public void release() {
		this.var = null;
		this.name = null;
		this.value = null;
		this.def = null;
	}

	/**
	 * 変数設定
	 *
	 * @param val 保存変数名文字列
	 */
	public void setVar(final String val) {
		this.var = val;
	}

	/**
	 * 選択項目名設定
	 *
	 * @param val 選択項目名
	 */
	public void setName(final String val) {
		this.name = val;
	}

	/**
	 * 選択確認対象項目設定
	 *
	 * @param val 選択確認対象文字列
	 */
	public void setValue(final String val) {
		this.value = val;
	}

	/**
	 * デフォルト値設定
	 *
	 * @param val デフォルト値
	 */
	public void setDefault(final String val) {
		this.def = val;
	}

	/**
	 * @see javax.servlet.jsp.tagext.TagSupport#doStartTag()
	 */
	@Override
	public int doStartTag() throws JspException {
		try {
			// アトリビュートクリア
			if (this.var != null) {
				this.pageContext.removeAttribute(this.var);
			}

			if (this.name != null && this.value != null) {
				super.output(this.var, toCheckedString(this.value));
			}
			return SKIP_BODY;
		} finally {
			release();
		}
	}

	/**
	 * チェック文字列取得
	 *
	 * @param val 値
	 * @return チェック文字列
	 */
	private String toCheckedString(final String val) {
		boolean checked = false;

		Object obj = super.getObject(super.getViewMap(), super.toArrayName(this.name));
		if (List.class.isInstance(obj)) {
			checked = checked(List.class.cast(obj), val);
			if (!checked && this.def != null) {
				if (super.getObject(super.getViewMap().getMap(), this.name) == null) {
					checked = checked(Arrays.asList(this.def.split("\\|")), val);
				}
			}
		}

		return val + (checked ? "\" " + STR_CHECKED + "=\"" + STR_CHECKED : "");
	}

	/**
	 * チェック判断
	 *
	 * @param list 値リスト
	 * @param val 比較値
	 * @return チェックされている場合 true を返す。
	 */
	private boolean checked(final List<?> list, final String val) {
		return val != null && list.stream().
				map(o -> Objects.toString(o, null)).
				anyMatch(Predicate.isEqual(val));
	}
}
