1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.metis.viewer;
18
19 import io.github.tonywasher.joceanus.metis.data.MetisDataDelta;
20 import io.github.tonywasher.joceanus.metis.data.MetisDataFieldValue;
21 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
22 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataMap;
23 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
24 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldDef;
25 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldSetDef;
26 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldVersionedDef;
27 import io.github.tonywasher.joceanus.metis.field.MetisFieldValidation;
28 import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionHistory;
29 import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedItem;
30 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
31 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
32 import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
33 import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
34
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Map.Entry;
39
40
41
42
43 public class MetisViewerFormatter {
44
45
46
47 protected static final int ITEMS_PER_PAGE = 50;
48
49
50
51
52 private static final String COLUMN_INDEX = "Index";
53
54
55
56
57 private static final String COLUMN_FIELD = MetisViewerResource.VIEWER_COLUMN_FIELD.getValue();
58
59
60
61
62 private static final String COLUMN_KEY = MetisViewerResource.VIEWER_COLUMN_KEY.getValue();
63
64
65
66
67 private static final String COLUMN_VALUE = MetisViewerResource.VIEWER_COLUMN_VALUE.getValue();
68
69
70
71
72 private static final String TABLE_LIST = "List";
73
74
75
76
77 private static final String TABLE_MAP = MetisViewerResource.VIEWER_TABLE_MAP.getValue();
78
79
80
81
82 private static final String TABLE_STACKTRACE = MetisViewerResource.VIEWER_TABLE_STACKTRACE.getValue();
83
84
85
86
87 private final MetisViewerBuilder theBuilder;
88
89
90
91
92
93
94
95 protected MetisViewerFormatter(final OceanusDataFormatter pFormatter) throws OceanusException {
96 theBuilder = new MetisViewerBuilder(pFormatter);
97 }
98
99
100
101
102
103
104 protected void formatPage(final MetisViewerPage pPage) {
105
106 theBuilder.resetDocument(pPage);
107
108
109 switch (pPage.getMode()) {
110 case CONTENTS:
111 formatHTMLObject(pPage.getObject());
112 break;
113 case SUMMARY:
114 formatHTMLCollection(pPage.getObject(), pPage.getItemNo());
115 break;
116 case ITEMS:
117 formatHTMLItem(pPage.getObject(), pPage.getItemNo());
118 break;
119 default:
120 break;
121 }
122
123
124 theBuilder.formatDocument();
125 }
126
127
128
129
130
131
132 private void formatHTMLObject(final Object pObject) {
133
134 final Object myObject = pObject instanceof MetisDataDelta myDelta
135 ? myDelta.getObject()
136 : pObject;
137
138
139 switch (myObject) {
140 case MetisFieldItem myField -> formatHTMLEosFieldItem(myField);
141 case StackTraceElement[] myStack -> formatHTMLStackTrace(myStack);
142 case OceanusProfile myProfile -> formatHTMLEosFieldItem(new MetisViewerProfileWrapper(myProfile));
143 case Throwable myThrow -> formatHTMLEosFieldItem(new MetisViewerExceptionWrapper(myThrow));
144 default -> formatHTMLUnknown(myObject);
145 }
146 }
147
148
149
150
151
152
153
154 private void formatHTMLCollection(final Object pObject,
155 final int pStart) {
156
157 Object myObject = pObject instanceof MetisDataDelta myDelta
158 ? myDelta.getObject()
159 : pObject;
160
161
162 if (myObject instanceof MetisDataList<?> myList) {
163 myObject = myList.getUnderlyingList();
164 } else if (myObject instanceof MetisDataMap<?, ?> myMap) {
165 myObject = myMap.getUnderlyingMap();
166 }
167
168
169 if (myObject instanceof List<?> myList) {
170 formatHTMLListSection(myList, pStart);
171
172
173 } else if (myObject instanceof Map<?, ?> myMap) {
174 formatHTMLMapSection(myMap, pStart);
175 }
176 }
177
178
179
180
181
182
183
184 private void formatHTMLItem(final Object pObject,
185 final int pIndex) {
186
187 Object myObject = pObject instanceof MetisDataDelta myDelta
188 ? myDelta.getObject()
189 : pObject;
190
191
192 if (myObject instanceof MetisDataList<?> myList) {
193 myObject = myList.getUnderlyingList();
194 }
195
196
197 if (myObject instanceof List<?> myList) {
198 formatHTMLListItem(myList, pIndex);
199 }
200 }
201
202
203
204
205
206
207 private void formatHTMLEosFieldItem(final MetisFieldItem pItem) {
208
209 final MetisFieldSetDef myFields = pItem.getDataFieldSet();
210 final boolean isVersioned = pItem instanceof MetisFieldVersionedItem;
211 final MetisFieldVersionedItem myItem = isVersioned
212 ? (MetisFieldVersionedItem) pItem
213 : null;
214
215
216 theBuilder.newTitle(myFields.getName());
217 theBuilder.newTable();
218 theBuilder.newTitleCell(COLUMN_FIELD);
219 theBuilder.newTitleCell(COLUMN_VALUE);
220
221
222 final Iterator<MetisFieldDef> myIterator = myFields.fieldIterator();
223 while (myIterator.hasNext()) {
224
225 final MetisFieldDef myField = myIterator.next();
226
227
228 final Object myValue = myField.isCalculated()
229 ? MetisDataFieldValue.SKIP
230 : myField.getFieldValue(pItem);
231
232
233 if (skipValue(myValue)) {
234 continue;
235 }
236
237
238 theBuilder.newTableRow();
239 theBuilder.newDataCell(myField.getFieldId().getId());
240 if (myItem != null
241 && myField instanceof MetisFieldVersionedDef
242 && myItem.fieldChanged(myField).isDifferent()) {
243 theBuilder.newDataCell(myValue, true);
244 } else {
245 theBuilder.newDataCell(myValue);
246 }
247 }
248 }
249
250
251
252
253
254
255
256 private static boolean skipValue(final Object pValue) {
257
258 Object myValue = pValue;
259
260
261 if (myValue instanceof MetisDataList<?> myList) {
262 myValue = myList.getUnderlyingList();
263 }
264 if (myValue instanceof List<?> myList) {
265 return myList.isEmpty();
266 }
267
268
269 if (myValue instanceof MetisDataMap<?, ?> myMap) {
270 myValue = myMap.getUnderlyingMap();
271 }
272 if (myValue instanceof Map<?, ?> myMap) {
273 return myMap.isEmpty();
274 }
275
276
277 if (myValue instanceof MetisFieldVersionHistory myHistory) {
278 return !myHistory.hasHistory();
279 }
280 if (myValue instanceof MetisFieldValidation myValid) {
281 return !myValid.hasErrors();
282 }
283
284
285 if (myValue instanceof OceanusDecimal myDecimal) {
286 return myDecimal.isZero();
287 }
288 if (myValue instanceof Number myNumber) {
289 return myNumber.longValue() == 0;
290 }
291
292
293 if (myValue instanceof Boolean myBool) {
294 return !myBool;
295 }
296
297
298 return myValue == null
299 || MetisDataFieldValue.SKIP.equals(myValue);
300 }
301
302
303
304
305
306
307
308 private void formatHTMLListItem(final List<?> pList,
309 final int pIndex) {
310
311 final Object myObject = pList.get(pIndex - 1);
312
313
314 formatHTMLObject(myObject);
315 }
316
317
318
319
320
321
322
323 private void formatHTMLListSection(final List<?> pList,
324 final int pStart) {
325
326 theBuilder.newTitle(TABLE_LIST);
327 theBuilder.newTable();
328 theBuilder.newTitleCell(COLUMN_INDEX);
329 theBuilder.newTitleCell(COLUMN_VALUE);
330
331
332 if (!pList.isEmpty()) {
333
334 final int myStart = (pStart - 1) * ITEMS_PER_PAGE;
335
336
337 final Iterator<?> myIterator = pList.listIterator(myStart);
338
339
340 int myCount = ITEMS_PER_PAGE;
341 int myIndex = myStart + 1;
342 while (myIterator.hasNext()
343 && myCount-- > 0) {
344
345 final Object myObject = myIterator.next();
346
347
348 theBuilder.newTableRow();
349 theBuilder.newDataCell(myIndex++);
350 theBuilder.newDataCell(myObject);
351 }
352 }
353 }
354
355
356
357
358
359
360
361 private void formatHTMLMapSection(final Map<?, ?> pMap,
362 final int pStart) {
363
364
365 theBuilder.newTitle(TABLE_MAP);
366 theBuilder.newTable();
367 theBuilder.newTitleCell(COLUMN_INDEX);
368 theBuilder.newTitleCell(COLUMN_KEY);
369 theBuilder.newTitleCell(COLUMN_VALUE);
370
371
372 if (!pMap.isEmpty()) {
373
374 int myCount = (pStart - 1) * ITEMS_PER_PAGE;
375 int myIndex = myCount + 1;
376
377
378 final Iterator<?> myIterator = pMap.entrySet().iterator();
379 if (myCount > 0) {
380
381 while (myIterator.hasNext()
382 && myCount-- > 0) {
383 myIterator.next();
384 }
385 }
386
387
388 myCount = ITEMS_PER_PAGE;
389 while (myIterator.hasNext()
390 && (myCount-- > 0)) {
391
392 final Entry<?, ?> myEntry = (Entry<?, ?>) myIterator.next();
393
394
395 theBuilder.newTableRow();
396 theBuilder.newDataCell(myIndex++);
397 theBuilder.newDataCell(myEntry.getKey());
398 theBuilder.newDataCell(myEntry.getValue());
399 }
400 }
401 }
402
403
404
405
406
407
408 private void formatHTMLStackTrace(final StackTraceElement[] pStack) {
409
410 theBuilder.newTitle(TABLE_STACKTRACE);
411 theBuilder.newTable();
412 theBuilder.newTitleCell(TABLE_STACKTRACE);
413
414
415 for (StackTraceElement st : pStack) {
416
417 theBuilder.newTableRow();
418 theBuilder.newDataCell(st.toString());
419 }
420 }
421
422
423
424
425
426
427 private void formatHTMLUnknown(final Object pObject) {
428
429 theBuilder.newTitle("Unknown");
430 theBuilder.newTable();
431 theBuilder.newTitleCell(COLUMN_FIELD);
432 theBuilder.newTitleCell(COLUMN_VALUE);
433
434
435 theBuilder.newTableRow();
436 theBuilder.newDataCell("Class");
437 theBuilder.newDataCell(pObject != null
438 ? pObject.getClass()
439 : null);
440
441
442 theBuilder.newTableRow();
443 theBuilder.newDataCell("Value");
444 theBuilder.newDataCell(pObject);
445 }
446 }