package com.github.qinyou.common.interceptor;

import com.github.qinyou.common.constant.Constant;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.StrKit;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 查询过滤器,将前端传递  固定格式字符串参数 解析为查询条件
 * 仅 mysql 下适用,其它数据库自行扩展
 * @author chuang
 */
public class SearchSql implements Interceptor {

    public void intercept(Invocation ai) {
        Controller c = ai.getController();

        // 查询字段前缀
        String prefix = "search_";
        // 获得 查询 参数
        Map<String, Object> searchParams = getParametersStartingWith(c.getRequest(), prefix);

        // 获得 查询 所有的 查询 filter
        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);

        // 根据 filter 获得 wheresql 语句
        String whereSql = buildFilter(filters.values());
        c.setAttr(Constant.SEARCH_SQL, whereSql);

        int pageNumber = c.getParaToInt("page", 1);
        int pageSize = c.getParaToInt("rows", 1);

        //分页参数, 兼容 bootstrap 分页 和 easyui grid 分页
//        int pageNumber;
//        int pageSize;
//        if (StrKit.notBlank(c.getPara("offset"))) {
//            // bootstraptable 分页
//            pageNumber = c.getParaToInt("offset", 0);
//            pageSize = c.getParaToInt("limit", 10);
//            if (pageNumber != 0) {// 获取页数
//                pageNumber = pageNumber / pageSize;
//            }
//            pageNumber += 1;
//        } else {
//            // easyui grid 分页
//            pageNumber = c.getParaToInt("page", 1);
//            pageSize = c.getParaToInt("rows", 1);
//        }

        c.setAttr("pageNumber", pageNumber);
        c.setAttr("pageSize", pageSize);
        ai.invoke();
    }

    /**
     * 取得带相同前缀的Request Parameters, copy from spring WebUtils.
     * 返回的结果的Parameter名已去除前缀.
     */
    private Map<String, Object> getParametersStartingWith(
            HttpServletRequest request, String prefix) {
        Enumeration<String> paramNames = request.getParameterNames();
        Map<String, Object> params = new TreeMap<>();
        if (prefix == null) {
            prefix = "";
        }
        while (paramNames != null && paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            if ("".equals(prefix) || paramName.startsWith(prefix)) {
                String unprefixed = paramName.substring(prefix.length());
                String[] values = request.getParameterValues(paramName);
                //noinspection StatementWithEmptyBody
                if (values == null || values.length == 0) {
                    // Do nothing, no values found at all.
                } else if (values.length > 1) {
                    params.put(unprefixed, values);
                } else {
                    params.put(unprefixed, values[0]);
                }
            }
        }
        return params;
    }

    /**
     * 按属性条件列表创建查询字句
     */
    private String buildFilter(final Collection<SearchFilter> filters) {
        StringBuilder sb = new StringBuilder();
        if (null != filters && filters.size() > 0) {
            for (SearchFilter filter : filters) {
                if (sb.length() > 0) {
                    sb.append(" and ");
                }
                sb.append(filter.fieldName);

                // 此处 可能要根据数据库类型 修改
                switch (filter.operator) {
                    case EQ:
                        sb.append(" ='").append(filter.value).append("'");
                        break;
                    case LIKE:
                        // 默认首尾加 %
                        sb.append(" like ").append("'%").append(filter.value).append("%'");
                        break;
                    case LIKECUST:
                        // * 替换为 %
                        sb.append(" like ").append("'").append(filter.value.toString().replaceAll("\\*","%")).append("'");
                        break;
                    case GT:
                        sb.append(" >'").append(filter.value).append("'");
                        break;
                    case LT:
                        sb.append(" <'").append(filter.value).append("'");
                        break;
                    case GTE:
                        sb.append(" >='").append(filter.value).append("'");
                        break;
                    case LTE:
                        sb.append(" <='").append(filter.value).append("'");
                        break;
                    case GTES:
                        sb.append(" >=").append(filter.value);
                        break;
                    case LTES:
                        sb.append(" <=").append(filter.value);
                        break;
                    case NEQ:
                        sb.append(" !='").append(filter.value).append("'");
                        break;
                    case INN:
                        // in 数字
                        sb.append(" in (").append(filter.value).append("')");
                        break;
                    case INS:
                        // in 字符串
                        sb.append(" in ('").append(filter.value.toString().replaceAll(",", "','")).append("')");
                        break;
                    case IS:
                        // is null
                        sb.append("  is null ");
                        break;
                    case ISNOT:
                        // not is null
                        sb.append("  is not null ");
                        break;
                }
            }
        }
        return sb.toString();
    }
}

class SearchFilter {

    // 查询字段名
    public final String fieldName;
    // 查询字段值
    public final Object value;
    // 查询条件
    public final Operator operator;

    public SearchFilter(String fieldName, Operator operator, Object value) {
        this.fieldName = fieldName;
        this.value = value;
        this.operator = operator;
    }

    /**
     * searchParams中key的格式为OPERATOR_FIELDNAME
     */
    public static Map<String, SearchFilter> parse(Map<String, Object> searchParams) {
        Map<String, SearchFilter> filters = new HashMap<>();

        for (Map.Entry<String, Object> entry : searchParams.entrySet()) {
            // 过滤掉空值
            String key = entry.getKey();
            Object value = entry.getValue();
            if (StrKit.isBlank((String) value)) {
                continue;
            }

            // 拆分operator与field

            String[] names = key.split("_");
            if (names.length < 2) {
                throw new IllegalArgumentException(key + " is not a valid search filter name");
            }

            // field 中可能有查询条件
            String filedName;
            StringBuilder filedNameTemp = new StringBuilder();
            for (int i = 1; i < names.length; i++) {
                filedNameTemp.append(names[i]).append("_");
            }
            if (filedNameTemp.substring(filedNameTemp.length() - 1).equals("_")) {
                filedNameTemp = new StringBuilder(filedNameTemp.substring(0, filedNameTemp.length() - 1));
            }
            filedName = filedNameTemp.toString();

            // 查询条件
            Operator operator = Operator.valueOf(names[0]);

            // 创建searchFilter
            SearchFilter filter = new SearchFilter(filedName, operator, value);

            filters.put(key, filter);
        }

        return filters;
    }

    public enum Operator {
        EQ, LIKE,LIKECUST, GT, LT, GTE, NEQ, LTE, GTES, LTES, INS, INN, IS, ISNOT
    }
}