package com.sinosig.mongodb.util.helper;

import com.sinosig.util.SearchContext;
import com.sinosig.util.SearchFieldFilter;
import com.sinosig.util.SearchFilter;
import com.sinosig.util.SearchGroupFilter;
import com.sinosig.util.enums.SearchFieldType;
import com.sinosig.util.enums.SearchGroupType;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Component
public class MongoDBQueryBuilder {

    /**
     * 解析SearchContext中的field与group，构造mongodb的查询条件
     * @param context 数据查询上下文对象
     * @return   mongodb数据查询对象
     */
    public Criteria buildCriteria(SearchContext context){

        Criteria group_criteria = null;

        List<SearchFilter> conditions=context.getCondition();

        if(conditions.size()==0)
        return new Criteria();

        List<Criteria> criteria_arrayList=new ArrayList<Criteria>();

        for(SearchFilter cond : conditions){

            Criteria criteria = null;

            if(cond instanceof SearchFieldFilter){ //构造字段的查询条件
                criteria=parseFieldCond((SearchFieldFilter) cond);
            }
            else if (cond instanceof SearchGroupFilter){//构造组的查询条件
                criteria=parseGroupCond((SearchGroupFilter) cond);
            }
            if(!ObjectUtils.isEmpty(criteria))
                criteria_arrayList.add(criteria);
        }

        if(criteria_arrayList.size()>0){
            Criteria[] criteria_array = criteria_arrayList.toArray(new Criteria[criteria_arrayList.size()]);//构造mongo查询条件的Criteria数组
            group_criteria=new Criteria().andOperator(criteria_array);//Criteria数组中各条件使用and条件拼接
        }
        return group_criteria;
    }

    /**
     * 字段条件解析
     * @param field 字段型数据查询上下文对象
     * @return  mongodb数据查询对象
     */
    private Criteria parseFieldCond(SearchFieldFilter field){

        Criteria criteria = null;
        Pattern pattern;
        String param=field.getParam();
        SearchFieldType cond=field.getCondition();
        Object value=field.getValue();

        if(StringUtils.isEmpty(param)|| StringUtils.isEmpty(cond))
            return new Criteria();

        switch (cond){
            case GT:
                criteria=Criteria.where(param).gt(value); break;
            case GTANDEQ:
                criteria=Criteria.where(param).gte(value);break;
            case EQ:
                criteria=Criteria.where(param).is(value); break;
            case NOTEQ:
                criteria=Criteria.where(param).not().is(value); break;
            case LT:
                criteria=Criteria.where(param).lt(value); break;
            case LTANDEQ:
                criteria=Criteria.where(param).lte(value); break;
            case LIKE:
                pattern= Pattern.compile(String.format("^.*%1$s.*$",value), Pattern.CASE_INSENSITIVE);
                criteria=Criteria.where(param).regex(pattern); break;
            case LEFTLIKE:
                pattern= Pattern.compile(String.format("^%1$s.*$",value), Pattern.CASE_INSENSITIVE);
                criteria=Criteria.where(param).regex(pattern); break;
            case RIGHTLIKE:
                pattern= Pattern.compile(String.format("^.*%1$s$",value), Pattern.CASE_INSENSITIVE);
                criteria=Criteria.where(param).regex(pattern); break;
            case ISNULL:
                criteria=Criteria.where(param).is(""); break;
            case ISNOTNULL:
                criteria=Criteria.where(param).not().is(""); break;
            case IN:
                if(value instanceof List){
                    criteria=Criteria.where(param).in(value); break;
                }
                break;
            case NOTIN:
                if(value instanceof List){
                    criteria=Criteria.where(param).not().in(value); break;
                }
        }
        return criteria;
    }

    /**
     * 组条件解析
     * @param group 组合型数据查询上下文对象
     * @return mongodb数据查询对象
     */
    private Criteria parseGroupCond(SearchGroupFilter group){

        Criteria group_criteria = null;
        List<SearchFilter> groupCond=group.getCondition();//组内条件
        SearchGroupType groupType=group.getSearchGroupType();//组内条件的组合关系(AND/OR)
        if(groupCond.size()==0 || StringUtils.isEmpty(groupType))
            return new Criteria();

        List<Criteria> criteria_arrayList=new ArrayList<Criteria>();

        for(SearchFilter cond : groupCond){

            Criteria criteria = null;

            if(cond instanceof SearchFieldFilter){ //单条件查询
                criteria=parseFieldCond((SearchFieldFilter) cond);
            }
            else if (cond instanceof SearchGroupFilter){//组条件查询
                criteria=parseGroupCond((SearchGroupFilter) cond);
            }
            if(!ObjectUtils.isEmpty(criteria))
                criteria_arrayList.add(criteria);
        }

        if(criteria_arrayList.size()>0){

            Criteria[] criteria_array = criteria_arrayList.toArray(new Criteria[criteria_arrayList.size()]);

            switch(groupType){
                case AND:
                    group_criteria=new Criteria().andOperator(criteria_array);break;
                case OR:
                    group_criteria=new Criteria().orOperator(criteria_array);break;
            }
        }
        return group_criteria;
    }





}
