1 /*
2 * Copyright 2009-2013 Stephen Colebourne
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.joda.money.format;
17
18 import java.math.BigDecimal;
19 import java.text.ParsePosition;
20 import java.util.Locale;
21
22 import org.joda.money.BigMoney;
23 import org.joda.money.CurrencyUnit;
24
25 /**
26 * Context used when parsing money.
27 * <p>
28 * This class is mutable and intended for use by a single thread.
29 * A new instance is created for each parse.
30 */
31 public final class MoneyParseContext {
32
33 /**
34 * The locale to parse using.
35 */
36 private Locale locale;
37 /**
38 * The text to parse.
39 */
40 private CharSequence text;
41 /**
42 * The text index.
43 */
44 private int textIndex;
45 /**
46 * The text error index.
47 */
48 private int textErrorIndex = -1;
49 /**
50 * The parsed currency.
51 */
52 private CurrencyUnit currency;
53 /**
54 * The parsed amount.
55 */
56 private BigDecimal amount;
57
58 /**
59 * Constructor.
60 *
61 * @param locale the locale, not null
62 * @param text the text to parse, not null
63 * @param index the current text index
64 */
65 MoneyParseContext(Locale locale, CharSequence text, int index) {
66 this.locale = locale;
67 this.text = text;
68 this.textIndex = index;
69 }
70
71 //-----------------------------------------------------------------------
72 /**
73 * Gets the locale.
74 *
75 * @return the locale, not null
76 */
77 public Locale getLocale() {
78 return locale;
79 }
80
81 /**
82 * Sets the locale.
83 *
84 * @param locale the locale, not null
85 */
86 public void setLocale(Locale locale) {
87 MoneyFormatter.checkNotNull(locale, "Locale must not be null");
88 this.locale = locale;
89 }
90
91 /**
92 * Gets the text being parsed.
93 *
94 * @return the text being parsed, never null
95 */
96 public CharSequence getText() {
97 return text;
98 }
99
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 }