package project.web.processor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import online.context.session.SessionScope;
import online.context.session.SessionUser;
import online.struts.action.UniForm;
import online.struts.chain.command.ActionRequest;
import online.struts.chain.command.ActionRequest.CommandRequest;
import online.struts.mapping.RequestMapping;

import org.apache.commons.chain2.Processing;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.chain.commands.ActionCommandBase;
import org.apache.struts.chain.contexts.ActionContext;
import org.apache.struts.chain.contexts.ServletActionContext;

import project.master.MsgUtil;
import project.svc.auth.Authentication;
import core.config.Factory;

/**
 * アクションチェック
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class AuthenticationProcessor extends ActionCommandBase implements CommandRequest {
	/** 再ログオン */
	public static final String ID_RELOGON = "RELOGON";

	/** タイムアウトメッセージ */
	private static final String MSGID_TIME_OUT = "ZZ000000003";
	/** 未ログオンメッセージ */
	private static final String MSGID_NOT_LOGON = "ZZ000000002";

	/** 多重ログイン可否 */
	private boolean multiple = false;

	/**
	 * 多重ログイン可否取得
	 *
	 * @return 多重ログイン可否
	 */
	public boolean isMultiple() {
		return this.multiple;
	}

	/**
	 * 多重ログイン可否設定
	 *
	 * @param val 多重ログイン可否
	 */
	public void setMultiple(final boolean val) {
		this.multiple = val;
	}

	/**
	 * @see org.apache.struts.chain.commands.ActionCommandBase
	 * #execute(org.apache.struts.chain.contexts.ActionContext)
	 */
	@Override
	public Processing execute(final ActionContext<String, Object> context) {
		if (context.getForwardConfig() == null
						&& Processing.FINISHED.equals(ActionRequest.execute(context, this))) {
			return Processing.FINISHED;
		}
		return Processing.CONTINUE;
	}

	/**
	 * @see online.struts.chain.command.ActionRequest.CommandRequest
	 * #command(org.apache.struts.chain.contexts.ServletActionContext,
	 * online.struts.mapping.RequestMapping, online.struts.action.UniForm)
	 */
	@Override
	public Processing command(final ServletActionContext sac,
					final RequestMapping mapping, final UniForm uf) {
		// ログオンとアクションチェック
		// セッションタイムアウトチェック
		ActionForward af = checkLogon(sac.getRequest(), uf, mapping);
		if (af != null && ID_RELOGON.equals(af.getName())) {
			// メッセージ設定
			MsgUtil.putTopMessage(uf, MSGID_NOT_LOGON);
			sac.getResponse().setStatus(HttpServletResponse.SC_UNAUTHORIZED);
		}

		sac.setForwardConfig(af);

		return Processing.CONTINUE;
	}

	/**
	 * ログオン確認処理
	 *
	 * @param request HTTPリクエスト
	 * @param uf 汎用フォーム
	 * @param mapping マッピング
	 * @return ActionForwardオブジェクト
	 */
	private ActionForward checkLogon(final HttpServletRequest request,
					final UniForm uf, final ActionMapping mapping) {
		// ログオンチェック
		SessionUser su = SessionScope.getSessionUser(request);
		if (su == null) {
			MsgUtil.putTopMessage(uf, MSGID_TIME_OUT);
			return mapping.findForward(ID_RELOGON);
		}

		if (!this.multiple) {
			Authentication auth = Factory.create(Authentication.class);
			HttpSession session = request.getSession(false);
			if (session == null || !auth.checkLogon(su.getUid(), session.getId())) {
				return mapping.findForward(ID_RELOGON);
			}

			// アクション時間設定
			auth.setActionTime(su.getUid(), uf.getPresent(), session.getId());
		}

		return null;
	}
}
