001    package org.ujmp.core.util;
002    
003    import java.text.DateFormat;
004    import java.text.DecimalFormat;
005    import java.text.DecimalFormatSymbols;
006    import java.text.FieldPosition;
007    import java.text.Format;
008    import java.text.NumberFormat;
009    import java.text.ParsePosition;
010    import java.text.SimpleDateFormat;
011    import java.util.Date;
012    
013    import org.ujmp.core.Coordinates;
014    import org.ujmp.core.Matrix;
015    import org.ujmp.core.bigdecimalmatrix.BigDecimalMatrix;
016    import org.ujmp.core.datematrix.DateMatrix;
017    import org.ujmp.core.exceptions.MatrixException;
018    
019    public class UJMPFormat extends Format {
020            private static final long serialVersionUID = -557618747324763226L;
021    
022            private static UJMPFormat multiLineInstance = new UJMPFormat(true, 10, true);
023    
024            private static UJMPFormat singleLineInstance = new UJMPFormat(false, 100, false);
025    
026            private NumberFormat defaultNumberFormat = null;
027    
028            private NumberFormat exponentialNumberFormat = null;
029    
030            private DateFormat dateFormat = null;
031    
032            private boolean multiLine = true;
033    
034            private boolean usePadding = false;
035    
036            private int width = 10;
037    
038            public UJMPFormat(boolean multiLine, int width, boolean usePadding) {
039                    DecimalFormatSymbols symbols = new DecimalFormatSymbols(UJMPSettings.getLocale());
040                    symbols.setNaN("NaN");
041                    symbols.setInfinity("Inf");
042                    defaultNumberFormat = new DecimalFormat("0.0000", symbols);
043                    exponentialNumberFormat = new DecimalFormat("0.000E000", symbols);
044                    dateFormat = new SimpleDateFormat("yyyy-mm-dd");
045                    this.multiLine = multiLine;
046                    this.width = width;
047                    this.usePadding = usePadding;
048            }
049    
050            public static final UJMPFormat getMultiLineInstance() {
051                    return multiLineInstance;
052            }
053    
054            public static final UJMPFormat getSingleLineInstance() {
055                    return singleLineInstance;
056            }
057    
058            @Override
059            public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
060                    if (obj == null) {
061                            if (usePadding) {
062                                    pad(toAppendTo, ' ', width);
063                            }
064                            return toAppendTo;
065                    } else if (obj instanceof String) {
066                            return format((String) obj, toAppendTo, pos);
067                    } else if (obj instanceof Matrix) {
068                            return format((Matrix) obj, toAppendTo, pos);
069                    } else if (obj instanceof Date) {
070                            return format((Date) obj, toAppendTo, pos);
071                    } else if (obj instanceof Number) {
072                            return format((Number) obj, toAppendTo, pos);
073                    } else {
074                            return format(String.valueOf(obj), toAppendTo, pos);
075                    }
076            }
077    
078            private StringBuffer format(Matrix obj, StringBuffer toAppendTo, FieldPosition pos) {
079                    if (obj == null) {
080                            if (usePadding) {
081                                    pad(toAppendTo, ' ', width);
082                            }
083                            return toAppendTo;
084                    } else if (obj.isScalar()) {
085                            Object v = obj.getAsObject(obj.allCoordinates().iterator().next());
086                            return format(v, toAppendTo, pos);
087                    } else if (multiLine) {
088                            return formatMultiLine(obj, toAppendTo, pos);
089                    } else {
090                            toAppendTo.append("[Matrix]");
091                            return toAppendTo;
092                    }
093            }
094    
095            private StringBuffer format(Date obj, StringBuffer toAppendTo, FieldPosition pos) {
096                    int length = toAppendTo.length();
097                    toAppendTo = dateFormat.format(obj, toAppendTo, pos);
098                    length = width - (toAppendTo.length() - length);
099                    if (usePadding) {
100                            pad(toAppendTo, ' ', length);
101                    }
102                    return toAppendTo;
103            }
104    
105            private StringBuffer pad(StringBuffer s, char c, int count) {
106                    for (int i = 0; i < count; i++) {
107                            s.append(c);
108                    }
109                    return s;
110            }
111    
112            private StringBuffer format(String obj, StringBuffer toAppendTo, FieldPosition pos) {
113                    if (obj != null && obj.length() > width) {
114                            obj = obj.substring(0, width);
115                    }
116                    if (obj != null) {
117                            toAppendTo.append(obj);
118                            if (usePadding) {
119                                    pad(toAppendTo, ' ', width - obj.length());
120                            }
121                            return toAppendTo;
122                    } else {
123                            if (usePadding) {
124                                    pad(toAppendTo, ' ', width);
125                            }
126                            return toAppendTo;
127                    }
128            }
129    
130            private StringBuffer format(Number obj, StringBuffer toAppendTo, FieldPosition pos) {
131                    String s = defaultNumberFormat.format(obj);
132                    if (s.length() > width) {
133                            s = exponentialNumberFormat.format(obj);
134                    }
135                    if (usePadding) {
136                            pad(toAppendTo, ' ', width - s.length());
137                    }
138                    toAppendTo.append(s);
139                    return toAppendTo;
140            }
141    
142            private StringBuffer formatMultiLine(Matrix m, StringBuffer toAppendTo, FieldPosition pos) {
143                    long maxRows = UJMPSettings.getMaxRowsToPrint();
144                    long maxColumns = UJMPSettings.getMaxColumnsToPrint();
145    
146                    final String EOL = System.getProperty("line.separator");
147    
148                    long rowCount = m.getRowCount();
149                    long columnCount = m.getColumnCount();
150                    long[] cursor = new long[m.getDimensionCount()];
151    
152                    if (m.getDimensionCount() > 2) {
153                            toAppendTo.append(m.getDimensionCount());
154                            toAppendTo.append("D-Matrix [");
155                            toAppendTo.append(Coordinates.toString('x', m.getSize()));
156                            toAppendTo.append("]: only two dimensions are printed");
157                            toAppendTo.append(EOL);
158                    }
159    
160                    if (m.getAnnotation() != null) {
161                            format(m.getLabel(), toAppendTo, pos);
162                            toAppendTo.append("   ");
163                            for (int col = 0; col < columnCount && col < maxColumns; col++) {
164                                    format(m.getColumnLabel(col), toAppendTo, pos);
165                                    if (col < columnCount - 1) {
166                                            toAppendTo.append(' ');
167                                    }
168                            }
169                            toAppendTo.append(EOL);
170                            pad(toAppendTo, '=', width);
171                            toAppendTo.append("   ");
172                            for (int col = 0; col < columnCount && col < maxColumns; col++) {
173                                    pad(toAppendTo, '-', width);
174                                    if (col < columnCount - 1) {
175                                            toAppendTo.append(' ');
176                                    }
177                            }
178                            toAppendTo.append(EOL);
179                    }
180    
181                    for (cursor[Matrix.ROW] = 0; cursor[Matrix.ROW] < rowCount && cursor[Matrix.ROW] < maxRows; cursor[Matrix.ROW]++) {
182                            if (m.getAnnotation() != null) {
183                                    format(m.getRowLabel(cursor[Matrix.ROW]), toAppendTo, pos);
184                                    toAppendTo.append(" | ");
185                            }
186                            for (cursor[Matrix.COLUMN] = 0; cursor[Matrix.COLUMN] < columnCount
187                                            && cursor[Matrix.COLUMN] < maxColumns; cursor[Matrix.COLUMN]++) {
188                                    Object o = m.getAsObject(cursor);
189                                    if (o == null && (m instanceof BigDecimalMatrix || m instanceof DateMatrix)) {
190                                            toAppendTo = format(Double.NaN, toAppendTo, pos);
191                                    } else {
192                                            toAppendTo = format(o, toAppendTo, pos);
193                                    }
194                                    if (cursor[Matrix.COLUMN] < columnCount - 1) {
195                                            toAppendTo.append(' ');
196                                    }
197                            }
198                            toAppendTo.append(EOL);
199                    }
200    
201                    if (rowCount == 0 || columnCount == 0) {
202                            toAppendTo.append("[" + rowCount + "x" + columnCount + "]" + EOL);
203                    } else if (rowCount > UJMPSettings.getMaxRowsToPrint()
204                                    || columnCount > UJMPSettings.getMaxColumnsToPrint()) {
205                            toAppendTo.append("[...]");
206                    }
207    
208                    return toAppendTo;
209            }
210    
211            @Override
212            public Object parseObject(String source, ParsePosition pos) {
213                    throw new MatrixException("not implemented");
214            }
215    }