package team.bangbang.spring.parameter;

import java.io.IOException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import team.bangbang.common.config.Constants;
import team.bangbang.common.data.util.DataShaper;
import team.bangbang.common.data.util.Transport;
import team.bangbang.sso.client.IAccountClient;
import team.bangbang.sso.data.Account;

/**
 * 自定义解析器
 *
 * @author 帮帮组
 * @version 1.0 2018-06-05
 */
public class CustomizedResolver implements HandlerMethodArgumentResolver {
	private static final String TEMP_REQUEST_MAP = "TEMP_REQUEST_MAP";

	/*
	 * (non-Javadoc)
	 *
	 * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#
	 * supportsParameter(org.springframework.core.MethodParameter)
	 */
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(EntityParam.class)
				|| parameter.hasParameterAnnotation(SessionUser.class);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#
	 * resolveArgument(org.springframework.core.MethodParameter,
	 * org.springframework.web.method.support.ModelAndViewContainer,
	 * org.springframework.web.context.request.NativeWebRequest,
	 * org.springframework.web.bind.support.WebDataBinderFactory)
	 */
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		// 处理EntityParam注解
		// 获取参数注解
		EntityParam ea = parameter.getParameterAnnotation(EntityParam.class);
		if (ea != null) {
			// 获取变量的名称
			String name = parameter.getParameterName();
			if (name == null || name.trim().length() == 0) {
				return null;
			}

			// 获取方法参数的类型
			Class<?> cls = parameter.getParameterType();

			// 获取请求数据
			Map<String, Object> datas = getRequestMap(webRequest);

			return requestToObject(datas, name, cls);
		}

		// 处理SessionUser注解
		// 获取参数注解
		SessionUser su = parameter.getParameterAnnotation(SessionUser.class);
		if (su != null) {
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			// 必须使用SSOClientFilter,SSOClientFilter获得当前登录信息
			IAccountClient accClt = (IAccountClient) request.getAttribute(Constants.KEY_SSO_CLIENT_ACCOUNT);
			// 转换为Account对象,并添加dataLimit
			Account user = (accClt != null ? accClt.getAccount() : null);
			
			return user;
		}

		return null;
	}

	private Map<String, Object> getRequestMap(NativeWebRequest webRequest) throws IOException {
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

		// 从Request中重新读取
		@SuppressWarnings("unchecked")
		Map<String, Object> datas = (Map<String, Object>) request.getAttribute(TEMP_REQUEST_MAP);

		if (datas != null) {
			return datas;
		}

		datas = new HashMap<String, Object>();

		// 上传文件、传递数据
		Transport.transport(request, datas);

		request.setAttribute(TEMP_REQUEST_MAP, datas);

		return datas;
	}

	/**
	 * 单纯文本参数表单提交的处理,将请求参数对应到当前Action的成员变量中
	 *
	 * @param map 页面数据,如果存在文件上传,则此处的Map中保存了文件上传后的File对象
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws ParseException
	 */
	private Object requestToObject(Map<String, Object> map, String entityName, Class<?> cls)
			throws InstantiationException, IllegalAccessException, ParseException {
		Object objReturn = cls.newInstance();
		Set<String> keys = map.keySet();
		if (keys == null || keys.isEmpty()) {
			return objReturn;
		}

		Object objValue = null;
		for (String strKey : keys) {
			if (strKey.equals(entityName)) {
				// 直接返回这个值
				objReturn = DataShaper.toObject(cls, map.get(strKey));
				continue;
			}

			// 获取相关的参数
			if (strKey.startsWith(entityName + ".")) {
				// 页面没有传入该值
				objValue = map.get(strKey);
				if (objValue == null) {
					continue;
				}

				// objReturn : a
				// strKey : a.b.c

				int nIndex = strKey.indexOf(".");
				strKey = strKey.substring(nIndex + 1);

				// strKey : b.c
				try {
					DataShaper.executeExpression(objReturn, strKey, objValue);
				} catch (Exception e) {
				}
			}
		} // end for

		return objReturn;
	}
}