/*****************************************************************************
SQLJEP - Java SQL Expression Parser 0.2
November 1 2006
(c) Copyright 2006, Alexey Gaidukov
SQLJEP Author: Alexey Gaidukov
SQLJEP is based on JEP 2.24 (http://www.singularsys.com/jep/)
(c) Copyright 2002, Nathan Funk
See LICENSE.txt for license information.
*****************************************************************************/
package com.meidusa.amoeba.sqljep.function;
import java.util.Hashtable;
import java.text.*;
import java.math.*;
public final class OracleNumberFormat extends Format {
private static final long serialVersionUID = 1L;
private static final String PATTERN_EXCEPTION = "Wrong pattern";
public static final String NOT_IMPLIMENTED_EXCEPTION = "Not implimented";
final static char DOT = '.';
final static char GROUP = ' ';
private static final Hashtable<String, FORMAT> formatsCache = new Hashtable<String, FORMAT>();
private FORMAT format = null;
public static enum SIGN {
DEFAULT,
MI,
_S,
S_,
PR
};
public static enum CURRENCY {
NON,
DOLLARS,
LOCAL,
ISO
};
private static class FORMAT {
boolean sci;
boolean localGroups = true; // for D and G
String numbers = "";
int digits = 0; // number of digits in 'numbers' member
int firstNine = -1; // position in 'numbers' member the first 9 digit
SIGN sign = SIGN.DEFAULT;
boolean fm = false;
boolean b = false;
CURRENCY cur = CURRENCY.NON;
int v = 0;
int dot = 0;
public void getPrefix(StringBuffer s, BigDecimal n) {
if (sci && !fm) {
s.append(' ');
}
if (n.signum() == 1) {
if (sign == SIGN.S_) {
s.append('+');
}
else if (!fm && sign != SIGN._S && sign != SIGN.MI) {
s.append(' ');
}
}
else if (n.signum() == -1) {
if (sign == SIGN.PR) {
s.append('<');
}
else if (sign != SIGN._S && sign != SIGN.MI) {
s.append('-');
}
}
else if (!fm) {
s.append(' ');
}
if (cur == CURRENCY.DOLLARS) {
s.append("$");
}
// else if (cur == CURRENCY.LOCAL) {
// s.append("L");
// }
else if (cur == CURRENCY.ISO) {
s.append("RUR");
}
}
public void getSuffix(StringBuffer s, BigDecimal n) {
if (cur == CURRENCY.LOCAL) {
s.append("��?");
}
if (n.signum() == 1) {
if (sign == SIGN._S) {
s.append('+');
}
else if (sign == SIGN.MI) {
s.append(' ');
}
}
else if (n.signum() == -1) {
if (sign == SIGN.PR) {
s.append('>');
}
else if (sign == SIGN.MI || sign == SIGN._S) {
s.append('-');
}
}
}
public String toString() {
StringBuilder s = new StringBuilder();
if (sign == SIGN.S_) {
s.append('S');
}
if (fm) {
s.append("FM");
}
if (b) {
s.append('B');
}
if (cur == CURRENCY.DOLLARS) {
s.append('$');
}
else if (cur == CURRENCY.LOCAL) {
s.append('L');
}
else if (cur == CURRENCY.ISO) {
s.append('C');
}
s.append(numbers);
if (dot > 0) {
s.append('D');
for (int i = 0; i < dot; i++) {
s.append('9');
}
}
else if (v > 0) {
s.append('V');
for (int i = 0; i < v; i++) {
s.append('9');
}
}
if (sci) {
s.append("EEEE");
}
if (sign == SIGN._S) {
s.append('S');
}
else if (sign == SIGN.MI) {
s.append("MI");
}
return s.toString();
}
public boolean equals(Comparable<?> obj) {
if (obj == null) {
return false;
}
FORMAT other = (FORMAT)obj;
return (sci == other.sci &&
localGroups == other.localGroups &&
numbers.equals(other.numbers) &&
digits == other.digits &&
firstNine == other.firstNine &&
sign == other.sign &&
fm == other.fm &&
b == other.b &&
cur == other.cur &&
v == other.v &&
dot == other.dot);
}
};
public OracleNumberFormat(String pattern) throws java.text.ParseException {
format = formatsCache.get(pattern);
if (format == null) {
format = compilePattern(pattern);
formatsCache.put(pattern, format);
}
}
public String toString() {
return (format != null) ? format.toString() : "null";
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (getClass() != obj.getClass()) {
return false;
}
OracleNumberFormat other = (OracleNumberFormat)obj;
return (format != null) ? format.equals(other.format) : false;
}
private static FORMAT compilePattern(String pattern) throws java.text.ParseException {
if (pattern == null) {
throw new java.text.ParseException(PATTERN_EXCEPTION, 0);
}
if (pattern.equals("RN") || pattern.equals("rn")) {
throw new java.text.ParseException(NOT_IMPLIMENTED_EXCEPTION, 0);
}
FORMAT format = new FORMAT();
if (pattern.length() == 0) {
return format;
}
pattern = pattern.toUpperCase();
String prefix;
String suffix;
char c = pattern.charAt(0);
boolean n = (c == '0' || c == '9');
int i;
final int flen = pattern.length();
if (!n) {
for (i = 1; i < flen; i++) {
c = pattern.charAt(i);
if (c == '0' || c == '9')
break;
}
prefix = pattern.substring(0, i);
} else {
prefix = "";
i = 0;
}
StringBuilder numbers = new StringBuilder();
boolean stop = false;
boolean leadZero = true;
boolean definedGroups = false;
for (; i < flen; i++) {
c = pattern.charAt(i);
stop = true;
if (c == 'G') {
if (definedGroups && !format.localGroups) {
throw new java.text.ParseException(PATTERN_EXCEPTION, 0);
}
definedGroups = true;
format.localGroups = true;
stop = false;
numbers.append('G');
}
else if (c == ',') {
if (definedGroups && format.localGroups) {
throw new java.text.ParseException(PATTERN_EXCEPTION, i);
}
definedGroups = true;
format.localGroups = true;
stop = false;
numbers.append('G');
} else {
if (leadZero) {
if (c == '0') {
numbers.append('0');
format.digits++;
stop = false;
}
else if (c == '9') {
stop = false;
leadZero = false;
format.firstNine = numbers.length();
numbers.append('9');
format.digits++;
}
} else {
if (c == '0' || c == '9') {
stop = false;
numbers.append('9');
format.digits++;
}
}
}
if (stop) {
break;
}
}
if (leadZero) {
format.firstNine = numbers.length();
}
if (c == 'V') {
for (i++; i < flen; i++,format.v++) {
c = pattern.charAt(i);
if (c != '0' && c != '9')
break;
}
}
else if (c == '.' || c == 'D') {
if (definedGroups) {
if (format.localGroups && c == '.' || !format.localGroups && c == 'D') {
throw new java.text.ParseException(PATTERN_EXCEPTION, i);
}
} else {
format.localGroups = (c == 'D');
}
for (i++; i < flen; i++,format.dot++) {
c = pattern.charAt(i);
if (c != '0' && c != '9')
break;
}
}
format.numbers = numbers.toString();
if (i == prefix.length()) {
throw new java.text.ParseException(PATTERN_EXCEPTION, i);
}
suffix = pattern.substring(i);
int suf_offset = 0;
if (suffix.startsWith("EEEE")) {
format.sci = true;
suf_offset = 4;
}
if (suffix.startsWith("S", suf_offset)) {
format.sign = SIGN._S;
suf_offset += 1;
}
else if (suffix.startsWith("MI", suf_offset)) {
format.sign = SIGN.MI;
suf_offset += 2;
}
else if (suffix.startsWith("PR", suf_offset)) {
format.sign = SIGN.PR;
suf_offset += 2;
}
if (suf_offset < suffix.length()) {
throw new java.text.ParseException(PATTERN_EXCEPTION, i);
}
int pref_offset = 0;
if (format.sign == SIGN.DEFAULT && prefix.startsWith("S")) {
format.sign = SIGN.S_;
pref_offset += 1;
}
if (prefix.startsWith("FM", pref_offset)) {
format.fm = true;
pref_offset += 2;
}
if (prefix.startsWith("B", pref_offset)) {
format.b = true;
pref_offset += 1;
}
if (format.sign == SIGN.DEFAULT && prefix.startsWith("S", pref_offset)) {
format.sign = SIGN.S_;
suf_offset += 1;
}
if (prefix.startsWith("$", pref_offset)) {
format.cur = CURRENCY.DOLLARS;
pref_offset += 1;
}
else if (prefix.startsWith("L", pref_offset)) {
format.cur = CURRENCY.LOCAL;
pref_offset += 1;
}
else if (prefix.startsWith("C", pref_offset)) {
format.cur = CURRENCY.ISO;
pref_offset += 1;
}
if (pref_offset < prefix.length()) {
throw new java.text.ParseException(PATTERN_EXCEPTION, 0);
}
return format;
}
public StringBuffer format(Object number, StringBuffer str, FieldPosition fieldPosition) {
if (number instanceof Number) {
BigDecimal d;
if (number instanceof BigDecimal) {
d = (BigDecimal)number;
}
else if (number instanceof Double || number instanceof Float) {
d = new BigDecimal(((Number)number).doubleValue());
} else {
d = new BigDecimal(((Number)number).longValue());
}
if (format.sci) {
int len = d.unscaledValue().abs().toString().toCharArray().length;
int scale = d.scale();
format.getPrefix(str, d);
d = new BigDecimal(d.unscaledValue(), len-1);
d = d.setScale(format.dot+format.v, BigDecimal.ROUND_HALF_EVEN);
char coeff[] = d.unscaledValue().abs().toString().toCharArray();
if (coeff.length > 1+format.v) {
str.append(coeff, 0, 1+format.v);
if (coeff.length > 1) {
str.append(DOT);
str.append(coeff, 1+format.v, coeff.length-1);
}
} else {
str.append(coeff);
for (int i = 0; i < format.v+1-coeff.length; i++) {
str.append('0');
}
}
int adjusted = len-scale-1;
str.append('E');
str.append(adjusted >= 0 ? '+' : '-');
String m = Integer.toString(Math.abs(adjusted));
if (m.length() == 1) {
str.append('0');
}
str.append(m);
format.getSuffix(str, d);
} else {
if (format.b && d.signum() == 0) {
if (!format.fm) {
for (int i = 0; i < format.numbers.length()+format.v+1; i++) {
str.append(' ');
}
}
}
else if (d.precision() - d.scale() > format.digits) {
for (int i = 0; i < format.numbers.length()+format.v+1; i++) {
str.append('#');
}
} else {
format.getPrefix(str, d);
int scale = d.scale();
int digits = format.digits;
if (format.v > 0 && scale > 0) {
int v;
if (format.v > scale) {
v = 0;
format.v -= scale;
} else {
v = scale-format.v;
format.v = 0;
}
digits += scale;
d = new BigDecimal(d.unscaledValue(), v);
}
char coeff[] = d.unscaledValue().abs().toString().toCharArray();
int len = coeff.length;
if (format.dot < d.scale()) {
d = d.setScale(format.dot, BigDecimal.ROUND_HALF_EVEN);
coeff = d.unscaledValue().abs().toString().toCharArray();
len = coeff.length;
}
int j = 0;
int prec = len-d.scale();
// boolean canGroup = false;
int i1 = 0;
final int n = format.numbers.length();
for (int i = 0; i < n; i++) {
if (format.numbers.charAt(i) == 'G') {
str.append(GROUP);
}
else if (i1 < digits-prec) {
if (format.firstNine != 0) {
str.append('0');
// canGroup = true;
}
else if (!format.fm) {
str.append(' ');
}
i1++;
} else {
str.append(coeff[j++]);
// canGroup = true;
i1++;
}
}
for (; j < coeff.length; j++) {
str.append(coeff[j]);
}
for (int i = 0; i < format.v; i++) {
str.append('0');
}
if (format.dot > 0) {
str.append(DOT);
}
for (int i = 0; i < format.dot; i++) {
if (i < d.scale()) {
str.append(coeff[prec+i]);
} else {
str.append('0');
}
}
format.getSuffix(str, d);
}
}
}
return str;
}
public Object parseObject(String source, ParsePosition pos) {
StringBuilder d = new StringBuilder(pos != null ? source.substring(pos.getIndex()) : source);
int start = 0; // first not white space symbol
try {
boolean negate = false;
int len = d.length(); // length of parsed string
for (; start < len; start++) {
if (d.charAt(start) != ' ')
break;
}
if (format.sign == SIGN.PR) {
if (d.charAt(start) == '<' && d.charAt(len-1) == '>') {
d.setCharAt(start++, ' ');
d.setLength(--len);
negate = true;
}
}
else if (format.sign == SIGN.MI) {
if (d.charAt(len-1) == '-') {
d.setLength(--len);
negate = true;
}
}
else if (format.sign == SIGN._S) {
char s = d.charAt(len-1);
if (s == '-') {
d.setLength(--len);
negate = true;
}
else if (s == '+') {
d.setLength(--len);
} else {
pos.setErrorIndex(start);
return null;
}
}
else if (format.sign == SIGN.S_) {
char s = d.charAt(start);
if (s == '-') {
d.setCharAt(start++, ' ');
negate = true;
}
else if (s == '+') {
d.setCharAt(start++, ' ');
} else {
pos.setErrorIndex(start);
return null;
}
}
else if (format.sign == SIGN.DEFAULT) {
char s = d.charAt(start);
if (s == '-') {
d.setCharAt(start++, ' ');
negate = true;
}
else if (s == '+') {
d.setCharAt(start++, ' ');
}
}
for (; start < len; start++) {
if (d.charAt(start) != ' ')
break;
}
int e = d.indexOf("E");
if (e == -1) {
e = d.indexOf("e");
}
int dot = source.indexOf(DOT);
int coefflen = len-start;
if (negate) {
coefflen++;
}
char coeff[] = new char[coefflen];
int scale = 0;
int precision = 0;
if (negate) {
precision++;
coeff[0] = '-';
}
if (format.sci) {
if (format.numbers.length() == 0 || format.numbers.indexOf('G') != -1) {
pos.setErrorIndex(start);
return null;
}
if (e == -1) {
pos.setErrorIndex(start);
return null;
}
coeff[precision++] = d.charAt(start);
scale = -Integer.valueOf(d.substring(e+1));
if (dot == -1) {
if (start+1 != e) {
pos.setErrorIndex(start);
return null;
}
}
else if (format.dot < e-dot-1) {
pos.setErrorIndex(dot);
return null;
} else {
if (start+1 != dot) {
pos.setErrorIndex(start);
return null;
}
scale += e-dot-1;
for (int i = dot+1; i < e; i++) {
coeff[precision++] = d.charAt(i);
}
}
} else {
if (e >= 0) {
pos.setErrorIndex(e);
return null;
}
if (dot != -1) {
coefflen--;
scale = len-dot-1;
if (format.dot < scale) {
pos.setErrorIndex(dot);
return null;
}
}
try {
int end = (dot < 0 ? len : dot);
int j = format.numbers.length()-1;
for (int i = start; i < end; i++, j--) {
char c = d.charAt(i);
if (format.numbers.charAt(j) == 'G') {
if (c != GROUP) {
pos.setErrorIndex(i);
return null;
}
} else {
if (Character.isDigit(c)) {
coeff[precision++] = c;
} else {
pos.setErrorIndex(i);
return null;
}
}
}
} catch (Exception ex) {
pos.setErrorIndex(start);
ex.printStackTrace();
return null;
}
if (dot != -1) {
for (int i = dot+1; i < len; i++) {
char c = d.charAt(i);
if (Character.isDigit(c)) {
coeff[precision++] = c;
} else {
pos.setErrorIndex(i);
return null;
}
}
}
}
String str = new String(coeff, 0, precision);
Number ret;
if (scale == 0 && precision < 10) {
ret = new Integer(Integer.valueOf(str));
} else {
ret = new BigDecimal(new BigInteger(str), scale);
}
pos.setIndex(len);
return ret;
} catch (Exception e) {
pos.setErrorIndex(start);
e.printStackTrace();
return null;
}
}
}