package jp.agentec.sinaburocast.action;

import java.io.IOException;
import java.util.Map;

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

import jp.agentec.sinaburocast.common.SessionBindingListener;
import jp.agentec.sinaburocast.common.SinaburoConstant;
import jp.agentec.sinaburocast.common.SinaburoConstant.AttrKey;
import jp.agentec.sinaburocast.common.util.ServletUtil;
import jp.agentec.sinaburocast.entity.AdminUser;
import jp.agentec.sinaburocast.entity.Member;
import jp.agentec.sinaburocast.vo.AuthenticatedTokenVO;

import org.apache.log4j.Logger;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.seasar.framework.container.S2Container;
import org.seasar.struts.annotation.Execute;

/**
 * AbstractActionクラス
 *
 *
 */
public abstract class AbstractAction {
	private final Logger logger = Logger.getLogger(getClass());

	public ServletContext application;
	public S2Container container;
	public HttpSession session;
	public HttpServletRequest request;
	public HttpServletResponse response;

	@javax.annotation.Resource
    protected Map<String, Object> sessionScope;

    /**
     * サブクラスでindex()を定義していないのにアクセスされた場合に404エラーへ飛ばす.
     *
     * 定義しておかないと例外が発生するための対処
     * @return
     * @throws Exception
     */
	@Execute(validator=false)
    public String index() throws Exception {
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
    	return null;
    }

	/**
	 * エラーメッセージがあるかどうかを返します.
	 *
	 * @return エラーメッセージがあるかどうか
	 */
    protected boolean hasErrors() {
    	return	ServletUtil.hasErrors(request);
    }

	/**
	 * メッセージ設定.
	 *
	 * application_ja.propertiesにpropertyとlabelが設定されていない場合に使用。
	 * @param messageOrProperty エラーメッセージ or propertyキー(引数がないもの)
	 */
	protected void addMessage(String messageOrProperty){
		ServletUtil.addMessage(request, messageOrProperty);
	}

	/**
	 * エラーメッセージ.
	 *
	 * application_ja.propertiesにpropertyとlabelが設定されていない場合に使用。
	 * @param messageOrProperty エラーメッセージ or propertyキー(引数がないもの)
	 */
	protected void addError(String messageOrProperty){
		ServletUtil.addError(request, messageOrProperty);
	}

	/**
	 * メッセージ設定.
	 *
	 * application_ja.propertiesにpropertyとlabelが設定されている場合に使用。
	 * @param property プロパティ名. errors.YYY等
	 * @param args 置換パラメータ. プロパティ名でないことに注意。
	 */
	protected void addMessage(String property, String... args){
		ServletUtil.addMessage(request, property, args);
	}

	/**
	 * エラーメッセージ.
	 *
	 * application_ja.propertiesにpropertyとlabelが設定されている場合に使用。
	 * @param property プロパティ名. errors.YYY等
	 * @param args 置換パラメータ. プロパティ名でないことに注意。
	 */
	protected void addError(String property, String... args){
		ServletUtil.addError(request, property, args);
	}

	/**
	 * セッションへのメッセージ設定.
	 *
	 * リダイレクトを超えて伝達したい場合に使用する。
	 * application_ja.propertiesにpropertyとlabelが設定されている場合に使用。
	 * @param property プロパティ名. errors.YYY等
	 * @param args 置換パラメータ. プロパティ名でないことに注意。
	 */
	protected void addMessage2session(String property, String... args){
		ServletUtil.addMessage(session, property, args);
	}

	/**
	 * セッションへのエラーメッセージ設定.
	 *
	 * リダイレクトを超えて伝達したい場合に使用する。
	 * application_ja.propertiesにpropertyとlabelが設定されている場合に使用。
	 * @param property プロパティ名. errors.YYY等
	 * @param args 置換パラメータ. プロパティ名でないことに注意。
	 */
	protected void addError2session(String property, String... args){
		ServletUtil.addError(session, property, args);
	}
	
	/**
	 * propertyを利用して画面から直接取得できる。 
	 * @param property 画面側で表示する場所で必要とする。
	 * @param key      keyでapp_jp.propertiesを検索する。isResourceがfalseの場合メーッセージを入れる。
	 * @param args     argsで埋め込む
	 */
	public void addErrorMessage(String property,String key,String... args){
		ActionMessages messages = (ActionMessages)request.getAttribute(Globals.ERROR_KEY);
		if (messages == null) {
			messages = new ActionMessages();
		}
		
		messages.add(property, new ActionMessage(key,args ));
		
		request.setAttribute(Globals.ERROR_KEY, messages);
	}

	/**
	 * リダイレクト先のURLを返す。
	 *
	 * @deprecated ROOTコンテキストのときリダイレクト先が//になる。
	 * @param path
	 * @return
	 */
	@Deprecated
	public String getRedirectUrl(String path) {
		if (path.contains("?")) {
			return path + "&redirect=true";
		}
		else {
			return path + "?redirect=true";
		}
	}

	/**
	 * リダイレクトする。
	 *
	 * contractUrlPathはフィルタが付加するため付けない。
	 *
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public void redirect(String path) throws IOException {
		String url = "";
		url = request.getContextPath() + path;

		if (logger.isDebugEnabled()) {
			logger.debug("Redirect to: " + url);
		}
		response.sendRedirect(url);
	}

	/**
     * セッションを再作成
     * 指定された属性を引き継ぐ
     */
    protected void renewSession(String... atrNames) {
    	session = ServletUtil.renewSession(request, atrNames);
    }

    /**
     * セッションのパスをセットする
     * 
     */
    protected void setCookiePath(String path) {
    	Cookie cookie = new Cookie("JSESSIONID", session.getId());
		cookie.setPath(path);
		cookie.setMaxAge(-1); // ブラウザが開いているときのみ
		response.addCookie(cookie);
    }

	protected AuthenticatedTokenVO getMemberInfo() {
    	return	(AuthenticatedTokenVO) session.getAttribute(AttrKey.AUTHENTICATED_TOKEN);
    }

    /**
     * ログインユーザIDを取得する。
     *
     * @return ログインユーザID
     */
    protected Integer getUserId() {
		return getMemberInfo().userId;
	}

    /**
     * ログインユーザのアカウント名を取得する。
     *
     * @return ログインユーザアカウント名
     */
    protected String getLoginId() {
		return getMemberInfo().loginId;
	}

    /**
	 * キャッシュを禁止
	 *
	 */
	protected void setNoCache() {
		response.addHeader("Expires", "-1");
		response.addHeader("Cache-Control", "no-cache");
		response.addHeader("Pragma", "no-cache");
	}
	
	/**
	 * ユーザー
	 * セッション情報を確立する。
	 * @param memberInfo MemberEntity
	 * @param userType
	 */
	protected void setAuthenticatedToken(Member memberInfo,int userType){
		AuthenticatedTokenVO token = new AuthenticatedTokenVO();
		token.member = memberInfo;
		token.userType = userType;
		token.userName = memberInfo.lastName;
		
		token.userId = memberInfo.memberId;
		token.loginId= memberInfo.loginId;
		
		session.setAttribute(AttrKey.AUTHENTICATED_TOKEN, token);
		SessionBindingListener listener = new SessionBindingListener(token, application);
		session.setAttribute(SinaburoConstant.AttrKey.BINDING_LISTENER, listener);	
	}
	
	
	/**
	 * memberを取得する。
	 * @return member
	 */
	protected Member getMember() {
		Object obj = session.getAttribute(AttrKey.AUTHENTICATED_TOKEN);
		if(obj == null){
			return null;
		}
		return ((AuthenticatedTokenVO)obj).member;
	}
	
	
	/**
	 * 管理者
	 * セッション情報を確立する。
	 * @param memberInfo MemberEntity
	 * @param userType
	 */
	protected void setAuthenticatedToken(AdminUser adminUserInfo,int userType){
		AuthenticatedTokenVO token = new AuthenticatedTokenVO();
		token.adminUser = adminUserInfo;
		token.userType = userType;
		token.userName = adminUserInfo.adminUserName;
		
		token.userId = adminUserInfo.adminUserId;
		token.loginId= adminUserInfo.loginId;
		
		session.setAttribute(AttrKey.AUTHENTICATED_TOKEN, token);
		SessionBindingListener listener = new SessionBindingListener(token, application);
		session.setAttribute(SinaburoConstant.AttrKey.BINDING_LISTENER, listener);	
	}
	
	
	/**
	 * adminUserを取得する。
	 * @return acminUser
	 */
	protected AdminUser getAdmin() {
		Object obj = session.getAttribute(AttrKey.AUTHENTICATED_TOKEN);
		if(obj == null){
			return null;
		}
		return ((AuthenticatedTokenVO)obj).adminUser;
	}
	
	/**ログインしていないユーザーはログイン画面に戻す。*/
	protected String adminLoginCheckPath = "/admin/";
	/**
	 * adminUserを取得する。
	 * @return acminUser
	 */
	protected String adminLoginCheck(String returnPath) {
		Object obj = session.getAttribute(AttrKey.AUTHENTICATED_TOKEN);
		if(obj == null){
			return returnPath;
		}
		
		if(((AuthenticatedTokenVO)obj).adminUser == null){
			return returnPath;
		}
		
		return "";
	}
	
	
	
	
}