package com.xiaoleilu.hutool.cron.pattern.matcher;
import java.util.ArrayList;
import java.util.List;
import com.xiaoleilu.hutool.cron.CronException;
import com.xiaoleilu.hutool.cron.pattern.parser.DayOfMonthValueParser;
import com.xiaoleilu.hutool.cron.pattern.parser.ValueParser;
import com.xiaoleilu.hutool.cron.pattern.parser.YearValueParser;
import com.xiaoleilu.hutool.util.CollectionUtil;
import com.xiaoleilu.hutool.util.NumberUtil;
import com.xiaoleilu.hutool.util.StrUtil;
/**
* {@link ValueMatcher} 构建器
* @author Looly
*
*/
public class ValueMatcherBuilder {
/**
* 处理定时任务表达式每个时间字段<br>
* 多个时间使用逗号分隔
*
* @param value 某个时间字段
* @param parser 针对这个时间字段的解析器
* @return List
*/
public static ValueMatcher build(String value, ValueParser parser) {
if (value.length() == 1 && value.equals("*")) {
return new AlwaysTrueValueMatcher();
}
List<Integer> values = parseArray(value, parser);
if (values.size() == 0) {
throw new CronException("Invalid field: [{}]", value);
}
if (parser instanceof DayOfMonthValueParser) {
//考虑每月的天数不同,切存在闰年情况,日匹配单独使用
return new DayOfMonthValueMatcher(values);
}else if(parser instanceof YearValueParser){
//考虑年数字太大,不适合boolean数组,单独使用列表遍历匹配
return new YearValueMatcher(values);
}else {
return new BoolArrayValueMatcher(values);
}
}
/**
* 处理数组形式表达式<br>
* 处理的形式包括:
* <ul>
* <li><strong>a</strong> 或 <strong>*</strong></li>
* <li><strong>a,b,c,d</strong></li>
* </ul>
* @param value 子表达式值
* @param parser 针对这个字段的解析器
* @return 值列表
*/
private static List<Integer> parseArray(String value, ValueParser parser){
final List<Integer> values = new ArrayList<>();
final List<String> parts = StrUtil.split(value, StrUtil.C_COMMA);
for (String part : parts) {
CollectionUtil.addAllIfNotContains(values, parseStep(part, parser));
}
return values;
}
/**
* 处理间隔形式的表达式<br>
* 处理的形式包括:
* <ul>
* <li><strong>a</strong> 或 <strong>*</strong></li>
* <li><strong>a/b</strong> 或 <strong>*/b</strong></li>
* <li><strong>a-b/2</strong></li>
* </ul>
*
* @param value 表达式值
* @param parser 针对这个时间字段的解析器
* @return List
*/
private static List<Integer> parseStep(String value, ValueParser parser) {
List<String> parts = StrUtil.split(value, StrUtil.C_SLASH);
int size = parts.size();
if (size == 1) {// 普通形式
return parseRange(value, parser);
} else if (size == 2) {// 间隔形式
final List<Integer> rangeValues = parseRange(parts.get(0), parser);
int step = parser.parse(parts.get(1));
if (step < 1) {
throw new CronException("Non positive divisor for field: [{}]", value);
}
// 根据定义的间隔值,返回重新生成的时间值列表
List<Integer> values2 = new ArrayList<>();
for (int i = 0; i < rangeValues.size(); i += step) {
values2.add(rangeValues.get(i));
}
return values2;
} else {
throw new CronException("Invalid syntax of field: [{}]", value);
}
}
/**
* 处理表达式中范围表达式 处理的形式包括:
* <ul>
* <li>*</li>
* <li>2</li>
* <li>3-8</li>
* <li>8-3</li>
* <li>3-3</li>
* </ul>
*
* @param value 范围表达式
* @param parser 针对这个时间字段的解析器
* @return List
*/
private static List<Integer> parseRange(String value, ValueParser parser) {
// 全部匹配形式
if (value.length() == 1 && value.equals("*")) {
List<Integer> values = new ArrayList<>();
for (int i = parser.getMin(); i <= parser.getMax(); i++) {
values.add(i);
}
return values;
}
List<String> parts = StrUtil.split(value, '-');
int size = parts.size();
List<Integer> values = new ArrayList<>();
if (size == 1) {// 普通值
values.add(parser.parse(value));
return values;
} else if (size == 2) {// range值
int v1 = parser.parse(parts.get(0));
int v2 = parser.parse(parts.get(1));
if (v1 < v2) {// 正常范围,例如:2-5
NumberUtil.appendRange(v1, v2, values);
} else if (v1 > v2) {// 逆向范围,反选模式,例如:5-2
NumberUtil.appendRange(v1, parser.getMax(), values);
NumberUtil.appendRange(parser.getMin(), v2, values);
} else {// v1 == v2
values.add(v1);
}
} else {
throw new CronException("Invalid syntax of field: [{}]", value);
}
return values;
}
}