1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.basepom.mojo.propertyhelper.fields;
16
17 import static com.google.common.base.Preconditions.checkState;
18
19 import org.basepom.mojo.propertyhelper.Field;
20 import org.basepom.mojo.propertyhelper.FieldContext;
21 import org.basepom.mojo.propertyhelper.ValueProvider;
22 import org.basepom.mojo.propertyhelper.definitions.NumberDefinition;
23
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.StringJoiner;
27
28 import com.google.common.annotations.VisibleForTesting;
29 import com.google.common.base.Joiner;
30 import com.google.common.collect.ImmutableList;
31
32 public final class NumberField extends Field<String, NumberDefinition> {
33
34 private final ValueProvider valueProvider;
35
36
37 private List<NumberElement> numberElements;
38 private List<NumberElement> numberIndex;
39
40 @VisibleForTesting
41 public static NumberField forTesting(NumberDefinition numberDefinition, ValueProvider valueProvider) {
42 return new NumberField(numberDefinition, valueProvider, FieldContext.forTesting());
43 }
44
45 public NumberField(final NumberDefinition fieldDefinition, final ValueProvider valueProvider,
46 FieldContext fieldContext) {
47 super(fieldDefinition, fieldContext);
48
49 this.valueProvider = valueProvider;
50 }
51
52 @Override
53 public String getFieldName() {
54
55
56 return fieldDefinition.getId();
57 }
58
59 @Override
60 @SuppressWarnings("PMD.LambdaCanBeMethodReference")
61 public String getValue() {
62 parse();
63
64 return formatResult(value().map(v -> Long.toString(v))
65 .orElse(valueProvider.getValue().orElse("")));
66 }
67
68 private void parse() {
69 final Optional<String> value = valueProvider.getValue();
70
71 ImmutableList.Builder<NumberElement> numberELementBuilder = ImmutableList.builder();
72 ImmutableList.Builder<NumberElement> numberIndexBuilder = ImmutableList.builder();
73
74 if (value.isPresent()) {
75 String numberValue = value.get();
76 if (!numberValue.isBlank()) {
77 StringBuilder sb = new StringBuilder();
78 int charIndex = 0;
79 boolean number = Character.isDigit(numberValue.charAt(charIndex));
80
81 while (charIndex < numberValue.length()) {
82 char currentChar = numberValue.charAt(charIndex);
83 if (number != Character.isDigit(currentChar)) {
84 var numberElement = new NumberElement(number, sb.toString());
85
86 numberELementBuilder.add(numberElement);
87 if (number) {
88 numberIndexBuilder.add(numberElement);
89 }
90
91 number = !number;
92 sb.setLength(0);
93 }
94 sb.append(currentChar);
95 charIndex++;
96 }
97 if (sb.length() > 0) {
98 var numberElement = new NumberElement(number, sb.toString());
99
100 numberELementBuilder.add(numberElement);
101 if (number) {
102 numberIndexBuilder.add(numberElement);
103 }
104 }
105 }
106 }
107
108 this.numberElements = numberELementBuilder.build();
109 this.numberIndex = numberIndexBuilder.build();
110 }
111
112 private String print() {
113 return Joiner.on("").join(numberElements.stream().map(NumberElement::getFieldValue).iterator());
114 }
115
116 private Optional<Long> value() {
117 return fieldDefinition.getFieldNumber()
118 .map(numberIndex::get)
119 .flatMap(NumberElement::getLongValue);
120 }
121
122 private void set(long value) {
123 Optional<NumberElement> numberElement = fieldDefinition.getFieldNumber()
124 .map(numberIndex::get);
125
126 if (numberElement.isPresent()) {
127 numberElement.get().setLongValue(value);
128 valueProvider.setValue(print());
129 } else {
130 valueProvider.setValue(Long.toString(value));
131 }
132 }
133
134 public void increment() {
135 parse();
136
137 fieldDefinition.getFieldNumber().ifPresent(fieldNumber -> checkState(numberIndex.size() > fieldNumber,
138 "Only %s fields in %s, field %s requested.", numberElements.size(), print(), fieldNumber));
139
140 value().ifPresent(value -> {
141 set(value + fieldDefinition.getIncrement());
142 });
143 }
144
145 public Optional<Long> getNumberValue() {
146 parse();
147
148 fieldDefinition.getFieldNumber().ifPresent(fieldNumber -> checkState(numberIndex.size() > fieldNumber,
149 "Only %s fields in %s, field %s requested.", numberElements.size(), print(), fieldNumber));
150
151 return value();
152 }
153
154 @Override
155 public String toString() {
156 return new StringJoiner(", ", NumberField.class.getSimpleName() + "[", "]")
157 .add("valueProvider=" + valueProvider)
158 .add("numberElements=" + numberElements)
159 .add("numberIndex=" + numberIndex)
160 .add("fieldDefinition=" + fieldDefinition)
161 .toString();
162 }
163
164 private static final class NumberElement {
165
166 private final boolean number;
167 private String value;
168
169 private NumberElement(boolean number, String value) {
170 this.number = number;
171 this.value = value;
172 }
173
174 String getFieldValue() {
175 return value;
176 }
177
178 void setLongValue(long value) {
179 this.value = Long.toString(value);
180 }
181
182 Optional<Long> getLongValue() {
183 return number ? Optional.of(Long.parseLong(value)) : Optional.empty();
184 }
185
186 @Override
187 public String toString() {
188 return new StringJoiner(", ", NumberElement.class.getSimpleName() + "[", "]")
189 .add("number=" + number)
190 .add("value='" + value + "'")
191 .toString();
192 }
193 }
194 }