1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.data;
18
19 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20 import io.github.tonywasher.joceanus.oceanus.convert.OceanusDataConverter;
21 import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
22 import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
23 import io.github.tonywasher.joceanus.metis.data.MetisDataEditState;
24 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
25 import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
26 import io.github.tonywasher.joceanus.metis.data.MetisDataState;
27 import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
28 import io.github.tonywasher.joceanus.metis.field.MetisFieldState;
29 import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionValues;
30 import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedItem;
31 import io.github.tonywasher.joceanus.metis.list.MetisListKey;
32 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList.PrometheusListStyle;
33 import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
34
35 import java.util.Iterator;
36
37
38
39
40
41
42
43
44 public abstract class PrometheusDataItem
45 extends MetisFieldVersionedItem
46 implements PrometheusTableItem, Comparable<Object> {
47
48
49
50 private static final MetisFieldSet<PrometheusDataItem> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusDataItem.class);
51
52
53
54
55 static {
56 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATALIST_NAME, PrometheusDataItem::getList);
57 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_BASE, PrometheusDataItem::getBase);
58 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_TOUCH, PrometheusDataItem::getTouchStatus);
59 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_HEADER, PrometheusDataItem::isHeader);
60 }
61
62
63
64
65 public static final String ERROR_VALIDATION = PrometheusDataResource.DATAITEM_ERROR_VALIDATION.getValue();
66
67
68
69
70 public static final String ERROR_RESOLUTION = PrometheusDataResource.DATAITEM_ERROR_RESOLUTION.getValue();
71
72
73
74
75 public static final String ERROR_DUPLICATE = PrometheusDataResource.DATAITEM_ERROR_DUPLICATE.getValue();
76
77
78
79
80 public static final String ERROR_UNKNOWN = PrometheusDataResource.DATAITEM_ERROR_UNKNOWN.getValue();
81
82
83
84
85 public static final String ERROR_EXIST = PrometheusDataResource.DATAITEM_ERROR_EXIST.getValue();
86
87
88
89
90 public static final String ERROR_MISSING = PrometheusDataResource.DATAITEM_ERROR_MISSING.getValue();
91
92
93
94
95 public static final String ERROR_LENGTH = PrometheusDataResource.DATAITEM_ERROR_LENGTH.getValue();
96
97
98
99
100 public static final String ERROR_NEGATIVE = PrometheusDataResource.DATAITEM_ERROR_NEGATIVE.getValue();
101
102
103
104
105 public static final String ERROR_POSITIVE = PrometheusDataResource.DATAITEM_ERROR_POSITIVE.getValue();
106
107
108
109
110 public static final String ERROR_ZERO = PrometheusDataResource.DATAITEM_ERROR_ZERO.getValue();
111
112
113
114
115 public static final String ERROR_RANGE = PrometheusDataResource.DATAITEM_ERROR_RANGE.getValue();
116
117
118
119
120 public static final String ERROR_DISABLED = PrometheusDataResource.DATAITEM_ERROR_DISABLED.getValue();
121
122
123
124
125 public static final String ERROR_CREATEITEM = PrometheusDataResource.DATAITEM_ERROR_CREATE.getValue();
126
127
128
129
130 public static final String ERROR_MULT = PrometheusDataResource.DATAITEM_ERROR_MULTIPLE.getValue();
131
132
133
134
135 public static final String ERROR_INVALIDCHAR = PrometheusDataResource.DATAITEM_ERROR_INVALIDCHAR.getValue();
136
137
138
139
140 public static final int NAMELEN = 30;
141
142
143
144
145 public static final int DESCLEN = 50;
146
147
148
149
150 private PrometheusDataList<?> theList;
151
152
153
154
155 private PrometheusDataItem theBase;
156
157
158
159
160 private boolean isHeader;
161
162
163
164
165 private final PrometheusDataTouch theTouchStatus;
166
167
168
169
170
171
172
173 protected PrometheusDataItem(final PrometheusDataList<?> pList,
174 final Integer uId) {
175
176 setIndexedId(uId);
177 theList = pList;
178
179
180 pList.setNewId(this);
181
182
183 theTouchStatus = new PrometheusDataTouch();
184 }
185
186
187
188
189
190
191
192 protected PrometheusDataItem(final PrometheusDataList<?> pList,
193 final PrometheusDataValues pValues) {
194
195 this(pList, pValues.getValue(MetisDataResource.DATA_ID, Integer.class));
196 }
197
198
199
200
201
202
203
204 protected PrometheusDataItem(final PrometheusDataList<?> pList,
205 final PrometheusDataItem pBase) {
206
207 this(pList, pBase.getIndexedId());
208
209
210 getValues().copyFrom(pBase.getValues());
211
212
213 final PrometheusListStyle myStyle = pList.getStyle();
214 final PrometheusListStyle myBaseStyle = pBase.getList().getStyle();
215 final MetisDataState myState = pBase.getState();
216
217
218 switch (myStyle) {
219
220 case UPDATE:
221 switch (myState) {
222
223 case DELNEW:
224 case NEW:
225 getValues().setVersion(1);
226 break;
227
228 case DELETED:
229 getValuesHistory().pushHistory(1);
230 break;
231
232
233
234
235 case CHANGED:
236 setHistory(pBase);
237 break;
238
239
240 default:
241 break;
242 }
243
244
245 theBase = pBase;
246 break;
247
248
249 case EDIT:
250
251 switch (myBaseStyle) {
252
253 case CORE:
254 theBase = pBase;
255 copyFlags(pBase);
256 break;
257
258 case EDIT:
259
260 getValues().setVersion(pList.getVersion() + 1);
261
262
263 setIndexedId(0);
264 pList.setNewId(this);
265 break;
266 default:
267 break;
268 }
269 break;
270
271
272 case CORE:
273
274 getValues().setVersion(pList.getVersion() + 1);
275
276
277 if (myBaseStyle == PrometheusListStyle.EDIT) {
278
279 setIndexedId(0);
280 pList.setNewId(this);
281 }
282 break;
283
284
285 case COPY:
286 throw new IllegalArgumentException("Illegal creation of COPY element");
287
288
289 case CLONE:
290 case DIFFER:
291 default:
292 break;
293 }
294 }
295
296
297
298
299
300
301 public int getValueSetVersion() {
302 return getValues().getVersion();
303 }
304
305 @Override
306 public String formatObject(final OceanusDataFormatter pFormatter) {
307 return this.getDataFieldSet().getName();
308 }
309
310
311
312
313
314
315 public PrometheusDataList<?> getList() {
316 return theList;
317 }
318
319
320
321
322
323
324 public PrometheusDataSet getDataSet() {
325 return getTheDataSet();
326 }
327
328
329
330
331
332
333 private PrometheusDataSet getTheDataSet() {
334 return theList.getDataSet();
335 }
336
337
338
339
340
341
342 public PrometheusListStyle getStyle() {
343 return theList.getStyle();
344 }
345
346 @Override
347 public MetisListKey getItemType() {
348 return theList.getItemType();
349 }
350
351 @Override
352 public boolean isActive() {
353 return theTouchStatus.isActive();
354 }
355
356
357
358
359
360
361 public boolean isDisabled() {
362 return false;
363 }
364
365
366
367
368
369
370 public PrometheusDataTouch getTouchStatus() {
371 return theTouchStatus;
372 }
373
374 @Override
375 public boolean isEditable() {
376 return !isDeleted();
377 }
378
379 @Override
380 public boolean isHeader() {
381 return isHeader;
382 }
383
384
385
386
387
388
389 protected void setHeader(final boolean pHeader) {
390 isHeader = pHeader;
391 }
392
393
394
395
396
397
398 public boolean isLocked() {
399 return false;
400 }
401
402
403
404
405
406
407 public boolean isListLocked() {
408 return false;
409 }
410
411
412
413
414 public void deRegister() {
415 }
416
417
418
419
420 public void clearActive() {
421 theTouchStatus.resetTouches();
422 }
423
424
425
426
427
428
429 public void clearTouches(final MetisListKey pItemType) {
430 theTouchStatus.resetTouches(pItemType);
431 }
432
433
434
435
436
437
438 public void touchItem(final PrometheusDataItem pObject) {
439 theTouchStatus.touchItem(pObject.getItemType());
440 }
441
442
443
444
445 public void touchUnderlyingItems() {
446 }
447
448
449
450
451 public void touchOnUpdate() {
452 }
453
454
455
456
457 public void adjustMapForItem() {
458 }
459
460
461
462
463 public void updateMaps() {
464
465 clearActive();
466 touchUnderlyingItems();
467
468
469 adjustMapForItem();
470 }
471
472
473
474
475
476
477 public PrometheusDataItem getBase() {
478 return theBase;
479 }
480
481
482
483
484
485
486 public void setBase(final PrometheusDataItem pBase) {
487 theBase = pBase;
488 }
489
490
491
492
493 public void unLink() {
494 theList.remove(this);
495 }
496
497
498
499
500 public void setNewVersion() {
501 getValues().setVersion(getNextVersion());
502 }
503
504 @Override
505 public int getNextVersion() {
506 return theList.getVersion() + 1;
507 }
508
509 @Override
510 public void popHistory() {
511 rewindToVersion(theList.getVersion());
512 }
513
514 @Override
515 public void rewindToVersion(final int pVersion) {
516
517 if (getOriginalValues().getVersion() > pVersion) {
518
519 unLink();
520 deRegister();
521
522
523 return;
524 }
525
526
527 while (getValues().getVersion() > pVersion) {
528
529 getValuesHistory().popTheHistory();
530 }
531 }
532
533
534
535
536
537
538
539 public final void setHistory(final PrometheusDataItem pBase) {
540 getValuesHistory().setHistory(pBase.getOriginalValues());
541 }
542
543 @Override
544 public MetisDataDifference fieldChanged(final MetisFieldDef pField) {
545 return pField instanceof MetisFieldVersionedDef
546 ? getValuesHistory().fieldChanged(pField)
547 : MetisDataDifference.IDENTICAL;
548 }
549
550
551
552
553 public void setValidEdit() {
554 final MetisDataState myState = getState();
555 if (myState == MetisDataState.CLEAN) {
556 setEditState(MetisDataEditState.CLEAN);
557 } else if (theList.getStyle() == PrometheusListStyle.CORE) {
558 setEditState(MetisDataEditState.DIRTY);
559 } else {
560 setEditState(MetisDataEditState.VALID);
561 }
562 }
563
564 @Override
565 public void addError(final String pError,
566 final MetisDataFieldId pField) {
567
568 super.addError(pError, pField);
569
570
571 theList.setEditState(MetisDataEditState.ERROR);
572 }
573
574
575
576
577
578
579 private void copyFlags(final PrometheusDataItem pItem) {
580 theTouchStatus.copyMap(pItem.theTouchStatus);
581 }
582
583
584
585
586
587
588 public void resolveDataSetLinks() throws OceanusException {
589 }
590
591
592
593
594
595
596
597
598 protected void resolveDataLink(final MetisDataFieldId pFieldId,
599 final PrometheusDataList<?> pList) throws OceanusException {
600
601 final MetisFieldVersionValues myValues = getValues();
602
603
604 Object myValue = myValues.getValue(pFieldId);
605
606
607 if (myValue instanceof PrometheusDataItem myItem) {
608 myValue = myItem.getIndexedId();
609 }
610
611
612 if (myValue instanceof Integer i) {
613 final PrometheusDataItem myItem = pList.findItemById(i);
614 if (myItem == null) {
615 addError(ERROR_UNKNOWN, pFieldId);
616 throw new PrometheusDataException(this, ERROR_RESOLUTION);
617 }
618 myValues.setValue(pFieldId, myItem);
619
620
621 } else if (myValue instanceof String s) {
622 final PrometheusDataItem myItem = pList.findItemByName(s);
623 if (myItem == null) {
624 addError(ERROR_UNKNOWN, pFieldId);
625 throw new PrometheusDataException(this, ERROR_RESOLUTION);
626 }
627 myValues.setValue(pFieldId, myItem);
628 }
629 }
630
631
632
633
634
635
636
637 public boolean includeXmlField(final MetisDataFieldId pField) {
638 return false;
639 }
640
641 @Override
642 public boolean equals(final Object pThat) {
643
644 if (this == pThat) {
645 return true;
646 }
647 if (pThat == null) {
648 return false;
649 }
650
651
652 if (pThat.getClass() != getClass()) {
653 return false;
654 }
655
656
657 final PrometheusDataItem myItem = (PrometheusDataItem) pThat;
658
659
660 if (compareId(myItem) != 0) {
661 return false;
662 }
663
664
665 final Iterator<MetisFieldDef> myIterator = getDataFieldSet().fieldIterator();
666 while (myIterator.hasNext()) {
667
668 final MetisFieldDef myField = myIterator.next();
669
670
671 if (!(myField instanceof MetisFieldVersionedDef myVersioned)
672 || !myVersioned.isEquality()) {
673 continue;
674 }
675
676
677 final Object myValue = myField.getFieldValue(this);
678 final Object myNew = myField.getFieldValue(myItem);
679
680
681 if (!MetisDataDifference.isEqual(myValue, myNew)) {
682 return false;
683 }
684 }
685
686
687 return true;
688 }
689
690 @Override
691 public int hashCode() {
692
693 return getIndexedId();
694 }
695
696 @Override
697 public int compareTo(final Object pThat) {
698
699 if (this.equals(pThat)) {
700 return 0;
701 }
702 if (pThat == null) {
703 return -1;
704 }
705
706
707 if (!(pThat instanceof PrometheusDataItem)) {
708 return -1;
709 }
710
711
712 final PrometheusDataItem myThat = (PrometheusDataItem) pThat;
713 int iDiff = getItemType().getItemKey() - myThat.getItemType().getItemKey();
714 if (iDiff != 0) {
715 return iDiff;
716 }
717
718
719 iDiff = compareValues(myThat);
720 return iDiff != 0 ? iDiff : compareId(myThat);
721 }
722
723
724
725
726
727
728
729 protected abstract int compareValues(PrometheusDataItem pThat);
730
731
732
733
734
735
736
737 protected int compareId(final PrometheusDataItem pThat) {
738 return getIndexedId() - pThat.getIndexedId();
739 }
740
741
742
743
744
745
746 protected MetisDataState getBaseState() {
747 final PrometheusDataItem myBase = getBase();
748 return (myBase == null)
749 ? MetisDataState.NOSTATE
750 : myBase.getState();
751 }
752
753
754
755
756
757
758 public int indexOf() {
759
760 return theList.indexOf(this);
761 }
762
763
764
765
766
767
768
769 public boolean applyChanges(final PrometheusDataItem pElement) {
770 return false;
771 }
772
773
774
775
776
777
778 public void validate() {
779 getList().getValidator().validate(this);
780 }
781
782
783
784
785
786
787
788
789 public static boolean validString(final String pString,
790 final String pDisallowed) {
791
792 for (int i = 0; i < pString.length(); i++) {
793 final int myChar = pString.codePointAt(i);
794
795 if (Character.isISOControl(myChar)) {
796 return false;
797 }
798
799
800 if (pDisallowed != null
801 && pDisallowed.indexOf(myChar) != -1) {
802 return false;
803 }
804 }
805 return true;
806 }
807
808
809
810
811
812
813
814 public static int byteLength(final String pString) {
815 return OceanusDataConverter.stringToByteArray(pString).length;
816 }
817
818
819
820
821 public void removeItem() {
822 theList.remove(this);
823 }
824
825
826
827
828
829
830
831 public MetisFieldState getFieldState(final MetisDataFieldId pField) {
832
833 if (isDeleted()) {
834 return MetisFieldState.DELETED;
835
836
837 } else if (hasErrors() && hasErrors(pField)) {
838 return MetisFieldState.ERROR;
839
840
841 } else if (fieldChanged(pField).isDifferent()) {
842 return MetisFieldState.CHANGED;
843
844
845 } else {
846 switch (getState()) {
847 case NEW:
848 return MetisFieldState.NEW;
849 case RECOVERED:
850 return MetisFieldState.RESTORED;
851 default:
852 return MetisFieldState.NORMAL;
853 }
854 }
855 }
856
857
858
859
860
861
862 public MetisFieldState getItemState() {
863
864 if (isDeleted()) {
865 return MetisFieldState.DELETED;
866
867
868 } else if (hasErrors()) {
869 return MetisFieldState.ERROR;
870
871
872 } else if (hasHistory()) {
873 return MetisFieldState.CHANGED;
874
875
876 } else {
877 switch (getState()) {
878 case NEW:
879 return MetisFieldState.NEW;
880 case RECOVERED:
881 return MetisFieldState.RESTORED;
882 default:
883 return MetisFieldState.NORMAL;
884 }
885 }
886 }
887 }