package online.struts.chain.command;

import org.apache.commons.chain2.Processing;
import org.apache.struts.Globals;
import org.apache.struts.chain.commands.ActionCommand;
import org.apache.struts.chain.commands.ActionCommandBase;
import org.apache.struts.chain.contexts.ActionContext;
import org.apache.struts.chain.contexts.ServletActionContext;

import online.struts.action.UniForm;
import online.struts.mapping.RequestMapping;

/**
 * コマンドリクエスト
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public interface RequestCommand extends ActionCommandBase {

	/**
	 * @see org.apache.struts.chain.commands.ActionCommandBase
	 * #execute(org.apache.struts.chain.contexts.ActionContext)
	 */
	@Override
	default Processing execute(final ActionContext<String, Object> context) {
		// キャスト
		if (!ServletActionContext.class.isInstance(context)) {
			throw new IllegalStateException(String.valueOf(context));
		}
		final var sac = ServletActionContext.class.cast(context);

		final var ac = context.getActionConfig();
		if (!RequestMapping.class.isInstance(ac)) {
			return Processing.CONTINUE;
		}
		final var mapping = RequestMapping.class.cast(ac);

		final var form = context.getActionForm();
		if (!UniForm.class.isInstance(form)) {
			return Processing.CONTINUE;
		}
		final var uf = UniForm.class.cast(form);

		return command(sac, mapping, uf);
	}

	/**
	 * 例外判断
	 *
	 * @param sac コンテキスト
	 * @return 例外が発生していた場合 true を返す。
	 */
	static boolean isException(final ServletActionContext sac) {
		return sac.getRequest().getAttribute(Globals.EXCEPTION_KEY) != null;
	}

	/**
	 * 初回確認
	 *
	 * @param sac コンテキスト
	 * @param cls 確認クラス
	 * @return 初回の場合 true を返す。
	 */
	static boolean isFirst(final ServletActionContext sac,
		final Class<? extends ActionCommand<String, Object, ActionContext<String, Object>>> cls) {
		final var clazz = cls.getName();
		if (sac.getRequest().getAttribute(clazz) == null) {
			sac.getRequest().setAttribute(clazz, clazz);
			return true;
		}
		return false;
	}

	/**
	 * コマンド処理
	 *
	 * @param sac サーブレットアクションコンテキスト
	 * @param mapping アクションマッピング
	 * @param uf 汎用フォーム
	 * @return 処理結果
	 */
	Processing command(ServletActionContext sac, RequestMapping mapping, UniForm uf);
}
