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;

import core.util.NumberUtil;

/**
 * 選択文字列設定タグライブラリ
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class SelectTag extends BaseTag {
	/** serialVersionUID */
	private static final long serialVersionUID = -5206810127044659963L;

	/** 選択文字列 */
	private static final String STR_SELECTED = "selected";

	/** 変数用変数 */
	private String var = null;
	/** 選択項目用変数 */
	private String name = null;
	/** 選択文字列用変数 */
	private String value = null;
	/** デフォルト値用変数 */
	private String def = null;
	/** 選択項目配列時位置指定 */
	private int index = -1;

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

	/**
	 * 変数設定
	 *
	 * @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;
	}

	/**
	 * 選択項目配列時位置指定
	 *
	 * @param val 位置
	 */
	public void setIndex(final String val) {
		this.index = NumberUtil.toInt(val, -1);
	}

	/**
	 * @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, toSelectedString(this.value));
			}
			return SKIP_BODY;
		} finally {
			release();
		}
	}

	/**
	 * 選択文字列取得
	 *
	 * @param val 値
	 * @return 選択文字列
	 */
	public String toSelectedString(final String val) {
		boolean selected = false;

		Object obj = super.getObject(super.getViewMap(), super.toArrayName(this.name));
		if (List.class.isInstance(obj)) {
			selected = selected(List.class.cast(obj), val, this.index);
			if (!selected && this.def != null) {
				if (0 <= this.index) {
					if (this.index < List.class.cast(obj).size()
									&& List.class.cast(obj).get(this.index) == null) {
						selected = selected(Arrays.asList(this.def.split("\\|")), val, -1);
					}
				} else {
					if (super.getObject(super.getViewMap().getMap(), this.name) == null) {
						selected = selected(Arrays.asList(this.def.split("\\|")), val, -1);
					}
				}
			}
		}

		return val + (selected ? "\" " + STR_SELECTED + "=\"" + STR_SELECTED : "");
	}

	/**
	 * 出力処理
	 *
	 * @param val 選択値
	 * @param list 選択リスト
	 * @param idx インデックス
	 * @return 選択結果
	 */
	private boolean selected(final List<?> list, final String val, final int idx) {
		return val != null
			&& ((idx < 0 && list.stream().
						map(o -> Objects.toString(o, null)).anyMatch(Predicate.isEqual(val)))
				|| (idx < list.size() && val.equals(Objects.toString(list.get(idx), null))));
	}
}
