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