package project.web.auth;

import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

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

import core.config.Factory;
import online.context.check.InputCheck;
import online.context.session.SessionScope;
import online.context.session.SessionUser;
import online.model.ModelUtil;
import online.struts.action.UniForm;
import online.struts.mapping.RequestMapping;
import project.check.range.LengthRangeCheck;
import project.master.MsgUtil;
import project.svc.auth.Authentication;
import project.svc.auth.SessionInfo;
import project.svc.auth.SessionInfo.LogoffType;
import project.web.InstanceFactory;


/**
 * ログオンアクションクラス
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class LogonActionImpl extends LogonAction {

	/** タグ ユーザID */
	private static final String TAG_UID = "Uid";
	/** ユーザー情報　パスワード*/
	private static final String TAG_PWD = "Pwd";

	/** ユーザID、パスワードエラーメッセージ */
	private static final String MSGID_NOT_USER = "ZZ000000001";

	/**
	 * ログオン主処理
	 *
	 * @param mapping ActionMappingオブジェクト
	 * @param uf 汎用フォーム
	 * @param request HttpServletRequestオブジェクト
	 * @param response HttpServletResponseオブジェクト
	 * @return 処理結果
	 */
	@Override
	public String perform(final RequestMapping mapping, final UniForm uf,
					final HttpServletRequest request, final HttpServletResponse response) {

		if (uf.getSessionUser() != null) {
			return "LOGONED";
		}

		InputCheck ic = InstanceFactory.create(InputCheck.class, uf);
		ic.add(TAG_UID, new LengthRangeCheck(0, 64));
		ic.add(TAG_PWD, new LengthRangeCheck(0, 64));
		ic.populate();

		// 初期表示
		if (!uf.containsKey(TAG_UID) || !uf.containsKey(TAG_PWD)) {
			return ID_VIEW;
		}

		// ログオン処理
		Authentication auth = Factory.create(Authentication.class);
		if (!auth.logon(uf.getString(TAG_UID), uf.getString(TAG_PWD))) {
			MsgUtil.putTopMessage(uf, MSGID_NOT_USER);
			MsgUtil.putMessage(uf, TAG_UID, MSGID_NOT_USER);
			MsgUtil.putMessage(uf, TAG_PWD, MSGID_NOT_USER);
			return ID_VIEW;
		}

		// セション取得
		Map<String, Object> map = invalidateSession(request.getSession(false));
		HttpSession session = request.getSession();
		map.forEach(session::setAttribute);

		// ログオン情報設定
		SessionInfo li = auth.updateStatus(uf.getString(TAG_UID),
						uf.getPresent(), session.getId(), session.getMaxInactiveInterval());

		// 強制ログアウト時
		if (LogoffType.TYPE_FORCE.equals(li.getLogoffType())) {
			// 別セションログオンメッセージ設定
			MsgUtil.putTopMessage(uf, "ZZ000000004");
		}

		// セションに情報設定
		// モデル作成
		SessionUser m = new SessionUser(uf.getString(TAG_UID));
		// セション情報保存
		SessionScope.setSessionUser(request, m);
		uf.setSessionUser(m);

		// ログオン情報設定
		setLogonInfoToSession(li, uf, session);

		return ID_OK;
	}

	/**
	 * セション無効化
	 * @param session HttpSession
	 * @return セション保存オブジェクト
	 */
	private Map<String, Object> invalidateSession(final HttpSession session) {
		if (session != null) {
			Map<String, Object> map = Collections.list(session.getAttributeNames()).stream().
							collect(Collectors.toMap(v -> v, v -> session.getAttribute(v)));
			session.invalidate();
			return map;
		}
		return Collections.EMPTY_MAP;
	}

	/**
	 * ログオン情報設定
	 *
	 * @param li ログオン情報
	 * @param uf 汎用フォーム
	 * @param session セションオブジェクト
	 */
	protected void setLogonInfoToSession(final SessionInfo li,
					final UniForm uf, final HttpSession session) {
		// ログオン時間
		session.setAttribute(TAG_LOGON_TIME, li.getLogonDateTime());
		// ログオフ時間
		session.setAttribute(TAG_LOGOFF_TIME, li.getLogoffDateTime());
		// ログオフ形態
		session.setAttribute(TAG_LOGOFF_TYPE, li.getLogoffType());
		// メッセージ
		session.setAttribute(ModelUtil.TAG_MESSAGE, uf.getStringArray(ModelUtil.TAG_MESSAGE));
		session.setAttribute(ModelUtil.TAG_STATUS, uf.getStringArray(ModelUtil.TAG_STATUS));
	}
}
