package cn.common.page.resolver;


import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import cn.common.page.response.Result;
import cn.util.core.IsKit;
import cn.util.core.TypeKit;

/**
 * 自定义 返回值处理配置类 实现 HandlerMethodReturnValueHandler接口
 * 
 * 统一json自定义格式的方式有多种：
 * 1，直接重写@reposeBody的实现，
 * 2，自定义一个注解，自己去解析对象成为json字符串进行返回
 * 第一种方式，不推荐
 * 第二种方式，主要通过定义注解，通过 HandlerMethodReturnValueHandler 对返回值的处理，而不让他进去viewResolver处理
 * 
 */
public class ResBodyWrapHandler implements HandlerMethodReturnValueHandler 
{
	private final String basePackage;
	private final String rawPackage;
	private final HandlerMethodReturnValueHandler delegate;

	public ResBodyWrapHandler(final HandlerMethodReturnValueHandler delegate,
			final String basePackage,final String rawPackage) {
		this.delegate = delegate;
		this.basePackage = basePackage;
		this.rawPackage = rawPackage;
	}

	@Override
	public boolean supportsReturnType(final MethodParameter returnType) {
		return this.delegate.supportsReturnType(returnType);
	}
	/**真正获取处理链，然后从处理链中选择合适的引擎并依次处理。
	 * 处理给定的返回值
	 * 通过向 ModelAndViewContainer 添加属性和设置视图或者
	 * 通过调用 ModelAndViewContainer.setRequestHandled(true) 来标识响应已经被直接处理(不再调用视图解析器)
	 * returnValue返回前端的数据；returnType产生returnValue的方法及参数method 'QueryById' parameter -1
	 */
	@Override
	public void handleReturnValue(Object returnValue, final MethodParameter returnType,
			final ModelAndViewContainer mavContainer,
			final NativeWebRequest webRequest) throws Exception
	{
		if(IsKit.isNullOrEmpty(returnValue)) {
		}
		//控制器中的方法没有调用ResponseResult.success，或控制器类下的处理分支
		else if (this.isWrapReturnValue(returnValue, returnType)) {
			//如果调用接口时候用的是FastJson，有可能出现多余的反斜杠. 消除反斜杠：
			if (returnValue instanceof String){
				String temp = TypeKit.objToStr(returnValue);
				returnValue = StringEscapeUtils.unescapeEcmaScript(temp)
						.replace("\"{","{")
						.replace("}\"","}")
						.replace("\\\"","\"");
			}
			else {
				returnValue = Result.ok(returnValue);//对返回值进行重新包装	
			}
		}
		//控制器中的方法调用ResponseResult.success的处理分支
		this.delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}
	/**
	 * 如果returnValue为ResponseResult类型
	 * 或 basePackage为空
	 * 或 不是调用类的前辍
	 * 则返回false(不需要包装@ResponseBody返回值)
	 *
	 * @param returnValue 返回值
	 * @param returnType  返回值类型
	 * @return true|false
	 */
	private boolean isWrapReturnValue(final Object returnValue, final MethodParameter returnType)
	{
		if (returnValue instanceof Result){
			return false;
		}
		if (StringUtils.isBlank(this.basePackage)) {
			return false;
		}

		if (returnValue instanceof String){
			return true;
		}
		
		final String declaringClazzName = returnType.getMethod().getDeclaringClass().getName();
		if(StringUtils.startsWith(declaringClazzName, this.rawPackage))
			return false;
		
		return StringUtils.startsWith(declaringClazzName, this.basePackage);
	}
}
