package com.uas.platform.b2b.filter;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.uas.platform.b2b.model.Authority;
import com.uas.platform.b2b.model.Resource;
import com.uas.platform.b2b.model.Role;
import com.uas.platform.b2b.model.User;
import com.uas.platform.b2b.service.UserService;
import com.uas.platform.b2b.support.SecurityConstant;
import com.uas.platform.b2b.support.SystemSession;
import com.uas.platform.core.model.Constant;
import com.uas.platform.core.util.encry.Md5Utils;

/**
 * 
 * @author yingp
 * @version 1.0
 * 
 */
public class SecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

	private FilterInvocationSecurityMetadataSource securityMetadataSource;

	@Autowired
	@Qualifier("org.springframework.security.authenticationManager")
	protected AuthenticationManager authenticationManager;

	@Autowired
	private UserService userService;

	/**
	 * @param request
	 * @param response
	 * @param chain
	 * @throws IOException
	 * @throws ServletException
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		autoLogin(httpRequest);
		logSession(httpRequest);
		User user = SystemSession.getUser();
		if (user == null) {// 未登录则要求登录
			httpResponse.sendRedirect(httpRequest.getContextPath() + SecurityConstant.LOGIN_URL);
			return;
		}
		if (user.isSys()) {// 超级用户无需验证权限
			chain.doFilter(request, response);
			return;
		}
		invoke(new FilterInvocation(request, response, chain));
		logoutSession();
	}

	public void invoke(FilterInvocation filter) throws IOException, ServletException {
		InterceptorStatusToken token = super.beforeInvocation(filter);
		try {
			filter.getChain().doFilter(filter.getRequest(), filter.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}
	}

	/**  
     *   
     */
	public void destroy() {
	}

	/**
	 * @return
	 */
	@Override
	public Class<? extends Object> getSecureObjectClass() {
		return FilterInvocation.class;
	}

	/**
	 * @return
	 */
	@Override
	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
		this.securityMetadataSource = securityMetadataSource;
	}

	public void init(FilterConfig filterConfig) throws ServletException {

	}

	/**
	 * 将user信息放在当前线程里面
	 * 
	 * @param request
	 */
	private void logSession(HttpServletRequest request) {
		Object user = request.getSession().getAttribute("user");
		if (user != null)
			SystemSession.setUser((User) user);
		else {
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			if (authentication != null) {
				User authedUser = userService.findUserByUserUU(Long.parseLong(authentication.getName()));
				authedUser.setCurrentEnterprise();
				Set<Role> roles = authedUser.getRoles();
				if (!authedUser.isSys() && !CollectionUtils.isEmpty(roles)) {
					for (Role role : roles) {
						if (role.isSys()) {// 超级账号
							authedUser.setIssys(Constant.YES);
							break;
						}
					}
				}
				request.getSession().setAttribute("user", authedUser);
				SystemSession.setUser(authedUser);
			}
		}
	}

	/**
	 * 线程池策略下，不会频繁删除线程，置于线程内的对象须手动删除
	 */
	private void logoutSession() {
		SystemSession.clear();
	}

	static final String TEL_REGEXP = "^((\\(\\d{3}\\))|(\\d{3}\\-))?(13|15|18)\\d{9}$";

	static final String UU_REGEXP = "^\\d{4,}$";

	static final String ROLE_USER = "ROLE_USER";

	/**
	 * 自动登录
	 */
	private void autoLogin(HttpServletRequest request) {
		String username = request.getParameter("b_username");
		String password = request.getParameter("b_password");
		if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
			User user = null;
			if (username.contains("@")) { // 邮箱登录
				user = userService.findUserByUserEmail(username);
			} else if (username.matches(TEL_REGEXP)) {// 手机号登录
				user = userService.findUserByUserTel(username);
			} else if (username.matches(UU_REGEXP)) {
				user = userService.findUserByUserUU(Long.parseLong(username));
			}
			if (user != null && user.getUserPwd().equals(Md5Utils.encode(password, user.getUserUU()))) {
				Collection<GrantedAuthority> array = getGrantedAuthorities(user);
				UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUserUU(), password, array);
				Authentication authenticatedUser = authenticationManager.authenticate(token);
				SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
				request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
						SecurityContextHolder.getContext());
				user.setCurrentEnterprise();
				request.getSession().setAttribute("user", user);
			} else
				throw new UsernameNotFoundException(username + " 账号或密码错误");
		}
	}

	private Set<GrantedAuthority> getGrantedAuthorities(User user) {
		Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
		Set<Role> roles = user.getRoles();
		if (!CollectionUtils.isEmpty(roles)) {
			for (Role role : roles) {
				if (role.isSys()) {// 超级账号
					user.setIssys(Constant.YES);
					break;
				}
				Set<Authority> authorities = role.getAuthorities();
				if (!CollectionUtils.isEmpty(authorities)) {
					for (Authority authority : authorities) {
						Set<Resource> resources = authority.getResources();
						if (!CollectionUtils.isEmpty(resources)) {
							for (Resource res : resources) {
								authSet.add(new SimpleGrantedAuthority(res.getName()));
							}
						}
					}
				}
			}
		}
		return authSet;
	}

}
