package com.customfit.ctg.model; import com.customfit.ctg.controller.*; import java.lang.reflect.*; import java.util.ArrayList; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; /** * A Measurement represents what, in science, is typically * called a vector quantity. That is, it is two things: a value, * and a unit. * * @author David, Drew */ public class Measurement implements Comparable<Measurement> { /** * The quantity of the Measurement. */ private double quantity = 0.0; /** * The unit of the Measurement. */ private String unit = ""; /** * Create a new Measurement with the quantity and unit specified. * * @param quantity The quantity of the Measurement. (e.g., 1.0, 99) * @param unit The unit of the Measurement. (e.g., grams, gallons, miles, millenia) */ public Measurement(double quantity, String unit) { this.quantity = quantity; this.unit = unit; } /** * Create a new Measurement with the quantity and unit specified * in the measurableUnitString. * * @param measurableUnitString Amount and unit as specified by a previous Measurement.toString(). */ public Measurement(String measurableUnitString) { if (!measurableUnitString.trim().isEmpty()) { try { //grab amount quantity this.quantity = Double.parseDouble(measurableUnitString.replaceAll("[A-Z,a-z, ]", "")); } catch (Exception e) { } } //grab amount unit this.unit = measurableUnitString.replaceAll("\\.|[0-9]", "").trim(); } /** * Gets the quantity of the Measurement. * * @return The quantity of the Measurement. */ public double getQuantity() { return quantity; } /** * Gets the unit of the Measurement. * * @return The unit of the Measurement. */ public String getUnit() { return unit; } /** * Sets the unit of the Measurement. * * @param unit The unit of the Measurement. */ public void setUnit(String unit) { this.unit = unit; } /** * Sets the quantity of the Measurement. * * @param quantity The quantity of the Measurement. */ public void setQuantity(double quantity) { this.quantity = quantity; } /** * Gets the quantity and the unit in a string. * * Example: 1.0 grams * * @return The quantity and the unit in a string. */ @Override public String toString() { if (this.getUnit() != null) return this.getQuantity() + " " + this.getUnit(); else return new Double(this.getQuantity()).toString(); } /** * Compares this Measurement with another Measurement. * The units are ignored and only the numerical comparison * is made. It calls Double.compare(). * * @param o The Measurement to compare it with. * * @return The result of a Double.compare(). */ public int compareTo(Measurement o) { if (this.getUnit() != o.getUnit()) { System.err.println("compareTo() hit on MeasurableUnit with different units specified. You shouldn't compare apples and oranges if you expect a similar result. Will supply mathematical differenc, but fix your units."); } return Double.compare(this.getQuantity(), o.getQuantity()); } /** * Scales a Measurement's quantity field. * * @param measurableUnit A Measurement instance. * @param scaleFactor The scale factor, e.g. 0.5, 2.0, 5.0, ... * * @return The new Measurement with the scaled field. */ public static Measurement scaleMeasurableUnit(Measurement measurement, double scaleFactor) { Measurement newMeasurement = null; try { newMeasurement = (Measurement)measurement.clone(); newMeasurement.quantity *= scaleFactor; } catch (CloneNotSupportedException ex) { Application.dumpException("The was a problem cloning the Measurable Unit object. Clone is not supported.", ex); } return newMeasurement; } /** * Scales quantity field into a new Measurement. * * @param scaleFactor The scale factor, e.g. 0.5, 2.0, 5.0, ... * * @return The new Measurement with the scaled field. */ public Measurement scale(double scaleFactor) { return Measurement.scaleMeasurableUnit(this, scaleFactor); } //TODO: Update whether this is dry or fluid ounces. /** * Converts a Measurement to ounces. * * @param measurement The Measurement to convert. * * @return The Measurement in ounces. */ public static Measurement measurementToOunces(Measurement measurement) { //TODO: Update whether this is dry or fluid ounces. return new Measurement(measurementToOunces(measurement.getQuantity(), measurement.getUnit()), "ounces"); } //TODO: Document whether this is dry or fluid ounces. /** * Converts a Measurement to ounces. * * @param quantity The quantity of the Measurement. * @param unit The unit of the Measurement. * * @return The Measurement in ounces. */ public static double measurementToOunces(double quantity, String unit) { double ounces = quantity; if (unit.equals(USAUnits.POUNDS) || unit.equals(USAUnits.PINTS)) ounces *= 16.0; else if (unit.equals(USAUnits.GALLONS)) ounces *= 128.0; else if (unit.equals(USAUnits.QUARTS)) ounces *= 32.0; else if (unit.equals(USAUnits.CUPS)) ounces *= 8.0; else if (unit.equals(USAUnits.TABLESPOONS)) ounces *= .5; else if (unit.equals(USAUnits.TEASPOONS)) ounces *= .167; else if (unit.equals(USAUnits.LIQUID_OUNCES) || unit.equals(USAUnits.DRY_OUNCES)) { //ounces = ounces; //so do nothing } else { ounces = 0.0; System.err.println("Error: Unknown measurement unit provided for conversion."); } return ounces; } /** * Converts Measurement to ounces. * * @return A new Measurement in ounces. */ public Measurement toOunces() { return Measurement.measurementToOunces(this); } @Override public boolean equals(Object obj) { if (obj == null) return false; Measurement measurement = (Measurement)obj; if (this.unit != null && measurement.unit != null && !this.unit.equals(measurement.unit)) return false; else if (this.quantity != measurement.quantity) return false; return true; } /** * Creates a new Measurement object with the sum of the two quantities and the unit * from the measurement of the left. * * @param measurementLeft A Measurement object. (This one must have the unit specified.) * @param measurementRight A Measurement object. (The unit will be ignored.) * * @return Measurement object with the sum of the two quantities. */ public static Measurement addMeasurements(Measurement measurementLeft, Measurement measurementRight) { return new Measurement(measurementLeft.quantity+measurementRight.quantity, measurementLeft.unit); } /** * Creates a new Measurement object with the sum of the quantities of this Measurement * and the one you specified. The input Measurement's unit will be ignored and only * the quantities will be merged into the new Measurement object. The unit from this * instance will be passed into the new Measurement object. * * @param measurement The Measurement object you would like to add into this one. * * @return A new Measurement object with the sum of the two quantities. */ public Measurement add(Measurement measurement) { //put this on the left return Measurement.addMeasurements(this, measurement); } /** * Represents a sample of the US Customary measurement units. */ public static class USAUnits { //USA units public static final String POUNDS = "pounds"; public static final String GALLONS = "gallons"; public static final String QUARTS = "quarts"; public static final String PINTS = "pints"; public static final String CUPS = "cups"; public static final String LIQUID_OUNCES = "fluid ounces"; // Volume public static final String DRY_OUNCES = "ounces (dry)"; // Weight public static final String TABLESPOONS = "tablespoons"; public static final String TEASPOONS = "teaspoons"; /** * All US Customary measurement units. */ public static final String[] ALL_UNITS = new String[] { POUNDS, GALLONS, QUARTS, PINTS, CUPS, LIQUID_OUNCES, DRY_OUNCES, TABLESPOONS, TEASPOONS }; public static String[] getAllUSAUnits() { ArrayList<String> fields = new ArrayList<String>(); USAUnits usaUnits = new USAUnits(); for (Field field : usaUnits.getClass().getDeclaredFields()) { if (field.getType().getName().equals(new String().getClass().getName())) try { fields.add((String)field.get(new USAUnits())); } catch (IllegalAccessException ex) { Application.dumpException("Error getting unit from USAUnits.", ex); } catch (IllegalArgumentException ex) { Application.dumpException("Error getting unit from USAUnits.", ex); } } return fields.toArray(new String[] {}); } } /** * Represents a sample of the Metric measurement units. */ public static class MetricUnits { //metric units public static final String GRAMS = "grams"; public static final String MILLIGRAMS = "milligrams"; /** * All Metric units. */ public static final String[] ALL_UNITS = new String[] { GRAMS, MILLIGRAMS }; public static String[] getAllMetricUnits() { ArrayList<String> fields = new ArrayList<String>(); MetricUnits metricUnits = new MetricUnits(); for (Field field : metricUnits.getClass().getFields()) { if (field.getType().getName().equals(new String().getClass().getName())) try { fields.add((String)field.get(new MetricUnits())); } catch (IllegalAccessException ex) { Application.dumpException("Error getting unit from MetricUnits.", ex); } catch (IllegalArgumentException ex) { Application.dumpException("Error getting unit from MetricUnits.", ex); } } return fields.toArray(new String[] {}); } } /** * Represents a sample of the Food measurement units. */ public static class FoodUnits { public static final String CALORIES = "Calories"; //capitalize, because calories != Calories, sometimes also called kCals. /** * All Food units. */ public static final String[] ALL_UNITS = new String[] { CALORIES }; public static String[] getAllFoodUnits() { ArrayList<String> fields = new ArrayList<String>(); FoodUnits foodUnits = new FoodUnits(); for (Field field : foodUnits.getClass().getDeclaredFields()) { if (field.getType().getName().equals(new String().getClass().getName())) try { fields.add((String)field.get(new FoodUnits())); } catch (IllegalAccessException ex) { Application.dumpException("Error getting unit from FoodUnits.", ex); } catch (IllegalArgumentException ex) { Application.dumpException("Error getting unit from FoodUnits.", ex); } } return fields.toArray(new String[] {}); } } /** * Lists all USAUnits, MetricUnits, and FoodUnits into an array. * * @return All units array. */ public static String[] getAllUnits() { ArrayList<String> allUnits = new ArrayList<String>(); allUnits.addAll(Arrays.asList(USAUnits.getAllUSAUnits())); allUnits.addAll(Arrays.asList(MetricUnits.getAllMetricUnits())); allUnits.addAll(Arrays.asList(FoodUnits.getAllFoodUnits())); return allUnits.toArray(new String[] {}); } /** * Lists all USAUnits and MetricUnits into an array. Ignores FoodUnits. * * @return All units array. */ public static String[] getAllMeasurementUnits() { ArrayList<String> allUnits = new ArrayList<String>(); allUnits.addAll(Arrays.asList(USAUnits.getAllUSAUnits())); allUnits.addAll(Arrays.asList(MetricUnits.getAllMetricUnits())); return allUnits.toArray(new String[] {}); } }