/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008 jOpenDocument, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU
* General Public License Version 3 only ("GPL").
* You may not use this file except in compliance with the License.
* You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html
* See the License for the specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*
*/
package org.jopendocument.dom;
import org.jopendocument.util.Tuple2;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Units of length.
*
* @author Sylvain CUAZ
*/
public enum LengthUnit {
/**
* The millimetre.
*/
MM("mm", BigDecimal.ONE),
/**
* The centimetre.
*/
CM("cm", BigDecimal.TEN),
/**
* The inch.
*/
INCH("in", new BigDecimal("25.4"));
private final String symbol;
private final BigDecimal multiplier;
private LengthUnit(final String abbr, BigDecimal multiplier) {
this.symbol = abbr;
this.multiplier = multiplier;
}
/**
* The symbol for this unit of length.
*
* @return the symbol, eg "cm".
*/
public final String getSymbol() {
return this.symbol;
}
/**
* Convert from this unit to another.
*
* @param d a length, eg 1.
* @param other another unit, eg {@link #CM}.
* @return the {@link RoundingMode#HALF_UP rounded} result, eg 2.54 if this is {@link #INCH}
*/
public final BigDecimal convertTo(final BigDecimal d, LengthUnit other) {
if (this == other) {
return d;
} else {
return d.multiply(this.multiplier).divide(other.multiplier, RoundingMode.HALF_UP);
}
}
public static final LengthUnit fromSymbol(final String s) {
for (final LengthUnit lu : values())
if (lu.symbol.equals(s))
return lu;
return null;
}
// defined as positiveLength in relaxNG, eg 15.2cm
private static final Pattern lenghPattern = Pattern.compile("(\\d+(\\.\\d+)?)(\\p{Alpha}+)?");
// 0: value, eg 15 ; 1: unit, eg "cm" or null
private static final String[] parseLength2String(String l) {
final Matcher m = lenghPattern.matcher(l);
if (!m.matches())
throw new IllegalStateException("unable to parse " + l);
return new String[] { m.group(1), m.group(3) };
}
public static final Tuple2<BigDecimal, LengthUnit> parseLength(final String l) {
if (l == null)
return null;
final String[] valAndUnit = parseLength2String(l);
final LengthUnit unit = LengthUnit.fromSymbol(valAndUnit[1]);
if (unit == null)
throw new IllegalStateException("unknown unit " + unit);
return Tuple2.create(new BigDecimal(valAndUnit[0]), unit);
}
/**
* Parse a length.
*
* @param l the length, can be <code>null</code>, e.g. "2.0cm".
* @param to the result unit, e.g. {@link LengthUnit#MM}.
* @return the parsed length, <code>null</code> if <code>l</code> is, e.g. 20.
*/
public static final BigDecimal parseLength(final String l, final LengthUnit to) {
if (l == null)
return null;
final Tuple2<BigDecimal, LengthUnit> valAndUnit = LengthUnit.parseLength(l);
return valAndUnit.get1().convertTo(valAndUnit.get0(), to);
}
}