001 /*
002 * Copyright 2009-2013 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.money.format;
017
018 import java.math.BigDecimal;
019 import java.text.ParsePosition;
020 import java.util.Locale;
021
022 import org.joda.money.BigMoney;
023 import org.joda.money.CurrencyUnit;
024
025 /**
026 * Context used when parsing money.
027 * <p>
028 * This class is mutable and intended for use by a single thread.
029 * A new instance is created for each parse.
030 */
031 public final class MoneyParseContext {
032
033 /**
034 * The locale to parse using.
035 */
036 private Locale locale;
037 /**
038 * The text to parse.
039 */
040 private CharSequence text;
041 /**
042 * The text index.
043 */
044 private int textIndex;
045 /**
046 * The text error index.
047 */
048 private int textErrorIndex = -1;
049 /**
050 * The parsed currency.
051 */
052 private CurrencyUnit currency;
053 /**
054 * The parsed amount.
055 */
056 private BigDecimal amount;
057
058 /**
059 * Constructor.
060 *
061 * @param locale the locale, not null
062 * @param text the text to parse, not null
063 * @param index the current text index
064 */
065 MoneyParseContext(Locale locale, CharSequence text, int index) {
066 this.locale = locale;
067 this.text = text;
068 this.textIndex = index;
069 }
070
071 //-----------------------------------------------------------------------
072 /**
073 * Gets the locale.
074 *
075 * @return the locale, not null
076 */
077 public Locale getLocale() {
078 return locale;
079 }
080
081 /**
082 * Sets the locale.
083 *
084 * @param locale the locale, not null
085 */
086 public void setLocale(Locale locale) {
087 MoneyFormatter.checkNotNull(locale, "Locale must not be null");
088 this.locale = locale;
089 }
090
091 /**
092 * Gets the text being parsed.
093 *
094 * @return the text being parsed, never null
095 */
096 public CharSequence getText() {
097 return text;
098 }
099
100 /**
101 * Sets the text.
102 *
103 * @param text the text being parsed, not null
104 */
105 public void setText(CharSequence text) {
106 MoneyFormatter.checkNotNull(text, "Text must not be null");
107 this.text = text;
108 }
109
110 /**
111 * Gets the length of the text being parsed.
112 *
113 * @return the length of the text being parsed
114 */
115 public int getTextLength() {
116 return text.length();
117 }
118
119 /**
120 * Gets a substring of the text being parsed.
121 *
122 * @param start the start index
123 * @param end the end index
124 * @return the substring, not null
125 */
126 public String getTextSubstring(int start, int end) {
127 return text.subSequence(start, end).toString();
128 }
129
130 //-----------------------------------------------------------------------
131 /**
132 * Gets the current parse position index.
133 *
134 * @return the current parse position index
135 */
136 public int getIndex() {
137 return textIndex;
138 }
139
140 /**
141 * Sets the current parse position index.
142 *
143 * @param index the current parse position index
144 */
145 public void setIndex(int index) {
146 this.textIndex = index;
147 }
148
149 //-----------------------------------------------------------------------
150 /**
151 * Gets the error index.
152 *
153 * @return the error index, negative if no error
154 */
155 public int getErrorIndex() {
156 return textErrorIndex;
157 }
158
159 /**
160 * Sets the error index.
161 *
162 * @param index the error index
163 */
164 public void setErrorIndex(int index) {
165 this.textErrorIndex = index;
166 }
167
168 /**
169 * Sets the error index from the current index.
170 */
171 public void setError() {
172 this.textErrorIndex = textIndex;
173 }
174
175 //-----------------------------------------------------------------------
176 /**
177 * Gets the parsed currency.
178 *
179 * @return the parsed currency, null if not parsed yet
180 */
181 public CurrencyUnit getCurrency() {
182 return currency;
183 }
184
185 /**
186 * Sets the parsed currency.
187 *
188 * @param currency the parsed currency, may be null
189 */
190 public void setCurrency(CurrencyUnit currency) {
191 this.currency = currency;
192 }
193
194 //-----------------------------------------------------------------------
195 /**
196 * Gets the parsed amount.
197 *
198 * @return the parsed amount, null if not parsed yet
199 */
200 public BigDecimal getAmount() {
201 return amount;
202 }
203
204 /**
205 * Sets the parsed currency.
206 *
207 * @param amount the parsed amount, may be null
208 */
209 public void setAmount(BigDecimal amount) {
210 this.amount = amount;
211 }
212
213 //-----------------------------------------------------------------------
214 /**
215 * Checks if the parse has found an error.
216 *
217 * @return whether a parse error has occurred
218 */
219 public boolean isError() {
220 return textErrorIndex >= 0;
221 }
222
223 /**
224 * Checks if the text has been fully parsed such that there is no more text to parse.
225 *
226 * @return true if fully parsed
227 */
228 public boolean isFullyParsed() {
229 return textIndex == getTextLength();
230 }
231
232 /**
233 * Checks if the context contains a currency and amount suitable for creating
234 * a monetary value.
235 *
236 * @return true if able to create a monetary value
237 */
238 public boolean isComplete() {
239 return currency != null && amount != null;
240 }
241
242 //-----------------------------------------------------------------------
243 /**
244 * Converts the indexes to a parse position.
245 *
246 * @return the parse position, never null
247 */
248 public ParsePosition toParsePosition() {
249 ParsePosition pp = new ParsePosition(textIndex);
250 pp.setErrorIndex(textErrorIndex);
251 return pp;
252 }
253
254 /**
255 * Converts the context to a {@code BigMoney}.
256 *
257 * @return the monetary value, never null
258 * @throws MoneyFormatException if either the currency or amount is missing
259 */
260 public BigMoney toBigMoney() {
261 if (currency == null) {
262 throw new MoneyFormatException("Cannot convert to BigMoney as no currency found");
263 }
264 if (amount == null) {
265 throw new MoneyFormatException("Cannot convert to BigMoney as no amount found");
266 }
267 return BigMoney.of(currency, amount);
268 }
269
270 }