summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
blob: 1fb2709380aa52858a026347ec2a14c710a84a64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
 * @since 2020-08-26
 */
package sevenUnitsGUI;

import java.util.List;
import java.util.function.Predicate;

import sevenUnits.unit.Metric;
import sevenUnits.unit.UnitPrefix;

/**
 * A rule that specifies whether prefix repetition is allowed
 *
 * @since 2020-08-26
 */
public enum DefaultPrefixRepetitionRule implements Predicate<List<UnitPrefix>> {
	NO_REPETITION {
		@Override
		public boolean test(List<UnitPrefix> prefixes) {
			return prefixes.size() <= 1;
		}
	},
	NO_RESTRICTION {
		@Override
		public boolean test(List<UnitPrefix> prefixes) {
			return true;
		}
	},
	/**
	 * You are allowed to have any number of Yotta/Yocto followed by possibly one
	 * Kilo-Zetta/Milli-Zepto followed by possibly one Deca/Hecto. Same for
	 * reducing prefixes, don't mix magnifying and reducing. Non-metric
	 * (including binary) prefixes can't be repeated.
	 */
	COMPLEX_REPETITION {
		@Override
		public boolean test(List<UnitPrefix> prefixes) {
			// determine whether we are magnifying or reducing
			final boolean magnifying;
			if (prefixes.isEmpty())
				return true;
			else if (prefixes.get(0).getMultiplier() > 1) {
				magnifying = true;
			} else {
				magnifying = false;
			}

			// if the first prefix is non-metric (including binary prefixes),
			// assume we are using non-metric prefixes
			// non-metric prefixes are allowed, but can't be repeated.
			if (!Metric.DECIMAL_PREFIXES.contains(prefixes.get(0)))
				return NO_REPETITION.test(prefixes);

			int part = 0; // 0=yotta/yoctos, 1=kilo-zetta/milli-zepto,
								// 2=deka,hecto,deci,centi

			for (final UnitPrefix prefix : prefixes) {
				// check that the current prefix is metric and appropriately
				// magnifying/reducing
				if (!Metric.DECIMAL_PREFIXES.contains(prefix))
					return false;
				if (magnifying != prefix.getMultiplier() > 1)
					return false;

				// check if the current prefix is correct
				// since part is set *after* this check, part designates the state
				// of the *previous* prefix
				switch (part) {
				case 0:
					// do nothing, any prefix is valid after a yotta
					break;
				case 1:
					// after a kilo-zetta, only deka/hecto are valid
					if (Metric.THOUSAND_PREFIXES.contains(prefix))
						return false;
					break;
				case 2:
					// deka/hecto must be the last prefix, so this is always invalid
					return false;
				}

				// set part
				if (Metric.YOTTA.equals(prefix) || Metric.YOCTO.equals(prefix)) {
					part = 0;
				} else if (Metric.THOUSAND_PREFIXES.contains(prefix)) {
					part = 1;
				} else {
					part = 2;
				}
			}
			return true;
		}
	};
}