1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.views;
18
19 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
21 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
22 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
23 import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
24 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogManager;
25 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogger;
26 import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
27 import io.github.tonywasher.joceanus.metis.data.MetisDataEditState;
28 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
29 import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
30 import io.github.tonywasher.joceanus.metis.list.MetisListKey;
31 import io.github.tonywasher.joceanus.metis.ui.MetisErrorPanel;
32 import io.github.tonywasher.joceanus.metis.viewer.MetisViewerErrorList;
33 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
34 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
35 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList.PrometheusDataListSet;
36 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
37 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
38
39 import java.util.Iterator;
40 import java.util.LinkedHashMap;
41 import java.util.Map;
42
43
44
45
46 public class PrometheusEditSet
47 implements MetisFieldItem, OceanusEventProvider<PrometheusDataEvent>, PrometheusDataListSet {
48
49
50
51 @SuppressWarnings("rawtypes")
52 private static final MetisFieldSet<PrometheusEditSet> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusEditSet.class);
53
54
55
56
57 static {
58 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATASET_VERSION, PrometheusEditSet::getVersion);
59 }
60
61
62
63
64 private static final OceanusLogger LOGGER = OceanusLogManager.getLogger(PrometheusEditSet.class);
65
66
67
68
69 private final OceanusEventManager<PrometheusDataEvent> theEventManager;
70
71
72
73
74 @SuppressWarnings("rawtypes")
75 private final MetisFieldSet<PrometheusEditSet> theLocalFields;
76
77
78
79
80 private final Map<MetisListKey, PrometheusEditEntry<?>> theMap;
81
82
83
84
85 private final PrometheusDataControl theControl;
86
87
88
89
90 private PrometheusDataSet theDataSet;
91
92
93
94
95 private int theVersion;
96
97
98
99
100 private Boolean itemEditing = Boolean.FALSE;
101
102
103
104
105
106
107 public PrometheusEditSet(final PrometheusDataControl pControl) {
108 this(pControl, pControl.getData());
109 }
110
111
112
113
114
115
116
117 public PrometheusEditSet(final PrometheusDataControl pControl,
118 final PrometheusDataSet pDataSet) {
119
120 theControl = pControl;
121 theDataSet = pDataSet;
122
123
124 theEventManager = new OceanusEventManager<>();
125
126
127 theLocalFields = MetisFieldSet.newFieldSet(this);
128
129
130 theMap = new LinkedHashMap<>();
131 }
132
133 @SuppressWarnings("rawtypes")
134 @Override
135 public MetisFieldSet<PrometheusEditSet> getDataFieldSet() {
136 return theLocalFields;
137 }
138
139 @Override
140 public String formatObject(final OceanusDataFormatter pFormatter) {
141 return getDataFieldSet().getName();
142 }
143
144 @Override
145 public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
146 return theEventManager.getEventRegistrar();
147 }
148
149
150
151
152
153
154 public void setEditing(final Boolean pFlag) {
155 itemEditing = pFlag;
156 }
157
158
159
160
161
162
163 public Boolean isEditing() {
164 return itemEditing;
165 }
166
167
168
169
170
171
172 public int getVersion() {
173 return theVersion;
174 }
175
176
177
178
179
180
181 public PrometheusDataSet getDataSet() {
182 return theDataSet;
183 }
184
185
186
187
188
189
190 public void setDataSet(final PrometheusDataSet pDataSet) {
191 theDataSet = pDataSet;
192 }
193
194
195
196
197
198
199
200
201 public <T extends PrometheusDataItem> PrometheusEditEntry<T> registerType(final MetisListKey pDataType) {
202
203 @SuppressWarnings("unchecked") final PrometheusEditEntry<T> myEntry = (PrometheusEditEntry<T>) theMap.computeIfAbsent(pDataType, t -> {
204
205 final PrometheusEditEntry<T> myNewEntry = new PrometheusEditEntry<>(t);
206 theLocalFields.declareLocalField(myNewEntry.getName(), n -> myNewEntry);
207 return myNewEntry;
208 });
209
210
211 myEntry.setDataList(null);
212 return myEntry;
213 }
214
215
216
217
218
219
220
221
222
223
224
225 @Override
226 public <L extends PrometheusDataList<?>> L getDataList(final MetisListKey pDataType,
227 final Class<L> pClass) {
228
229 final PrometheusEditEntry<?> myEntry = theMap.get(pDataType);
230
231
232 return myEntry != null
233 ? pClass.cast(myEntry.getDataList())
234 : theDataSet.getDataList(pDataType, pClass);
235 }
236
237 @Override
238 public boolean hasDataType(final MetisListKey pDataType) {
239 return theMap.containsKey(pDataType);
240 }
241
242
243
244
245
246
247
248
249 public <T extends PrometheusDataItem> void setEditEntryList(final MetisListKey pDataType,
250 final PrometheusDataList<T> pList) {
251 @SuppressWarnings("unchecked") final PrometheusEditEntry<T> myEntry = (PrometheusEditEntry<T>) theMap.get(pDataType);
252 myEntry.setDataList(pList);
253 }
254
255
256
257
258
259
260 public Iterator<MetisListKey> keyIterator() {
261 return theMap.keySet().iterator();
262 }
263
264
265
266
267
268
269 public Iterator<PrometheusEditEntry<?>> listIterator() {
270 return theMap.values().iterator();
271 }
272
273
274
275
276 public void incrementVersion() {
277
278 final OceanusProfile myTask = theControl.getActiveTask();
279 final OceanusProfile mySubTask = myTask == null
280 ? theControl.getNewProfile("incrementVersion")
281 : myTask.startTask("incrementVersion");
282
283
284 theVersion++;
285
286
287 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
288
289 final PrometheusDataList<?> myDataList = myEntry.getDataList();
290
291
292 if (myDataList != null) {
293
294 mySubTask.startTask(myDataList.listName());
295
296
297 myDataList.setVersion(theVersion);
298
299
300 if (Boolean.FALSE.equals(itemEditing)) {
301 myDataList.postProcessOnUpdate();
302 }
303 }
304 }
305
306
307 mySubTask.end();
308 }
309
310
311
312
313
314
315 private void rewindToVersion(final int pVersion) {
316
317 final OceanusProfile myTask = theControl.getActiveTask();
318 OceanusProfile mySubTask = myTask.startTask("reWindToVersion");
319
320
321 theVersion = pVersion;
322
323
324 Iterator<PrometheusEditEntry<?>> myIterator = theMap.values().iterator();
325 while (myIterator.hasNext()) {
326
327 final PrometheusEditEntry<?> myEntry = myIterator.next();
328 final PrometheusDataList<?> myDataList = myEntry.getDataList();
329
330
331 if (myDataList != null) {
332
333 mySubTask.startTask(myDataList.listName());
334
335
336 myDataList.rewindToVersion(theVersion);
337 }
338 }
339
340
341 mySubTask = myTask.startTask("postProcess");
342 myIterator = theMap.values().iterator();
343 while (myIterator.hasNext()) {
344
345 final PrometheusEditEntry<?> myEntry = myIterator.next();
346 final PrometheusDataList<?> myDataList = myEntry.getDataList();
347
348
349 if (myDataList != null) {
350
351 mySubTask.startTask(myDataList.listName());
352
353
354 if (Boolean.FALSE.equals(itemEditing)) {
355 myDataList.postProcessOnUpdate();
356 }
357 }
358 }
359
360
361 mySubTask = myTask.startTask("Notify");
362
363
364 theEventManager.fireEvent(PrometheusDataEvent.DATACHANGED);
365
366
367 mySubTask.end();
368 }
369
370
371
372
373 private void undoLastChange() {
374
375 if (theVersion == 0) {
376 return;
377 }
378
379
380 theVersion--;
381
382
383 rewindToVersion(theVersion);
384 }
385
386
387
388
389 private void resetChanges() {
390
391 if (theVersion == 0) {
392 return;
393 }
394
395
396 theVersion = 0;
397
398
399 rewindToVersion(theVersion);
400 }
401
402
403
404
405 private void applyChanges() {
406
407 final OceanusProfile myTask = theControl.getActiveTask();
408 final OceanusProfile mySubTask = myTask.startTask("applyChanges");
409
410
411 validate();
412
413
414 if (hasErrors()) {
415
416 mySubTask.startTask("Notify");
417
418
419 theEventManager.fireEvent(PrometheusDataEvent.DATACHANGED);
420
421
422 mySubTask.end();
423 return;
424 }
425
426
427 boolean bSuccess = prepareChanges();
428
429
430 if (bSuccess) {
431
432 bSuccess = theControl.analyseData(false);
433 }
434
435
436 if (bSuccess) {
437
438 commitChanges();
439
440
441 theControl.refreshViews();
442
443
444 } else {
445
446 rollBackChanges();
447
448
449 theControl.analyseData(true);
450 }
451
452
453 mySubTask.end();
454 }
455
456
457
458
459
460
461 private boolean prepareChanges() {
462
463 final OceanusProfile myTask = theControl.getActiveTask();
464 final OceanusProfile mySubTask = myTask.startTask("prepareChanges");
465 boolean bSuccess = true;
466
467
468 try {
469
470 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
471
472 mySubTask.startTask(myEntry.getName());
473
474
475 myEntry.prepareChanges();
476 }
477
478 } catch (OceanusException e) {
479 LOGGER.error("Failed to prepare changes", e);
480 bSuccess = false;
481 }
482
483
484 mySubTask.end();
485 return bSuccess;
486 }
487
488
489
490
491 private void commitChanges() {
492
493 final OceanusProfile myTask = theControl.getActiveTask();
494 final OceanusProfile mySubTask = myTask.startTask("commitChanges");
495
496
497 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
498
499 mySubTask.startTask(myEntry.getName());
500
501
502 myEntry.commitChanges();
503 }
504
505
506 theControl.incrementVersion();
507 theVersion = 0;
508
509
510 mySubTask.end();
511 }
512
513
514
515
516 private void rollBackChanges() {
517
518 final OceanusProfile myTask = theControl.getActiveTask();
519 final OceanusProfile mySubTask = myTask.startTask("rollBackChanges");
520
521
522 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
523
524 mySubTask.startTask(myEntry.getName());
525
526
527 myEntry.rollBackChanges();
528 }
529
530
531 mySubTask.end();
532 }
533
534
535
536
537
538
539 public boolean hasUpdates() {
540
541 return theVersion != 0;
542 }
543
544
545
546
547
548
549 public boolean hasErrors() {
550
551 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
552
553 final PrometheusDataList<?> myDataList = myEntry.getDataList();
554
555
556 if (myDataList != null && myDataList.hasErrors()) {
557 return true;
558 }
559 }
560
561
562 return false;
563 }
564
565
566
567
568 public void validate() {
569
570 final OceanusProfile myTask = theControl.getActiveTask();
571 final OceanusProfile mySubTask = myTask.startTask("validate");
572
573
574 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
575
576 final PrometheusDataList<?> myDataList = myEntry.getDataList();
577
578
579 if (myDataList != null) {
580
581 mySubTask.startTask(myDataList.listName());
582
583
584 myDataList.validate();
585 }
586 }
587
588
589 mySubTask.end();
590 }
591
592
593
594
595
596
597 public MetisDataEditState getEditState() {
598
599 final Iterator<PrometheusEditEntry<?>> myIterator = theMap.values().iterator();
600 MetisDataEditState myState = MetisDataEditState.CLEAN;
601 while (myIterator.hasNext()) {
602
603 final PrometheusEditEntry<?> myEntry = myIterator.next();
604 final PrometheusDataList<?> myDataList = myEntry.getDataList();
605
606
607 if (myDataList != null) {
608 myState = myState.combineState(myDataList.getEditState());
609 }
610 }
611
612
613 return myState;
614 }
615
616
617
618
619
620
621
622 public void processCommand(final PrometheusUIEvent pCmd,
623 final MetisErrorPanel pError) {
624
625 final OceanusProfile myTask = theControl.getNewProfile("EditCommand");
626
627
628 switch (pCmd) {
629 case OK:
630 applyChanges();
631 break;
632 case UNDO:
633 undoLastChange();
634 break;
635 case RESET:
636 resetChanges();
637 break;
638 default:
639 break;
640 }
641
642
643 final MetisViewerErrorList myErrors = theControl.getErrors();
644
645
646 if (!myErrors.isEmpty()) {
647 pError.setErrors(myErrors);
648 }
649
650
651 myTask.end();
652 }
653
654
655
656
657
658
659
660
661 public void processEditCommand(final PrometheusUIEvent pCmd,
662 final int pVersion,
663 final MetisErrorPanel pError) {
664
665 final OceanusProfile myTask = theControl.getNewProfile("ItemCommand");
666
667
668 switch (pCmd) {
669 case OK:
670 condenseHistory(pVersion);
671 break;
672 case UNDO:
673 undoLastChange();
674 break;
675 case REWIND:
676 rewindToVersion(pVersion);
677 break;
678 default:
679 break;
680 }
681
682
683 final MetisViewerErrorList myErrors = theControl.getErrors();
684
685
686 if (!myErrors.isEmpty()) {
687 pError.setErrors(myErrors);
688 }
689
690
691 myTask.end();
692 }
693
694
695
696
697
698
699 private void condenseHistory(final int pNewVersion) {
700
701 final OceanusProfile myTask = theControl.getActiveTask();
702 final OceanusProfile mySubTask = myTask.startTask("condenseHistory");
703
704
705 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
706
707 final PrometheusDataList<?> myDataList = myEntry.getDataList();
708
709
710 if (myDataList != null) {
711
712 final OceanusProfile myListTask = mySubTask.startTask(myDataList.listName());
713 myListTask.startTask("Condense");
714
715
716 myDataList.condenseHistory(pNewVersion);
717
718
719 if (Boolean.FALSE.equals(itemEditing)) {
720 myListTask.startTask("postProcess");
721 myDataList.postProcessOnUpdate();
722 }
723 }
724 }
725
726
727 theVersion = pNewVersion;
728
729
730 theEventManager.fireEvent(PrometheusDataEvent.DATACHANGED);
731
732
733 mySubTask.end();
734 }
735 }