/*
* Copyright (C) 2012 Jan Pokorsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.cas.lib.proarc.webapp.shared.series;
import java.util.Iterator;
/**
* Roman numerals.
*
* @author Jan Pokorsky
*/
final class RomanSeries implements Iterator<String>, Iterable<String> {
private final int start;
private final int increment;
private Integer current;
private final boolean uppercase;
public RomanSeries(String startAsRoman, int increment, boolean uppercase) {
this(Roman.toArabic(startAsRoman), increment, uppercase);
}
public RomanSeries(int start, int increment, boolean uppercase) {
if (start < 1) {
throw new IllegalArgumentException("start < 1: " + start);
}
this.start = start;
this.increment = increment;
this.uppercase = uppercase;
}
@Override
public String next() {
if (current == null) {
current = start;
} else {
current += increment;
}
return current > 0
? Roman.toRoman(current, uppercase)
: null;
}
@Override
public boolean hasNext() {
return true;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<String> iterator() {
return current == null ? this : new RomanSeries(start, increment, uppercase);
}
enum Roman {
M(1000), CM(900), D(500), CD(400), C(100), XC(90), L(50), XL(40),
X(10), IX(9), V(5), IV(4), I(1);
private final int decimal;
Roman(int decimal) {
this.decimal = decimal;
}
public int getDecimal() {
return decimal;
}
public static String toRoman(int decimalValue) {
return toRoman(decimalValue, true);
}
public static String toRoman(int decimalValue, boolean upperCase) {
if (decimalValue < 1) {
throw new IllegalArgumentException("decimalValue: " + decimalValue);
}
StringBuilder result = new StringBuilder();
for (Roman roman : values()) {
int i = decimalValue / roman.getDecimal();
for (int j = 0; j < i; j++) {
result.append(upperCase ? roman.name() : roman.name().toLowerCase());
}
decimalValue %= roman.getDecimal();
}
return result.toString();
}
public static int toArabic(String romanValue) {
if (!Series.validRoman(romanValue)) {
throw new IllegalArgumentException("romanValue: " + romanValue);
}
romanValue = romanValue.toUpperCase();
int arabic = 0;
Roman next = null;
for (int i = 0; i < romanValue.length(); i++) {
Roman current = (next == null)
? Roman.valueOf(String.valueOf(romanValue.charAt(i)))
: next;
next = (i + 1 < romanValue.length())
? Roman.valueOf(String.valueOf(romanValue.charAt(i + 1)))
: null;
if (next == null || current.getDecimal() >= next.getDecimal()) {
arabic += current.getDecimal();
} else {
current = Roman.valueOf(current.name() + next.name());
arabic += current.getDecimal();
next = null;
i++;
}
}
return arabic;
}
}
}