package com.whenling.module.security.shiro;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.http.HttpStatus;

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Strings;
import com.whenling.module.base.SpringContext;
import com.whenling.module.domain.model.Result;
import com.whenling.module.security.RobotPrevention;
import com.whenling.module.web.util.WebHelper;

/**
 * ajax认证过滤器
 * 
 * @作者 孔祥溪
 * @博客 http://ken.whenling.com
 * @创建时间 2016年3月1日 下午7:06:24
 */
public class AjaxAuthenticationFilter extends FormAuthenticationFilter {

	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

	private RobotPrevention robotPrevention;

	public void setRobotPrevention(RobotPrevention robotPrevention) {
		this.robotPrevention = robotPrevention;
	}

	@Override
	protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
		if (this.robotPrevention != null) {
			if (this.robotPrevention.validateRequest(request, response)) {
				return super.executeLogin(request, response);
			} else {
				throw new AuthenticationException();
			}
		}
		return super.executeLogin(request, response);
	}

	@Override
	protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
		if (WebHelper.isAjax((HttpServletRequest) request)) {
			((HttpServletResponse) response).setStatus(HttpStatus.UNAUTHORIZED.value());
			writeObject(request, response, Result.notLogin());
		} else {
			super.saveRequestAndRedirectToLogin(request, response);
		}
	}

	@Override
	protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
		if (WebHelper.isAjax((HttpServletRequest) request)) {
			writeObject(request, response, Result.success());
			return false;
		}
		return super.onLoginSuccess(token, subject, request, response);
	}

	@Override
	protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
		if (WebHelper.isAjax((HttpServletRequest) request)) {
			Result result = Result.failure();
			if (e instanceof IncorrectCredentialsException) {
				result.message("密码错误");
			} else if (e instanceof ExpiredCredentialsException) {
				result.message("密码已过期");
			} else if (e instanceof UnknownAccountException) {
				result.message("该账号不存在");
			} else if (e instanceof DisabledAccountException) {
				result.message("该账号已禁用");
			} else if (e instanceof LockedAccountException) {
				result.message("该账号已锁定");
			} else if (e instanceof AccountException) {
				result.message("账号错误");
			} else if (e instanceof CredentialsException) {
				result.message("密码错误");
			}
			try {
				writeObject(request, response, result);
			} catch (IOException ex) {
				throw new RuntimeException(ex);
			}
			return false;
		}
		return super.onLoginFailure(token, e, request, response);
	}

	protected void writeObject(ServletRequest request, ServletResponse response, Object result) throws IOException {
		String characterEncoding = ((HttpServletRequest) request).getCharacterEncoding();
		Charset charset = Strings.isNullOrEmpty(characterEncoding) ? DEFAULT_CHARSET : Charset.forName(characterEncoding);
		OutputStreamWriter out = new OutputStreamWriter(response.getOutputStream(), charset);
		SerializeWriter writer = new SerializeWriter(out);
		JSONSerializer serializer = new JSONSerializer(writer, SpringContext.getBean(SerializeConfig.class));
		serializer.config(SerializerFeature.DisableCircularReferenceDetect, true);
		serializer.write(result);
		writer.flush();
		out.close();
	}
}