/** * Copyright (C) 2020, 2022, 2024, 2025 Adrien Hopkins * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ 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 * @since v0.3.0 */ public enum DefaultPrefixRepetitionRule implements Predicate> { /** Prefix repetition is never allowed; only one prefix may be used. */ NO_REPETITION { @Override public boolean test(List prefixes) { return prefixes.size() <= 1; } }, /** Prefix repetition is always allowed, without restrictions. */ NO_RESTRICTION { @Override public boolean test(List 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 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; } }; }