package com.skua.config.mybatis;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList;
import com.skua.core.api.vo.LoginUser;
import com.skua.core.context.BaseContextHandler;
import com.skua.core.context.SpringContextUtils;
import com.skua.core.util.ConvertUtils;
import com.skua.modules.system.service.impl.SysDepartServiceImpl;
import com.skua.tool.annotation.Anonymous;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class MybatisInterceptor implements Interceptor {

    @Value("${spring.datasource.dynamic.datasource.master.url}")
    private String dataBaseUrl;
    //保存查询时的departId
    private static String departId;

    //过滤不需要走数据权限的表
    private List<String> tableNameList = new ArrayList<String>() {{
        add("f_audit_doing");
        add("f_audit_history");
        add("f_data_item");
        add("f_data_type");
        add("f_permission_cfg_detail");
        add("f_process_cfg");
        add("f_process_node");
        add("f_process_node_approver");
        add("f_process_node_percfg");
        add("f_report_item");
        add("f_report_manage");
        add("sys_role");
        add("sys_metric_dict");
        add("f_permission_cfg");
        add("data_assessment_socre");
        add("emergency_plan_database");
        //add("sys_algorithm_library");
        add("sys_announcement");
        add("weather_now");
        //构筑物过滤权限
        add("sys_struct_dict");
        //库存管理过滤权限
        add("ajh_supplier_manage");
        add("ajh_meeting_attend");
        add("equipment_sparepart_supplies_allot");
        add("ajh_rectification_info");
        add("alarm_rule_config_public_templete");//放行报警配置公共模板表
        //算法库相关表过滤权限
        add("sys_algorithm_database_info");
        add("sys_algorithm_interface_service");
        add("sys_algorithm_library");
        add("sys_algorithm_library_detail");
        add("sys_algorithm_statistics_library");
        //巡检触发方式卡片配置
        add("inspection_point_trigger_config");

        //用户试卷
        add("edu_user_paper");
        //采购药剂物料
        add("erp_purchase_plan_item");
        add("erp_purchase_material");
        add("erp_distribut_material");
        //共享风险库
        add("danger_level_manage_share");

    }};

    //过滤不需要走部门ID查询的URL
    private List<String> queryCriteriaDepartIdList = new ArrayList<String>() {{
        add("com.skua.modules.remotecontrol.mapper.SysMonitorLocationMapper.getAllData");
    }};

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

        // 检查方法或类上是否有自定义注解:匿名访问注解
        Anonymous  anonymous = getAnnotationByAnonymous(mappedStatement);
        String sqlId = mappedStatement.getId();
        log.debug("------sqlId------" + sqlId);
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        Object parameter = invocation.getArgs()[1];
        log.debug("------sqlCommandType------" + sqlCommandType);
        if (parameter == null) {
            return invocation.proceed();
        }
        if (SqlCommandType.SELECT == sqlCommandType) {
            //如果为管理员,则跳过权限
            if ("1".equals(BaseContextHandler.get("userType"))) {
                return invocation.proceed();
            }
            //匿名访问注解,不涉及权限
            if(anonymous != null ){
                return invocation.proceed();
            }

            System.out.println("sqlId = "+sqlId);
            //这些方法不涉及权限
            if ("com.skua.modules.system.mapper.SysDepartMapper.getDepartTreeByJt".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.system.mapper.SysDepartMapper.getDepartTree".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.report.mapper.FReportItemvMapper.getListByTime".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhMeetingMapper.getDataById".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.inspection.mapper.InspectionUserWorkingGroupMapper.getPage".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhRectificationInfoMapper.countHistogramList".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhRectificationInfoMapper.countByDate".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhRectificationInfoMapper.levelHistogramList".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhRectificationInfoMapper.dutyHistogramList".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhRectificationInfoMapper.classifyList".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.ajh.mapper.AjhMeetingMinutesMapper.getDataById".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.system.mapper.SysDepartMapper.queryUserDeparts".equalsIgnoreCase(sqlId)
                    || "com.skua.modules.system.mapper.SysAnnouncementMapper.querySysCementListByUserId".equals(sqlId)
                    || "com.skua.modules.supplies.mapper.EquipmentSparepartSuppliesMapper.selectPageByOut".equals(sqlId)
                    || "com.skua.modules.product.equipRemoteControl.mapper.RemoteControlMapper.queryEquipListDetail".equals(sqlId)
                    || "com.skua.modules.erp.mapper.PurchasePlanMapper.statisticsPage".equals(sqlId) //采购计划统计
                    || "com.skua.modules.erp.mapper.PurchaseMaterialMapper.queryMaterialByGoodCode".equals(sqlId) //采购合同根据code查询
                    || "com.skua.modules.erp.mapper.PurchasePlanItemMapper.queryListByPlanId".equals(sqlId) //采购计划
                    || "com.skua.modules.erp.mapper.PurchaseMaterialMapper.queryListByContractId".equals(sqlId) //采购合同
                    || "com.skua.modules.erp.mapper.DistributMaterialMapper.queryListByContractId".equals(sqlId) //采购-分销合同
                    || "com.skua.modules.erp.mapper.ERPPurchaseContractMapper.selectList".equals(sqlId) //采购合同
                    || "com.skua.modules.supplies.mapper.EquipmentSparepartSuppliesMapper.selectList".equals(sqlId) //物料
                    || "com.skua.modules.system.datestandard.mapper.SysMonitorMetricInfoMapper.selectList".equals(sqlId) //点表
            ) {
                log.debug("************************------sqlId------**************************" + sqlId);
                return invocation.proceed();
            }
            Object[] args = invocation.getArgs();
            if (args[1] instanceof Map) {
                departId = "";
                Map<String, Object> argsMap = (Map) args[1];
                for (Map.Entry<String, Object> entry : argsMap.entrySet()) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    //获取直接的departId传参
                    if ("departId".equalsIgnoreCase(key)) {
                        departId = ConvertUtils.getString(value);
                    } else if (value instanceof QueryWrapper) {
                        //从QueryWrapper中取到departId对应的入参
                        AbstractWrapper queryWrapper = ((QueryWrapper) value).lambda();
                        //初始化queryWrapper中的getParamNameValuePairs方法
                        queryWrapper.getCustomSqlSegment();
                        MergeSegments expression = queryWrapper.getExpression();
                        Map paramNameValuePairs = queryWrapper.getParamNameValuePairs();
                        NormalSegmentList normal = expression.getNormal();
                        int count = 0;
                        boolean flag = false;
                        for (ISqlSegment iSqlSegment : normal) {
                            count++;
                            if (iSqlSegment.getSqlSegment().toLowerCase().contains("depart_id")) {
                                flag = true;
                                break;
                            }
                        }
                        if (flag) {
                            if (normal.size() == 1){
                                departId = normal.get(0).getSqlSegment().split("=")[1].replace("'","").trim();
                            }else {
                                String[] departIdArr = normal.get(count + 1).getSqlSegment().split(",");
                                if (departIdArr.length > 1) {
                                    break;
                                }
                                String sqlSegment = departIdArr[0].replace("#{", "").replace("}", "").replace("(", "").replace(")", "").split("\\.")[2];
                                departId = ConvertUtils.getString(paramNameValuePairs.get(sqlSegment)).replace("%", "");
                                break;
                            }
                        }
                    }else {
                    	if(value!=null) {
                    		Field[] fields = value.getClass().getDeclaredFields();
                            for (Field field : fields) {
                                if ("departId".equalsIgnoreCase(field.getName())){
                                    field.setAccessible(true);
                                    Object subFieldVal = field.get(value);
                                    field.setAccessible(false);
                                    departId = ConvertUtils.getString(subFieldVal);
                                }
                            }
                    	}
                    }
                }
            }
            MappedStatement ms = (MappedStatement) args[0];
            Object parameterObject = args[1];
            BoundSql boundSql = ms.getBoundSql(parameterObject);
            String sql = boundSql.getSql();
            MySqlStatementParser mySqlStatementParser = new MySqlStatementParser(sql);
            SQLStatement statement = mySqlStatementParser.parseStatement();
            if (statement instanceof SQLSelectStatement) {
                SQLSelect selectQuery = ((SQLSelectStatement) statement).getSelect();
                Object object = selectQuery.getQuery();
                if (!(object instanceof MySqlSelectQueryBlock) && !(object instanceof SQLUnionQuery)) {
                    log.info("没有数据过滤的接口" + sqlId);
                    return invocation.proceed();
                }
                if (object instanceof SQLUnionQuery) {
                    SQLUnionQuery union = (SQLUnionQuery) selectQuery.getQuery();
                    SQLSelectQuery left = union.getLeft();
                    if (left instanceof MySqlSelectQueryBlock) {
                        MySqlSelectQueryBlock leftSqlSelectQuery = (MySqlSelectQueryBlock) union.getLeft();
                        parsingData(leftSqlSelectQuery,sqlId);
                    }
                    SQLSelectQuery right = union.getRight();
                    if (right instanceof MySqlSelectQueryBlock) {
                        MySqlSelectQueryBlock rightSqlSelectQuery = (MySqlSelectQueryBlock) union.getRight();
                        parsingData(rightSqlSelectQuery,sqlId);
                    }
                } else {
                    MySqlSelectQueryBlock sqlSelectQuery = (MySqlSelectQueryBlock) selectQuery.getQuery();
                    parsingData(sqlSelectQuery,sqlId);
                }
            }
            BoundSql bs = new BoundSql(ms.getConfiguration(), statement.toString(), boundSql.getParameterMappings(), parameterObject);
            MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(bs));
            String sql1 = newMs.getBoundSql(parameterObject).getSql();
            for (ParameterMapping mapping : boundSql.getParameterMappings()) {
                String prop = mapping.getProperty();
                if (boundSql.hasAdditionalParameter(prop)) {
                    bs.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
                }
            }
            args[0] = newMs;
            return invocation.proceed();
        }
        if (SqlCommandType.INSERT == sqlCommandType) {
//            if ("com.skua.modules.algorithm.mapper.SysAlgorithmLibraryMapper.insert".equalsIgnoreCase(sqlId)) {
//                return invocation.proceed();
//            }
            Field[] fields = ConvertUtils.getAllFields(parameter);
            for (Field field : fields) {
                log.debug("------field.name------" + field.getName());
                try {
                    // 关于使用Quzrtz 开启线程任务
                    // 获取登录用户信息
                    LoginUser sysUser = null;
                    try {
                        sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
                    } catch (Exception e) {
                        sysUser = null;
                    }
                    if ("createBy".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_createBy = field.get(parameter);
                        field.setAccessible(false);
                        if (local_createBy == null || local_createBy.equals("")) {
                            String createBy = "zhsw";
                            if (sysUser != null) {
                                // 登录账号
                                createBy = sysUser.getUsername();
                            }
                            if (ConvertUtils.isNotEmpty(createBy)) {
                                field.setAccessible(true);
                                field.set(parameter, createBy);
                                field.setAccessible(false);
                            }
                        }
                    }
                    // 注入创建时间
                    if ("createTime".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_createDate = field.get(parameter);
                        field.setAccessible(false);
                        if (local_createDate == null || local_createDate.equals("")) {
                            field.setAccessible(true);
                            field.set(parameter, new Date());
                            field.setAccessible(false);
                        }
                    }
                    //注入部门编码
                    if ("departId".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_sysOrgCode = field.get(parameter);
                        field.setAccessible(false);
                        if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {
                            String sysOrgCode = "";
                            // 获取登录用户信息
                            if (sysUser != null) {
                                // 登录账号
                                sysOrgCode = sysUser.getOrgCode();
                            }
                            if (ConvertUtils.isNotEmpty(sysOrgCode)) {
                                field.setAccessible(true);
                                field.set(parameter, sysOrgCode);
                                field.setAccessible(false);
                            }
                        }
                    }
                    //注入部门编码
                    if ("orgCode".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_sysOrgCode = field.get(parameter);
                        field.setAccessible(false);
                        if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {
                            String sysOrgCode = "";
                            // 获取登录用户信息
                            if (sysUser != null) {
                                // 登录账号
                                sysOrgCode = sysUser.getOrgCode();
                            }
                            if (ConvertUtils.isNotEmpty(sysOrgCode)) {
                                field.setAccessible(true);
                                field.set(parameter, sysOrgCode);
                                field.setAccessible(false);
                            }
                        }
                    }
                    //注入部门编码
                    if ("createDept".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_sysOrgCode = field.get(parameter);
                        field.setAccessible(false);
                        if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {
                            String sysOrgCode = "";
                            // 获取登录用户信息
                            if (sysUser != null) {
                                // 登录账号
                                sysOrgCode = sysUser.getOrgCode();
                            }
                            if (ConvertUtils.isNotEmpty(sysOrgCode)) {
                                field.setAccessible(true);
                                field.set(parameter, sysOrgCode);
                                field.setAccessible(false);
                            }
                        }
                    }
                } catch (Exception e) {
                }
            }
        }
        if (SqlCommandType.UPDATE == sqlCommandType) {
            if ("com.skua.modules.algorithm.mapper.SysAlgorithmLibraryMapper.insert".equalsIgnoreCase(sqlId)) {
                return invocation.proceed();
            }
            Field[] fields = null;
            if (parameter instanceof ParamMap) {
                ParamMap<?> p = (ParamMap<?>) parameter;
                //update-begin-author:scott date:20190729 for:批量更新报错issues/IZA3Q--
                if (p.containsKey("et")) {
                    parameter = p.get("et");
                } else {
                    parameter = p.get("param1");
                }
                //update-end-author:scott date:20190729 for:批量更新报错issues/IZA3Q-
                fields = ConvertUtils.getAllFields(parameter);
            } else {
                fields = ConvertUtils.getAllFields(parameter);
            }
            for (Field field : fields) {
                log.debug("------field.name------" + field.getName());
                try {
                    if ("updateBy".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_updateBy = field.get(parameter);
                        field.setAccessible(false);
                        if (local_updateBy == null || local_updateBy.equals("")) {
                            String updateBy = "zhsw";
                            // 获取登录用户信息
                            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
                            if (sysUser != null) {
                                // 登录账号
                                updateBy = sysUser.getUsername();
                            }
                            if (ConvertUtils.isNotEmpty(updateBy)) {
                                field.setAccessible(true);
                                field.set(parameter, updateBy);
                                field.setAccessible(false);
                            }
                        }
                    }
                    if ("updateTime".equals(field.getName())) {
                        field.setAccessible(true);
                        Object local_updateDate = field.get(parameter);
                        field.setAccessible(false);
                        if (local_updateDate == null || local_updateDate.equals("")) {
                            field.setAccessible(true);
                            field.set(parameter, new Date());
                            field.setAccessible(false);
                        }
                    }
                } catch (Exception e) {
                }
            }
        }
        return invocation.proceed();
    }

    private void parsingData(MySqlSelectQueryBlock sqlSelectQuery,String sqlId) {
        Object whereSql = sqlSelectQuery.getWhere();
        //解析查询条件中的depart_id
        if (whereSql instanceof SQLBinaryOpExpr && !queryCriteriaDepartIdList.contains(sqlId)) {
            SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) whereSql;
            boolean flag =  queryCriteriaDepartId(sqlBinaryOpExpr);
            if (!flag){
                //创建新的in查询对象
//                SQLIdentifierExpr leftSQLIdentifierExpr = (SQLIdentifierExpr) left;
                SQLInListExpr sqlInListExpr = new SQLInListExpr();
                SQLIdentifierExpr sqlIdentifierExpr = new SQLIdentifierExpr();
                sqlIdentifierExpr.setName("depart_id");
                sqlIdentifierExpr.setParent(sqlInListExpr);
                sqlInListExpr.setExpr(sqlIdentifierExpr);
                sqlInListExpr.setNot(false);
                MySqlSelectQueryBlock parent = (MySqlSelectQueryBlock) sqlBinaryOpExpr.getParent();
                List<SQLExpr> targetList = new ArrayList<>();
                //根据departId参数,查询所有子节点数据
                SysDepartServiceImpl sysDepartServiceImpl = (SysDepartServiceImpl) SpringContextUtils.getBean("sysDepartServiceImpl");
                String[] departIds = sysDepartServiceImpl.getDepartTreeByParentDepartId(departId).split(",");
//                    String[] departIds = "af880d6a13404a67825e94bc0f2f3808,1543780351254511616,160e79b3d3944427af74e9fb405c93d2,8d949c6d09404aed9f558d1cdb11c45f,1519193830953553920,1519200041706954752,596a8645df454fe19e235eb278aaecfe,5c092853642f4ac8a7ba7861d349237b,1519201350841507840,930de267768a4ad1a668b786ac43f767,9c9c66915a2a4e95b5d2bae5555fb4c5,1543847167490277376".split(",");
                //将departIds传入targetList对象中
                SQLVariantRefExpr sqlVariantRefExpr;
                for (int i = 0; i < departIds.length; i++) {
                    sqlVariantRefExpr = new SQLVariantRefExpr();
                    if (i == 0) {
                        sqlVariantRefExpr.setName("?");
                    } else {
                        sqlVariantRefExpr.setName("'" + departIds[i] + "'");
                    }
                    sqlVariantRefExpr.setGlobal(false);
                    sqlVariantRefExpr.setSession(false);
                    sqlVariantRefExpr.setIndex(i);
                    sqlVariantRefExpr.setParent(sqlInListExpr);
                    targetList.add(sqlVariantRefExpr);
                }
//                        queryCriteriaDepartIdParentRef(parent, sqlInListExpr);
                sqlInListExpr.setTargetList(targetList);
                sqlInListExpr.setParent(parent);
                sqlSelectQuery.setWhere(sqlInListExpr);
            }
        }
        Object object = sqlSelectQuery.getFrom();
        if (object instanceof SQLJoinTableSource) {
            parsingDataSQLJoinTableSource((SQLJoinTableSource) object,sqlId);
        }
        if (object instanceof SQLExprTableSource) {
            replaceTableName((SQLExprTableSource) object);
        }
    }

    private boolean queryCriteriaDepartId(SQLBinaryOpExpr sqlBinaryOpExpr) {
        Object left = sqlBinaryOpExpr.getLeft();
        if (left instanceof SQLBinaryOpExpr) {
            if (((SQLBinaryOpExpr) left).getLeft() instanceof SQLPropertyExpr){
                SQLPropertyExpr leftSQLPropertyExpr = (SQLPropertyExpr)((SQLBinaryOpExpr) left).getLeft();
                String key = leftSQLPropertyExpr.getName();
                if ("depart_id".equalsIgnoreCase(key)) {
                    SQLBinaryOperator sqlBinaryOpExprOperator = sqlBinaryOpExpr.getOperator();
                    Object rightObject = sqlBinaryOpExpr.getRight();
                    //连接条件不为like或者连接条件为like且类型为SQLVariantRefExpr
                    if (!("like".equalsIgnoreCase(sqlBinaryOpExprOperator.getName())) || ("like".equalsIgnoreCase(sqlBinaryOpExprOperator.getName()) && rightObject instanceof SQLVariantRefExpr)) {
                        //创建新的in查询对象
                        SQLInListExpr sqlInListExpr = new SQLInListExpr();
                        sqlInListExpr.setExpr(leftSQLPropertyExpr);
                        sqlInListExpr.setNot(false);
                        if (sqlBinaryOpExpr.getParent() instanceof SQLBinaryOpExpr) {
                            SQLBinaryOpExpr parent = (SQLBinaryOpExpr) sqlBinaryOpExpr.getParent();
                            List<SQLExpr> targetList = new ArrayList<>();
                            //根据departId参数,查询所有子节点数据
                            SysDepartServiceImpl sysDepartServiceImpl = (SysDepartServiceImpl) SpringContextUtils.getBean("sysDepartServiceImpl");
                            String[] departIds = sysDepartServiceImpl.getDepartTreeByParentDepartId(departId).split(",");
//                    String[] departIds = "af880d6a13404a67825e94bc0f2f3808,1543780351254511616,160e79b3d3944427af74e9fb405c93d2,8d949c6d09404aed9f558d1cdb11c45f,1519193830953553920,1519200041706954752,596a8645df454fe19e235eb278aaecfe,5c092853642f4ac8a7ba7861d349237b,1519201350841507840,930de267768a4ad1a668b786ac43f767,9c9c66915a2a4e95b5d2bae5555fb4c5,1543847167490277376".split(",");
                            //将departIds传入targetList对象中
                            SQLVariantRefExpr sqlVariantRefExpr;
                            for (int i = 0; i < departIds.length; i++) {
                                sqlVariantRefExpr = new SQLVariantRefExpr();
                                if (i == 0) {
                                    sqlVariantRefExpr.setName("?");
                                } else {
                                    sqlVariantRefExpr.setName("'" + departIds[i] + "'");
                                }
                                sqlVariantRefExpr.setGlobal(false);
                                sqlVariantRefExpr.setSession(false);
                                sqlVariantRefExpr.setIndex(i);
                                sqlVariantRefExpr.setParent(sqlInListExpr);
                                targetList.add(sqlVariantRefExpr);
                            }
                            queryCriteriaDepartIdParentRef(parent, sqlInListExpr);
                            sqlInListExpr.setTargetList(targetList);
                            sqlBinaryOpExpr.setParent(parent);
                            queryCriteriaDepartIdRef(sqlBinaryOpExpr,sqlInListExpr);
                        } else if (sqlBinaryOpExpr.getParent() instanceof MySqlSelectQueryBlock) {
                            return false;
                        }
                    }
                }
            }else {
                queryCriteriaDepartId((SQLBinaryOpExpr) left);
            }
        }
        if (left instanceof SQLIdentifierExpr) {
            SQLIdentifierExpr leftSQLIdentifierExpr = (SQLIdentifierExpr) left;
            String key = leftSQLIdentifierExpr.getName();
            if ("depart_id".equalsIgnoreCase(key)) {
                SQLBinaryOperator sqlBinaryOpExprOperator = sqlBinaryOpExpr.getOperator();
                Object rightObject = sqlBinaryOpExpr.getRight();
                //连接条件不为like或者连接条件为like且类型为SQLVariantRefExpr
                if (!("like".equalsIgnoreCase(sqlBinaryOpExprOperator.getName())) || ("like".equalsIgnoreCase(sqlBinaryOpExprOperator.getName()) && rightObject instanceof SQLVariantRefExpr)) {
                    //创建新的in查询对象
                    SQLInListExpr sqlInListExpr = new SQLInListExpr();
                    sqlInListExpr.setExpr(leftSQLIdentifierExpr);
                    sqlInListExpr.setNot(false);
                    if (sqlBinaryOpExpr.getParent() instanceof SQLBinaryOpExpr) {
                        SQLBinaryOpExpr parent = (SQLBinaryOpExpr) sqlBinaryOpExpr.getParent();
                        List<SQLExpr> targetList = new ArrayList<>();
                        //根据departId参数,查询所有子节点数据
                        SysDepartServiceImpl sysDepartServiceImpl = (SysDepartServiceImpl) SpringContextUtils.getBean("sysDepartServiceImpl");
                        String[] departIds = sysDepartServiceImpl.getDepartTreeByParentDepartId(departId).split(",");
//                    String[] departIds = "af880d6a13404a67825e94bc0f2f3808,1543780351254511616,160e79b3d3944427af74e9fb405c93d2,8d949c6d09404aed9f558d1cdb11c45f,1519193830953553920,1519200041706954752,596a8645df454fe19e235eb278aaecfe,5c092853642f4ac8a7ba7861d349237b,1519201350841507840,930de267768a4ad1a668b786ac43f767,9c9c66915a2a4e95b5d2bae5555fb4c5,1543847167490277376".split(",");
                        //将departIds传入targetList对象中
                        SQLVariantRefExpr sqlVariantRefExpr;
                        for (int i = 0; i < departIds.length; i++) {
                            sqlVariantRefExpr = new SQLVariantRefExpr();
                            if (i == 0) {
                                sqlVariantRefExpr.setName("?");
                            } else {
                                sqlVariantRefExpr.setName("'" + departIds[i] + "'");
                            }
                            sqlVariantRefExpr.setGlobal(false);
                            sqlVariantRefExpr.setSession(false);
                            sqlVariantRefExpr.setIndex(i);
                            sqlVariantRefExpr.setParent(sqlInListExpr);
                            targetList.add(sqlVariantRefExpr);
                        }
                        queryCriteriaDepartIdParentRef(parent, sqlInListExpr);
                        sqlInListExpr.setTargetList(targetList);
                        sqlBinaryOpExpr.setParent(parent);
                        sqlBinaryOpExpr.setRight(sqlInListExpr);
                    }else if (sqlBinaryOpExpr.getParent() instanceof MySqlSelectQueryBlock){
                        return false;
                    }
                }
            }
        }
        if (left instanceof SQLInListExpr && !StringUtils.isBlank(departId)) {
            SQLInListExpr leftSQLInListExpr = (SQLInListExpr) left;
            List<SQLExpr> targetList = leftSQLInListExpr.getTargetList();
            if (targetList.size() == 1) {
                SysDepartServiceImpl sysDepartServiceImpl = (SysDepartServiceImpl) SpringContextUtils.getBean("sysDepartServiceImpl");
                String[] departIds = sysDepartServiceImpl.getDepartTreeByParentDepartId(departId).split(",");
                SQLInListExpr sqlInListExpr = (SQLInListExpr) targetList.get(0).getParent();
                SQLVariantRefExpr sqlVariantRefExpr;
                for (int i = 0; i < departIds.length; i++) {
                    sqlVariantRefExpr = new SQLVariantRefExpr();
                    sqlVariantRefExpr.setName("'" + departIds[i] + "'");
                    sqlVariantRefExpr.setGlobal(false);
                    sqlVariantRefExpr.setSession(false);
                    sqlVariantRefExpr.setIndex(i);
                    sqlVariantRefExpr.setParent(sqlInListExpr);
                    targetList.add(sqlVariantRefExpr);
                }
            }

        }

        Object right = sqlBinaryOpExpr.getRight();
        if (right instanceof SQLBinaryOpExpr) {
            queryCriteriaDepartId((SQLBinaryOpExpr) right);
        }
        if (right instanceof SQLIdentifierExpr) {
            SQLIdentifierExpr rightSQLIdentifierExpr = (SQLIdentifierExpr) right;
            String key = rightSQLIdentifierExpr.getName();
            if ("depart_id".equalsIgnoreCase(key)) {
                SQLBinaryOperator sqlBinaryOpExprOperator = sqlBinaryOpExpr.getOperator();
                Object rightObject = sqlBinaryOpExpr.getRight();
                if (!("like".equalsIgnoreCase(sqlBinaryOpExprOperator.getName())) || ("like".equalsIgnoreCase(sqlBinaryOpExprOperator.getName()) && rightObject instanceof SQLVariantRefExpr)) {
                    SQLInListExpr sqlInListExpr = new SQLInListExpr();
                    sqlInListExpr.setExpr(rightSQLIdentifierExpr);
                    sqlInListExpr.setNot(false);
                    SQLBinaryOpExpr parent = (SQLBinaryOpExpr) sqlBinaryOpExpr.getParent();
                    List<SQLExpr> targetList = new ArrayList<>();
                    SysDepartServiceImpl sysDepartServiceImpl = (SysDepartServiceImpl) SpringContextUtils.getBean("sysDepartServiceImpl");
                    String[] departIds = sysDepartServiceImpl.getDepartTreeByParentDepartId(departId).split(",");
//                    String[] departIds = "af880d6a13404a67825e94bc0f2f3808,1543780351254511616,160e79b3d3944427af74e9fb405c93d2,8d949c6d09404aed9f558d1cdb11c45f,1519193830953553920,1519200041706954752,596a8645df454fe19e235eb278aaecfe,5c092853642f4ac8a7ba7861d349237b,1519201350841507840,930de267768a4ad1a668b786ac43f767,9c9c66915a2a4e95b5d2bae5555fb4c5,1543847167490277376".split(",");
                    SQLVariantRefExpr sqlVariantRefExpr;
                    for (int i = 0; i < departIds.length; i++) {
                        sqlVariantRefExpr = new SQLVariantRefExpr();
                        if (i == 0) {
                            sqlVariantRefExpr.setName("?");
                        } else {
                            sqlVariantRefExpr.setName("'" + departIds[i] + "'");
                        }
                        sqlVariantRefExpr.setGlobal(false);
                        sqlVariantRefExpr.setSession(false);
                        sqlVariantRefExpr.setIndex(i);
                        sqlVariantRefExpr.setParent(sqlInListExpr);
                        targetList.add(sqlVariantRefExpr);
                    }
                    queryCriteriaDepartIdParentRef(parent, sqlInListExpr);
                    sqlInListExpr.setTargetList(targetList);
                    sqlBinaryOpExpr.setParent(parent);
                    sqlBinaryOpExpr.setRight(sqlInListExpr);
                }
            }
        }
        if (right instanceof SQLInListExpr && !StringUtils.isBlank(departId)) {
            SQLInListExpr rightSQLInListExpr = (SQLInListExpr) right;
            List<SQLExpr> targetList = rightSQLInListExpr.getTargetList();
            if (targetList.size() == 1) {
                SysDepartServiceImpl sysDepartServiceImpl = (SysDepartServiceImpl) SpringContextUtils.getBean("sysDepartServiceImpl");
                String[] departIds = sysDepartServiceImpl.getDepartTreeByParentDepartId(departId).split(",");
                SQLInListExpr sqlInListExpr = (SQLInListExpr) targetList.get(0).getParent();
                SQLVariantRefExpr sqlVariantRefExpr;
                for (int i = 0; i < departIds.length; i++) {
                    sqlVariantRefExpr = new SQLVariantRefExpr();
                    sqlVariantRefExpr.setName("'" + departIds[i] + "'");
                    sqlVariantRefExpr.setGlobal(false);
                    sqlVariantRefExpr.setSession(false);
                    sqlVariantRefExpr.setIndex(i);
                    sqlVariantRefExpr.setParent(sqlInListExpr);
                    targetList.add(sqlVariantRefExpr);
                }
            }

        }
        return true;
    }

    //将新创建的SQLInListExpr传入到对象中
    public void queryCriteriaDepartIdRef(SQLBinaryOpExpr sqlBinaryOpExpr, SQLInListExpr sqlInListExpr) {
        Object left = ((SQLBinaryOpExpr) sqlBinaryOpExpr.getLeft()).getLeft();
        if (left instanceof SQLBinaryOpExpr) {
            queryCriteriaDepartIdRef((SQLBinaryOpExpr)left, sqlInListExpr);
        } else if (left instanceof SQLIdentifierExpr) {
            if ("depart_id".equalsIgnoreCase(((SQLIdentifierExpr) left).getName())) {
                sqlBinaryOpExpr.setLeft(sqlInListExpr);
            }
        } else if (left instanceof SQLPropertyExpr){
            if ("depart_id".equalsIgnoreCase(((SQLPropertyExpr) left).getName())) {
                sqlBinaryOpExpr.setLeft(sqlInListExpr);
            }
        }
        Object right = ((SQLBinaryOpExpr) sqlBinaryOpExpr.getRight()).getLeft();
        if (right instanceof SQLBinaryOpExpr) {
            queryCriteriaDepartIdRef((SQLBinaryOpExpr) right, sqlInListExpr);
        } else if (right instanceof SQLIdentifierExpr) {
            if ("depart_id".equalsIgnoreCase(((SQLIdentifierExpr) right).getName())) {
                sqlBinaryOpExpr.setRight(sqlInListExpr);
            }
        } else if (right instanceof SQLPropertyExpr) {
            if ("depart_id".equalsIgnoreCase(((SQLPropertyExpr) right).getName())) {
                sqlBinaryOpExpr.setRight(sqlInListExpr);
            }
        }
    }

    //将新创建的SQLInListExpr传入到parent对象中
    public void queryCriteriaDepartIdParentRef(SQLBinaryOpExpr parent, SQLInListExpr sqlInListExpr) {
        Object left = ((SQLBinaryOpExpr) parent.getLeft()).getLeft();
        if (left instanceof SQLBinaryOpExpr) {
            queryCriteriaDepartIdParentRef((SQLBinaryOpExpr) ((SQLBinaryOpExpr) left).getParent(), sqlInListExpr);
        } else if (left instanceof SQLIdentifierExpr) {
            if ("depart_id".equalsIgnoreCase(((SQLIdentifierExpr) left).getName())) {
                parent.setLeft(sqlInListExpr);
            }
        }
        Object right = ((SQLBinaryOpExpr) parent.getRight()).getLeft();
        if (right instanceof SQLBinaryOpExpr) {
            queryCriteriaDepartIdParentRef((SQLBinaryOpExpr) ((SQLBinaryOpExpr) right).getParent(), sqlInListExpr);
        } else if (right instanceof SQLIdentifierExpr) {
            if ("depart_id".equalsIgnoreCase(((SQLIdentifierExpr) right).getName())) {
                parent.setRight(sqlInListExpr);
            }
        }
    }

    public void parsingDataSQLJoinTableSource(SQLJoinTableSource joinSqlTableSource,String sqlId) {
        try {
            Object leftObject = joinSqlTableSource.getLeft();
            if (leftObject instanceof SQLJoinTableSource) {
                parsingDataSQLJoinTableSource((SQLJoinTableSource) leftObject,sqlId);
            } else if (leftObject instanceof SQLExprTableSource) {
                replaceTableName((SQLExprTableSource) leftObject);
            } else if (leftObject instanceof SQLSubqueryTableSource) {
                SQLSubqueryTableSource sqlSubqueryTableSource = (SQLSubqueryTableSource) leftObject;
                MySqlSelectQueryBlock mySqlSelectQueryBlock = (MySqlSelectQueryBlock) sqlSubqueryTableSource.getSelect().getQuery();
                parsingData(mySqlSelectQueryBlock,sqlId);
            } else if (leftObject instanceof SQLUnionQueryTableSource) {
                SQLUnionQueryTableSource sqlTableSourceLeft = (SQLUnionQueryTableSource) leftObject;
                SQLUnionQuery union = sqlTableSourceLeft.getUnion();
                MySqlSelectQueryBlock leftSqlSelectQuery = (MySqlSelectQueryBlock) union.getLeft();
                parsingData(leftSqlSelectQuery,sqlId);
                MySqlSelectQueryBlock rightSqlSelectQuery = (MySqlSelectQueryBlock) union.getRight();
                parsingData(rightSqlSelectQuery,sqlId);
            }
            Object rightObject = joinSqlTableSource.getRight();
            if (rightObject instanceof SQLExprTableSource) {
                SQLExprTableSource rightSqlTableSource = (SQLExprTableSource) rightObject;
                replaceTableName(rightSqlTableSource);
            } else if (rightObject instanceof SQLSubqueryTableSource) {
                SQLSubqueryTableSource sqlSubqueryTableSource = (SQLSubqueryTableSource) rightObject;
                MySqlSelectQueryBlock mySqlSelectQueryBlock = (MySqlSelectQueryBlock) sqlSubqueryTableSource.getSelect().getQuery();
                parsingData(mySqlSelectQueryBlock,sqlId);
            } else {
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Object object = joinSqlTableSource.getLeft();
        if (object instanceof SQLJoinTableSource) {
            parsingDataSQLJoinTableSource((SQLJoinTableSource) object,sqlId);
        }
        if (object instanceof SQLExprTableSource) {
            replaceTableName((SQLExprTableSource) object);
        }
    }


    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
    }

    private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {
            builder.keyProperty(ms.getKeyProperties()[0]);
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }

    public static class BoundSqlSqlSource implements SqlSource {
        private BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }

    /**
     * 表名替换
     *
     * @return
     */
    private void replaceTableName(SQLExprTableSource sqlTableSource) {
        String tableName = sqlTableSource.toString();
        String alias = sqlTableSource.getAlias();
        //循环判断tableNames中是否含有departId或者departId的字段
        //主库数据源
        JdbcTemplate masterDB = (JdbcTemplate) SpringContextUtils.getBean("master");
        String querySql = "select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ? and COLUMN_NAME = ? ";
        String departIds = BaseContextHandler.getDeparts();
        if (!StringUtils.isBlank(departIds) && !tableNameList.contains(tableName)) {
            String[] departIdArr = departIds.split(",");
            StringBuilder departIdStringBuilder = new StringBuilder();
            for (int i = 0; i < departIdArr.length; i++) {
                departIdStringBuilder.append(",");
                departIdStringBuilder.append("'" + departIdArr[i] + "'");
            }
            String dataBaseSchema = dataBaseUrl.substring(dataBaseUrl.lastIndexOf("/") + 1, dataBaseUrl.indexOf("?"));
            List<Map<String, Object>> list = masterDB.queryForList(querySql, new Object[]{dataBaseSchema, tableName, "depart_id"});

            String columnName = "";
            if ((list != null && list.size() > 0)) {
                Map<String, Object> map = list.get(0);
                if (map.get("COLUMN_NAME") != null) {
                    columnName = map.get("COLUMN_NAME").toString();
                }
            }
            if ("sys_depart".equalsIgnoreCase(tableName)) {
                columnName = "id";
            }
            String newTableNameSql = "(select * from " + tableName + " where " + columnName + " in (" + departIdStringBuilder.toString().replaceFirst(",", "") + "))";
            if (alias == null) {
                newTableNameSql = newTableNameSql + " " + tableName;
            }
            SQLIdentifierExpr sqlExpr = (SQLIdentifierExpr) sqlTableSource.getExpr();
            if (!"".equals(columnName)) {
                sqlExpr.setName(newTableNameSql);
            }
        }
    }




    /***获取匿名注解:Anonymous */
    public Anonymous getAnnotationByAnonymous(MappedStatement mappedStatement){
        Anonymous annotation = null;
        try {
            String id = mappedStatement.getId();
            String className = id.substring(0, id.lastIndexOf("."));
            String methodName = id.substring(id.lastIndexOf(".") + 1);
            final Method[] method = Class.forName(className).getMethods();
            for (Method me : method) {
                if (me.getName().equals(methodName) && me.isAnnotationPresent(Anonymous.class)) {
                    return me.getAnnotation(Anonymous.class);
                }
            }
        } catch (Exception ex) {
            log.error("", ex);
        }
        return annotation;
    }

}