package com.persagy.dmp.common.utils;

import cn.hutool.core.collection.CollUtil;
import com.persagy.dmp.common.model.data.RegionValue;

import java.util.List;

/**
 * 区间 工具类
 * 暂时提供判断包含方法，后续再扩展相交、相连、取交集、取并集、取最小开始、取最大结束等区间工具方法
 * @author Charlie Yu
 * @date 2021-07-12
 */
public class RegionUtil {

    /**
     * 是否包含
     * @param region 区间 - 为空表示不限制
     * @param value 待比较数据
     * @return value是否在region范围内
     */
    public static <T extends Comparable> boolean contain(RegionValue<T> region, T value) {
        if(region == null || region.isEmpty()) {
            return true;
        }
        if(value == null) {
            return false;
        }
        // 区间有开始
        if(region.getStart() != null) {
            // 值小于区间开始，不包含
            if(value.compareTo(region.getStart()) < 0) {
                return false;
            } else if(value.compareTo(region.getStart()) == 0 && !region.isContainStart()) {
                // 值等于区间开始，但区间不包含开始，不包含
                return false;
            }
        }
        // 区间有结束
        if(region.getEnd() != null) {
            // 值大于区间结束，不包含
            if(value.compareTo(region.getEnd()) > 0) {
                return false;
            } else if(value.compareTo(region.getEnd()) == 0 && !region.isContainEnd()) {
                // 值等于区间结束，但区间不包含结束，不包含
                return false;
            }
        }
        return true;
    }

    /**
     * 是否全部包含
     * @param region 区间 - 为空表示不限制
     * @param valueList 待比较数据
     * @return valueList是否全部在region范围内
     */
    public static <T extends Comparable> boolean containAll(RegionValue<T> region, List<T> valueList) {
        if(region == null || region.isEmpty()) {
            return true;
        }
        if(CollUtil.isEmpty(valueList)) {
            return false;
        }
        for(T value:valueList) {
            if(contain(region, value)) {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 是否全部包含
     * @param regionList 区间列表 - 为空表示不限制
     * @param value 待比较数据
     * @return value是否在regionList范围内
     */
    public static <T extends Comparable> boolean anyContain(List<RegionValue<T>> regionList, T value) {
        if(CollUtil.isEmpty(regionList)) {
            return true;
        }
        if(value == null) {
            return false;
        }
        for(RegionValue<T> region:regionList) {
            if(contain(region, value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否全部包含
     * @param regionList 区间列表 - 为空表示不限制
     * @param valueList 待比较数据
     * @return valueList是否全部在regionList范围内
     */
    public static <T extends Comparable> boolean allContain(List<RegionValue<T>> regionList, List<T> valueList) {
        if(CollUtil.isEmpty(regionList)) {
            return true;
        }
        if(CollUtil.isEmpty(valueList)) {
            return false;
        }
        for(T value:valueList) {
            if(anyContain(regionList, value)) {
                continue;
            }
            // 有一个数据不在区间列表中，就是不符合
            return false;
        }
        return true;
    }

    /**
     * 是否包含
     * @param region 区间 - 为空表示不限制
     * @param value 待比较数据
     * @return value是否在region范围内
     */
    public static <T extends Comparable> boolean contains(RegionValue<T> region, RegionValue<T> value) {
        if(region == null || region.isEmpty()) {
            return true;
        }
        if(value == null || value.isEmpty()) {
            return false;
        }
        // value区间开始为空,region区间有开始，则一定不包含
        if(value.getStart() == null && region.getStart() != null) {
            return false;
        }
        // value区间结束为空，region区间有结束，则一定不包含
        if(value.getEnd() == null && region.getEnd() != null) {
            return false;
        }
        // 到此，value和region只会开始或结束都同时有值
        if(value.getStart() != null) {
            // 开始有值判断
            if(region.getStart().compareTo(value.getStart()) > 0) {
                // region开始在value开始之后则一定不包含
                return false;
            } else if(region.getStart().compareTo(value.getStart()) == 0 && !region.isContainStart() && value.isContainStart()) {
                // 如果region和value开始相同，但region不包含开始,value包含开始，也为不包含
                return false;
            }
        }
        // 结束有值判断
        if(value.getEnd() != null) {
            if(region.getEnd().compareTo(value.getEnd()) < 0) {
                // 开始都为空，那结束一定都不为空,region结束在value结束之前则一定不包含
                return false;
            } else if(region.getEnd().compareTo(value.getEnd()) == 0 && !region.isContainEnd() && value.isContainEnd()) {
                // 如果region和value结束相同，但region不包含结束,value包含结束，也为不包含
                return false;
            }
        }
        return true;
    }

    /**
     * 是否全部包含
     * @param region 区间 - 为空表示不限制
     * @param valueList 待比较数据
     * @return valueList是否全部在region范围内
     */
    public static <T extends Comparable> boolean containsAll(RegionValue<T> region, List<RegionValue<T>> valueList) {
        if(region == null || region.isEmpty()) {
            return true;
        }
        if(CollUtil.isEmpty(valueList)) {
            return false;
        }
        for(RegionValue<T> value:valueList) {
            if(contains(region, value)) {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 是否全部包含
     * @param regionList 区间列表 - 为空表示不限制
     * @param value 待比较数据
     * @return value是否在regionList范围内
     */
    public static <T extends Comparable> boolean anyContains(List<RegionValue<T>> regionList, RegionValue<T> value) {
        if(CollUtil.isEmpty(regionList)) {
            return true;
        }
        if(value == null || value.isEmpty()) {
            return false;
        }
        for(RegionValue<T> region:regionList) {
            if(contains(region, value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否全部包含
     * @param regionList 区间列表 - 为空表示不限制
     * @param valueList 待比较数据
     * @return valueList是否全部在regionList范围内
     */
    public static <T extends Comparable> boolean allContains(List<RegionValue<T>> regionList, List<RegionValue<T>> valueList) {
        if(CollUtil.isEmpty(regionList)) {
            return true;
        }
        if(CollUtil.isEmpty(valueList)) {
            return false;
        }
        for(RegionValue<T> value:valueList) {
            if(anyContains(regionList, value)) {
                continue;
            }
            // 有一个数据不在区间列表中，就是不符合
            return false;
        }
        return true;
    }

}
