package com.cesgroup.mybatiswork.interceptor;

import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;

import com.alibaba.fastjson.JSONObject;
import com.cesgroup.mybatiswork.handle.MyTypeHandle;

/**
 * @description: 日志拦截
 * @author: Sakamoto
 **/
@Intercepts({
		@Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class }),
		@Signature(type = StatementHandler.class, method = "update", args = { Statement.class }),
		@Signature(type = StatementHandler.class, method = "batch", args = { Statement.class })
})
public class MyMybatisLogInterceptor implements Interceptor {
	final Log log = LogFactory.getLog(MyTypeHandle.class);
	
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object target = invocation.getTarget();
		
		long startTime = System.currentTimeMillis();
		
		StatementHandler statementHandler = (StatementHandler) target;
		
		try {
			return invocation.proceed();
		} finally {
			long endTime = System.currentTimeMillis();
			long sqlCost = endTime - startTime;
			
			BoundSql boundSql = statementHandler.getBoundSql();
			String sql = boundSql.getSql();
			Object parameterObject = boundSql.getParameterObject();
			List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();
			
			// 格式化Sql语句，去除换行符，替换参数
			sql = formatSql(sql, parameterObject, parameterMappingList);
			
			log.warn("执行耗时[" + sqlCost + "ms] " + "SQL：" + sql + ";");
			
		}
	}
	
	private String formatSql(String sql, Object parameterObject, List<ParameterMapping> parameterMappingList) {
		sql = sql.replaceAll("\r|\n|\t", " ").replaceAll("\\s+", " ");
		if (parameterObject == null) {
			sql = sql.replaceAll("\\?", " null");
			return sql;
		}
		
		if (Map.class.isAssignableFrom(parameterObject.getClass())) {
			Map pb = (Map) parameterObject;
			for (ParameterMapping temp : parameterMappingList) {
				if (pb.get(temp.getProperty()) != null) {
					if (pb.get(temp.getProperty()).getClass().isAssignableFrom(JSONObject.class)) {
						JSONObject infObject = (JSONObject) pb.get(temp.getProperty());
						sql = sql.replaceFirst("\\?", "'" + infObject.toJSONString() + "'");
					} else {
						sql = sql.replaceFirst("\\?", "'" + pb.get(temp.getProperty()) + "'");
					}
				} else {
					sql = sql.replaceFirst("\\?", "'null'");
				}
			}
		}
		
		if (String.class.isAssignableFrom(parameterObject.getClass())) {
			sql = sql.replaceFirst("\\?", parameterObject == null ? "null" : "'" + parameterObject + "'");
		}
		
		if (Number.class.isAssignableFrom(parameterObject.getClass())) {
			sql = sql.replaceFirst("\\?", parameterObject == null ? "null" : parameterObject.toString());
		}
		
		return sql;
	}
	
	@Override
	public Object plugin(Object o) {
		return Plugin.wrap(o, this);
	}
	
	@Override
	public void setProperties(Properties properties) {
		
	}
}
