package me.chyxion.tigon.shiro;

import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import me.chyxion.tigon.webmvc.JSONViewConfig;
import me.chyxion.tigon.webmvc.JSONViewDataModel;
import me.chyxion.tigon.webmvc.util.ResponseTool;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.session.UnknownSessionException;
import me.chyxion.tigon.webmvc.exception.ExceptionMessage;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br>
 * chyxion@163.com <br>
 * Sep 21, 2014 8:24:39 PM
 */
@Slf4j
public class UserFilterExt extends UserFilter {
    protected final ResponseTool responseTool;
    protected final JSONViewConfig viewConfig;
    protected final ExceptionMessage exceptionMessage;

    /**
     * construct user filter ext
     * @param responseTool response tool
     * @param viewConfig view config
     * @param exceptionMessage exception message
     */
    public UserFilterExt(ResponseTool responseTool,
            JSONViewConfig viewConfig, ExceptionMessage exceptionMessage) {
        this.responseTool = responseTool;
        this.viewConfig = viewConfig;
        this.exceptionMessage = exceptionMessage;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        try {
            return super.isAccessAllowed(request, response, mappedValue);
        }
        catch (UnknownSessionException e) {
            log.warn("Unknown Session Exception Caused.", e);
            return false;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) {
        log.info("Access Denied, Redirect To Login.");
        if (!response.isCommitted()) {
            int code = 4011;
            Object message = null;
            if (exceptionMessage != null) {
                message = exceptionMessage.get(code);
            }
            if (message == null) {
                message = "Access Denied, You May Need Login";
            }
            JSONViewDataModel dataModel = new JSONViewDataModel()
                    .setSuccess(false)
                    .setCode(code)
                    .setMessage(message);
            processAccessDeniedDataModel((HttpServletRequest) request, 
                (HttpServletResponse) response, dataModel);
            if (!doRedirectToLogin(request, response, dataModel)) {
                responseTool.writeJSON(response,
                    dataModel.toMap(viewConfig.getSuccessKey(),
                        viewConfig.getDataKey(),
                        viewConfig.getCodeKey(),
                        viewConfig.getMessageKey()));
            }
        }
    }
   
    /**
     * Process Access Denied Model
     * @param request request
     * @param response response
     * @param dataModel data model
     */
    protected void processAccessDeniedDataModel(
            HttpServletRequest request, 
            HttpServletResponse response, 
            JSONViewDataModel dataModel) {
        // For Override
    }

    /**
     * for custom redirect to login
     * @param request request
     * @param response response
     * @param dataModel data model
     * @return true if redirected
     */
    protected boolean doRedirectToLogin(
            ServletRequest request, 
            ServletResponse response, 
            JSONViewDataModel dataModel) {
        // For Override
        return false;
    }
}
