SurfaceFormatter.java
/*
* Copyright (C) 2018 Alberto Irurueta Carro (alberto@irurueta.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.irurueta.units;
import java.text.ParseException;
import java.util.Locale;
/**
* Formats and parses surface value and unit.
*/
public class SurfaceFormatter extends MeasureFormatter<Surface, SurfaceUnit> {
/**
* Square millimeter symbol.
*/
public static final String SQUARE_MILLIMETER = "mm²";
/**
* Square centimeter symbol.
*/
public static final String SQUARE_CENTIMETER = "cm²";
/**
* Square meter symbol.
*/
public static final String SQUARE_METER = "m²";
/**
* Square kilometer symbol.
*/
public static final String SQUARE_KILOMETER = "Km²";
/**
* Square inch symbol.
*/
public static final String SQUARE_INCH = "sq in";
/**
* Square foot symbol.
*/
public static final String SQUARE_FOOT = "sq ft";
/**
* Square yard symbol.
*/
public static final String SQUARE_YARD = "sq yd";
/**
* Square mile symbol.
*/
public static final String SQUARE_MILE = "sq mi";
/**
* Centiare symbol.
*/
public static final String CENTIARE = "ca";
/**
* Are symbol.
*/
public static final String ARE = "a";
/**
* Decare symbol.
*/
public static final String DECARE = "daa";
/**
* Hectare symbol.
*/
public static final String HECTARE = "ha";
/**
* Acre symbol.
*/
public static final String ACRE = "acre";
/**
* Constructor.
*/
@SuppressWarnings("WeakerAccess")
public SurfaceFormatter() {
super();
}
/**
* Constructor with locale.
*
* @param locale locale.
* @throws IllegalArgumentException if locale is null.
*/
@SuppressWarnings("WeakerAccess")
public SurfaceFormatter(final Locale locale) {
super(locale);
}
/**
* Copy constructor.
*
* @param formatter input instance to copy from.
* @throws NullPointerException if provided formatter is null.
*/
public SurfaceFormatter(final SurfaceFormatter formatter) {
this(formatter.getLocale());
}
/**
* Determines if two distance formatters are equal by comparing all of its
* internal parameters.
*
* @param obj another object to compare.
* @return true if provided object is assumed to be equal to this instance.
*/
@Override
public boolean equals(final Object obj) {
final var equals = super.equals(obj);
return (obj instanceof SurfaceFormatter) && equals;
}
/**
* Hash code generated for this instance.
* Hash codes can be internally used by some collections to coarsely compare objects.
* This implementation only calls parent implementation to avoid static analyzer warning.
*
* @return hash code.
*/
@Override
public int hashCode() {
return super.hashCode();
}
/**
* Gets unit system for detected unit into provided string representation
* of a measurement.
*
* @param source a measurement string representation to be checked.
* @return a unit system (either metric or imperial) or null if unit
* cannot be determined.
*/
@Override
public UnitSystem getUnitSystem(final String source) {
final var unit = findUnit(source);
return unit != null ? SurfaceUnit.getUnitSystem(unit) : null;
}
/**
* Parses provided string and tries to determine a surface value and unit.
*
* @param source text to be parsed.
* @return a surface containing a value and unit.
* @throws ParseException if provided string cannot be parsed.
* @throws UnknownUnitException if unit cannot be determined.
*/
@Override
public Surface parse(final String source) throws ParseException, UnknownUnitException {
return internalParse(source, new Surface());
}
/**
* Attempts to determine a surface unit within a measurement string
* representation.
*
* @param source a surface measurement string representation.
* @return a surface unit, or null if none can be determined.
*/
@Override
public SurfaceUnit findUnit(final String source) {
if (source.contains(SQUARE_MILLIMETER + " ") || source.endsWith(SQUARE_MILLIMETER)) {
return SurfaceUnit.SQUARE_MILLIMETER;
}
if (source.contains(SQUARE_CENTIMETER + " ") || source.endsWith(SQUARE_CENTIMETER)) {
return SurfaceUnit.SQUARE_CENTIMETER;
}
if (source.contains(SQUARE_KILOMETER + " ") || source.endsWith(SQUARE_KILOMETER)) {
return SurfaceUnit.SQUARE_KILOMETER;
}
if (source.contains(SQUARE_INCH + " ") || source.endsWith(SQUARE_INCH)) {
return SurfaceUnit.SQUARE_INCH;
}
if (source.contains(SQUARE_FOOT + " ") || source.endsWith(SQUARE_FOOT)) {
return SurfaceUnit.SQUARE_FOOT;
}
if (source.contains(SQUARE_YARD + " ") || source.endsWith(SQUARE_YARD)) {
return SurfaceUnit.SQUARE_YARD;
}
if (source.contains(SQUARE_MILE + " ") || source.endsWith(SQUARE_MILE)) {
return SurfaceUnit.SQUARE_MILE;
}
if (source.contains(CENTIARE + " ") || source.endsWith(CENTIARE)) {
return SurfaceUnit.CENTIARE;
}
if (source.contains(DECARE + " ") || source.endsWith(DECARE)) {
return SurfaceUnit.DECARE;
}
if (source.contains(HECTARE + " ") || source.endsWith(HECTARE)) {
return SurfaceUnit.HECTARE;
}
if (source.contains(ACRE + " ") || source.endsWith(ACRE)) {
return SurfaceUnit.ACRE;
}
if (source.contains(ARE + " ") || source.endsWith(ARE)) {
return SurfaceUnit.ARE;
}
if (source.contains(SQUARE_METER + " ") || source.endsWith(SQUARE_METER)) {
return SurfaceUnit.SQUARE_METER;
}
return null;
}
/**
* Formats and converts provided surface value and unit using provided
* unit system.
* If provided value is too large for provided unit, this method will
* convert it to a more appropriate unit using provided unit system (either
* metric or imperial).
*
* @param value a surface value.
* @param unit a surface unit.
* @param system system unit to convert surface to.
* @return a string representation of surface value and unit.
*/
@Override
public String formatAndConvert(final Number value, final SurfaceUnit unit, final UnitSystem system) {
if (system == UnitSystem.IMPERIAL) {
return formatAndConvertImperial(value, unit);
} else {
return formatAndConvertMetric(value, unit);
}
}
/**
* Formats and converts provided surface value and unit using metric unit
* system.
* If provided surface value is too large for provided surface unit,
* this method will convert it to a more appropriate unit.
*
* @param value a surface value.
* @param unit a surface unit.
* @return a string representation of surface value and unit using metric
* unit system.
*/
public String formatAndConvertMetric(final Number value, final SurfaceUnit unit) {
final var v = value.doubleValue();
final var squareMillimeters = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_MILLIMETER);
if (Math.abs(squareMillimeters) < (SurfaceConverter.SQUARE_METERS_PER_SQUARE_CENTIMETER
/ SurfaceConverter.SQUARE_METERS_PER_SQUARE_MILLIMETER)) {
return format(squareMillimeters, SurfaceUnit.SQUARE_MILLIMETER);
}
final var squareCentimeters = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_CENTIMETER);
if (Math.abs(squareCentimeters) < (1.0 / SurfaceConverter.SQUARE_METERS_PER_SQUARE_CENTIMETER)) {
return format(squareCentimeters, SurfaceUnit.SQUARE_CENTIMETER);
}
final var squareMeters = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_METER);
if (Math.abs(squareMeters) < SurfaceConverter.SQUARE_METERS_PER_SQUARE_KILOMETER) {
return format(squareMeters, SurfaceUnit.SQUARE_METER);
}
final var squareKilometers = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_KILOMETER);
return format(squareKilometers, SurfaceUnit.SQUARE_KILOMETER);
}
/**
* Formats and converts provided surface value and unit using imperial unit
* system.
* If provided surface value is too large for provided surface unit,
* this method will convert it to a more appropriate unit.
*
* @param value a surface value.
* @param unit a surface unit.
* @return a string representation of surface value and unit using imperial
* unit system.
*/
public String formatAndConvertImperial(final Number value, final SurfaceUnit unit) {
final var v = value.doubleValue();
final var squareInches = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_INCH);
if (Math.abs(squareInches) < (SurfaceConverter.SQUARE_METERS_PER_SQUARE_FOOT
/ SurfaceConverter.SQUARE_METERS_PER_SQUARE_INCH)) {
return format(squareInches, SurfaceUnit.SQUARE_INCH);
}
final var squareFeet = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_FOOT);
if (Math.abs(squareFeet) < (SurfaceConverter.SQUARE_METERS_PER_SQUARE_YARD
/ SurfaceConverter.SQUARE_METERS_PER_SQUARE_FOOT)) {
return format(squareFeet, SurfaceUnit.SQUARE_FOOT);
}
final var squareYards = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_YARD);
if (Math.abs(squareYards) < (SurfaceConverter.SQUARE_METERS_PER_SQUARE_MILE
/ SurfaceConverter.SQUARE_METERS_PER_SQUARE_YARD)) {
return format(squareYards, SurfaceUnit.SQUARE_YARD);
}
final var squareMiles = SurfaceConverter.convert(v, unit, SurfaceUnit.SQUARE_MILE);
return format(squareMiles, SurfaceUnit.SQUARE_MILE);
}
/**
* Returns unit string representation.
*
* @param unit a measure unit.
* @return its string representation.
*/
@Override
public String getUnitSymbol(final SurfaceUnit unit) {
return switch (unit) {
case SQUARE_MILLIMETER -> SQUARE_MILLIMETER;
case SQUARE_CENTIMETER -> SQUARE_CENTIMETER;
case SQUARE_KILOMETER -> SQUARE_KILOMETER;
case SQUARE_INCH -> SQUARE_INCH;
case SQUARE_FOOT -> SQUARE_FOOT;
case SQUARE_YARD -> SQUARE_YARD;
case SQUARE_MILE -> SQUARE_MILE;
case CENTIARE -> CENTIARE;
case ARE -> ARE;
case DECARE -> DECARE;
case HECTARE -> HECTARE;
case ACRE -> ACRE;
default -> SQUARE_METER;
};
}
}