View Javadoc

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.io.IOException;
19  import java.io.Serializable;
20  import java.math.BigDecimal;
21  
22  import org.joda.money.BigMoney;
23  import org.joda.money.MoneyUtils;
24  
25  /**
26   * Prints and parses the amount part of the money.
27   * <p>
28   * This class is immutable and thread-safe.
29   */
30  final class AmountPrinterParser implements MoneyPrinter, MoneyParser, Serializable {
31  
32      /** Serialization version. */
33      private static final long serialVersionUID = 1L;
34  
35      /** The style to use. */
36      private final MoneyAmountStyle style;
37  
38      /**
39       * Constructor.
40       * @param style  the style, not null
41       */
42      AmountPrinterParser(MoneyAmountStyle style) {
43          this.style = style;
44      }
45  
46      //-----------------------------------------------------------------------
47      public void print(MoneyPrintContext context, Appendable appendable, BigMoney money) throws IOException {
48          MoneyAmountStyle activeStyle = style.localize(context.getLocale());
49          if (MoneyUtils.isNegative(money)) {
50              money = money.negated();
51              appendable.append(activeStyle.getNegativeSignCharacter());
52          }
53          String str = money.getAmount().toPlainString();
54          char zeroChar = activeStyle.getZeroCharacter();
55          if (zeroChar != '0') {
56              int diff = zeroChar - '0';
57              StringBuilder zeroConvert = new StringBuilder(str);
58              for (int i = 0; i < str.length(); i++) {
59                  char ch = str.charAt(i);
60                  if (ch >= '0' && ch <= '9') {
61                      zeroConvert.setCharAt(i, (char) (ch + diff));
62                  }
63              }
64              str = zeroConvert.toString();
65          }
66          final int decPoint = str.indexOf('.');
67          final int afterDecPoint = decPoint + 1;;
68          if (activeStyle.getGroupingStyle() == GroupingStyle.NONE) {
69              if (decPoint < 0) {
70                  appendable.append(str);
71                  if (activeStyle.isForcedDecimalPoint()) {
72                      appendable.append(activeStyle.getDecimalPointCharacter());
73                  }
74              } else {
75                  appendable.append(str.subSequence(0, decPoint))
76                      .append(activeStyle.getDecimalPointCharacter()).append(str.substring(afterDecPoint));
77              }
78          } else {
79              int groupingSize = activeStyle.getGroupingSize();
80              char groupingChar = activeStyle.getGroupingCharacter();
81              int pre = (decPoint < 0 ? str.length() : decPoint);
82              int post = (decPoint < 0 ? 0 : str.length() - decPoint - 1);
83              for (int i = 0; pre > 0; i++, pre--) {
84                  appendable.append(str.charAt(i));
85                  if (pre > 3 && pre % groupingSize == 1) {
86                      appendable.append(groupingChar);
87                  }
88              }
89              if (decPoint >= 0 || activeStyle.isForcedDecimalPoint()) {
90                  appendable.append(activeStyle.getDecimalPointCharacter());
91              }
92              if (activeStyle.getGroupingStyle() == GroupingStyle.BEFORE_DECIMAL_POINT) {
93                  appendable.append(str.substring(afterDecPoint));
94              } else {
95                  for (int i = 0; i < post; i++) {
96                      appendable.append(str.charAt(i + afterDecPoint));
97                      if (i % groupingSize == 2) {
98                          appendable.append(groupingChar);
99                      }
100                 }
101             }
102         }
103     }
104 
105     public void parse(MoneyParseContext context) {
106         final int len = context.getTextLength();
107         final MoneyAmountStyle activeStyle = style.localize(context.getLocale());
108         char[] buf = new char[len - context.getIndex()];
109         int bufPos = 0;
110         boolean dpSeen = false;
111         boolean lastWasGroup = false;
112         int pos = context.getIndex();
113         if (pos < len) {
114             char ch = context.getText().charAt(pos++);
115             if (ch == activeStyle.getNegativeSignCharacter()) {
116                 buf[bufPos++] = '-';
117             } else if (ch == activeStyle.getPositiveSignCharacter()) {
118                 buf[bufPos++] = '+';
119             } else if (ch >= activeStyle.getZeroCharacter() && ch < activeStyle.getZeroCharacter() + 10) {
120                 buf[bufPos++] = (char) ('0' + ch - activeStyle.getZeroCharacter());
121             } else if (ch == activeStyle.getDecimalPointCharacter()) {
122                 buf[bufPos++] = '.';
123                 dpSeen = true;
124             } else {
125                 context.setError();
126                 return;
127             }
128         }
129         for ( ; pos < len; pos++) {
130             char ch = context.getText().charAt(pos);
131             if (ch >= activeStyle.getZeroCharacter() && ch < activeStyle.getZeroCharacter() + 10) {
132                 buf[bufPos++] = (char) ('0' + ch - activeStyle.getZeroCharacter());
133                 lastWasGroup = false;
134             } else if (ch == activeStyle.getDecimalPointCharacter() && dpSeen == false) {
135                 buf[bufPos++] = '.';
136                 dpSeen = true;
137                 lastWasGroup = false;
138             } else if (ch == activeStyle.getGroupingCharacter() && lastWasGroup == false) {
139                 lastWasGroup = true;
140             } else {
141                 break;
142             }
143         }
144         if (lastWasGroup) {
145             pos--;
146         }
147         try {
148             context.setAmount(new BigDecimal(buf, 0, bufPos));
149             context.setIndex(pos);
150         } catch (NumberFormatException ex) {
151             context.setError();
152         }
153     }
154 
155     @Override
156     public String toString() {
157         return "${amount}";
158     }
159 
160 }