001/* 002* ParameterFormat -- Provides formatting and parsing for Parameter objects. 003* 004* Copyright (C) 2008-2011 by Joseph A. Huwaldt. 005* All rights reserved. 006* 007* This library is free software; you can redistribute it and/or 008* modify it under the terms of the GNU Lesser General Public 009* License as published by the Free Software Foundation; either 010* version 2 of the License, or (at your option) any later version. 011* 012* This library is distributed in the hope that it will be useful, 013* but WITHOUT ANY WARRANTY; without even the implied warranty of 014* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015* Lesser General Public License for more details. 016* 017* You should have received a copy of the GNU Lesser General Public License 018* along with this program; if not, write to the Free Software 019* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 020* Or visit: http://www.gnu.org/licenses/lgpl.html 021**/ 022package jahuwaldt.js.param; 023 024import java.io.IOException; 025import java.text.ParseException; 026 027import org.jscience.economics.money.Currency; 028import org.jscience.economics.money.Money; 029 030import javax.measure.unit.Unit; 031import javax.measure.unit.UnitFormat; 032 033import javolution.lang.MathLib; 034import javolution.text.TextFormat; 035import javolution.text.TypeFormat; 036import javolution.context.LocalContext; 037 038 039/** 040* <p> This class provides the interface for formatting and parsing {@link 041* Parameter parameter} instances.</p> 042* 043* <p> Modified by: Joseph A. Huwaldt </p> 044* 045* @author Joseph A. Huwaldt Date: November 15, 2008 046* @version October 2, 2011 047**/ 048public abstract class ParameterFormat extends TextFormat<Parameter<?>> { 049 050 /** 051 * Holds current format. 052 */ 053 private static final LocalContext.Reference<ParameterFormat> CURRENT = new LocalContext.Reference<ParameterFormat>( 054 new SimpleFormat()); 055 056 /** 057 * Default constructor. 058 */ 059 protected ParameterFormat() { } 060 061 /** 062 * Returns the current {@link javolution.context.LocalContext local} 063 * format (default <code>ParameterFormat.getSimpleFormatInstance()</code>). 064 * 065 * @return the context local format. 066 * @see #getSimpleFormatInstance 067 */ 068 public static ParameterFormat newInstance() { 069 return CURRENT.get(); 070 } 071 072 /** 073 * Sets the current {@link javolution.context.LocalContext local} format. 074 * 075 * @param format the new format. 076 */ 077 public static void setInstance(ParameterFormat format) { 078 CURRENT.set(format); 079 } 080 081 /** 082 * Returns a simple ParameterFormat for which the value is stated using 083 * the current units; for example <code>"1.34 m"</code>. 084 * This format can be used for formatting as well as for parsing. 085 */ 086 public static ParameterFormat getSimpleFormatInstance() { 087 return new SimpleFormat(); 088 } 089 090 /** 091 * This class represents the simple format with the value and units. 092 */ 093 private static class SimpleFormat extends ParameterFormat { 094 095 /** 096 * Default constructor. 097 */ 098 private SimpleFormat() { } 099 100 @SuppressWarnings("unchecked") 101 @Override 102 public Appendable format(Parameter<?> arg0, Appendable arg1) 103 throws IOException { 104 if (arg0.getUnit() instanceof Currency) 105 return formatMoney((Parameter<Money>) arg0, arg1); 106 double value = arg0.getValue(); 107 double error = MathLib.abs(value) * DOUBLE_RELATIVE_ERROR; 108 int log10Value = (int) MathLib.floor(MathLib.log10(MathLib 109 .abs(value))); 110 int log10Error = (int) MathLib.floor(MathLib.log10(error)); 111 int digits = log10Value - log10Error - 1; // Exact digits. 112 113 boolean scientific = (MathLib.abs(value) >= 1E6) || (MathLib.abs(value) < 1E-6); 114 boolean showZeros = false; 115 TypeFormat.format(value, digits, scientific, showZeros, arg1); 116 arg1.append(' '); 117 return UnitFormat.getInstance().format(arg0.getUnit(), arg1); 118 } 119 120 @Override 121 public Parameter<?> parse(CharSequence arg0, Cursor arg1) { 122 int start = arg1.getIndex(); 123 try { 124 double amount = TypeFormat.parseDouble(arg0, arg1); 125 arg1.skip(' ', arg0); 126 Unit<?> unit = UnitFormat.getInstance().parseProductUnit(arg0, arg1); 127 return Parameter.valueOf(amount, unit); 128 129 } catch (ParseException e) { 130 arg1.setIndex(start); 131 arg1.setErrorIndex(e.getErrorOffset()); 132 return null; 133 } 134 } 135 } 136 137 /** 138 * Provides custom formatting for money measurements. 139 */ 140 private static Appendable formatMoney(Parameter<Money> arg0, Appendable arg1) 141 throws IOException { 142 Currency currency = (Currency) arg0.getUnit(); 143 int fraction = currency.getDefaultFractionDigits(); 144 if (fraction == 0) { 145 long amount = arg0.longValue(currency); 146 TypeFormat.format(amount, arg1); 147 } else if (fraction == 2) { 148 long amount = MathLib.round(arg0.doubleValue(arg0.getUnit()) * 100); 149 TypeFormat.format(amount / 100, arg1); 150 arg1.append('.'); 151 arg1.append((char) ('0' + (amount % 100) / 10)); 152 arg1.append((char) ('0' + (amount % 10))); 153 } else { 154 throw new UnsupportedOperationException(); 155 } 156 arg1.append(' '); 157 return UnitFormat.getInstance().format(currency, arg1); 158 } 159 160 static final double DOUBLE_RELATIVE_ERROR = MathLib.pow(2, -53); 161 162}