View Javadoc
1   /*
2    * MoneyWise: Finance Application
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.moneywise.data.basic;
18  
19  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
23  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataNamedItem;
24  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
25  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataValidator.MoneyWiseDataValidatorDefaults;
27  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
28  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInstanceMap;
29  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
30  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedDataItem;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedFieldSet;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedPair;
35  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
36  
37  import java.util.Iterator;
38  
39  /**
40   * Region for a Unit Trust.
41   */
42  public class MoneyWiseRegion
43          extends PrometheusEncryptedDataItem
44          implements MetisDataNamedItem {
45      /**
46       * Object name.
47       */
48      public static final String OBJECT_NAME = MoneyWiseBasicDataType.REGION.getItemName();
49  
50      /**
51       * List name.
52       */
53      public static final String LIST_NAME = MoneyWiseBasicDataType.REGION.getListName();
54  
55      /**
56       * Local Report fields.
57       */
58      private static final PrometheusEncryptedFieldSet<MoneyWiseRegion> FIELD_DEFS = PrometheusEncryptedFieldSet.newEncryptedFieldSet(MoneyWiseRegion.class);
59  
60      /*
61       * FieldIds.
62       */
63      static {
64          FIELD_DEFS.declareEncryptedStringField(PrometheusDataResource.DATAITEM_FIELD_NAME, NAMELEN);
65          FIELD_DEFS.declareEncryptedStringField(PrometheusDataResource.DATAITEM_FIELD_DESC, DESCLEN);
66      }
67  
68      /**
69       * Copy Constructor.
70       *
71       * @param pList   the list
72       * @param pRegion The region to copy
73       */
74      protected MoneyWiseRegion(final MoneyWiseRegionList pList,
75                                final MoneyWiseRegion pRegion) {
76          /* Set standard values */
77          super(pList, pRegion);
78      }
79  
80      /**
81       * Values constructor.
82       *
83       * @param pList   the List to add to
84       * @param pValues the values constructor
85       * @throws OceanusException on error
86       */
87      private MoneyWiseRegion(final MoneyWiseRegionList pList,
88                              final PrometheusDataValues pValues) throws OceanusException {
89          /* Initialise the item */
90          super(pList, pValues);
91  
92          /* Protect against exceptions */
93          try {
94              /* Store the Name */
95              Object myValue = pValues.getValue(PrometheusDataResource.DATAITEM_FIELD_NAME);
96              if (myValue instanceof String s) {
97                  setValueName(s);
98              } else if (myValue instanceof byte[] ba) {
99                  setValueName(ba);
100             }
101 
102             /* Store the Description */
103             myValue = pValues.getValue(PrometheusDataResource.DATAITEM_FIELD_DESC);
104             if (myValue instanceof String s) {
105                 setValueDesc(s);
106             } else if (myValue instanceof byte[] ba) {
107                 setValueDesc(ba);
108             }
109 
110             /* Catch Exceptions */
111         } catch (OceanusException e) {
112             /* Pass on exception */
113             throw new MoneyWiseDataException(this, ERROR_CREATEITEM, e);
114         }
115     }
116 
117     /**
118      * Edit Constructor.
119      *
120      * @param pList the list
121      */
122     public MoneyWiseRegion(final MoneyWiseRegionList pList) {
123         super(pList, 0);
124         setNextDataKeySet();
125     }
126 
127     @Override
128     public MetisFieldSetDef getDataFieldSet() {
129         return FIELD_DEFS;
130     }
131 
132     @Override
133     public String formatObject(final OceanusDataFormatter pFormatter) {
134         return toString();
135     }
136 
137     @Override
138     public String toString() {
139         return getName();
140     }
141 
142     @Override
143     public boolean includeXmlField(final MetisDataFieldId pField) {
144         /* Determine whether fields should be included */
145         if (PrometheusDataResource.DATAITEM_FIELD_NAME.equals(pField)) {
146             return true;
147         }
148         if (PrometheusDataResource.DATAITEM_FIELD_DESC.equals(pField)) {
149             return getDesc() != null;
150         }
151 
152         /* Pass call on */
153         return super.includeXmlField(pField);
154     }
155 
156     @Override
157     public String getName() {
158         return getValues().getValue(PrometheusDataResource.DATAITEM_FIELD_NAME, String.class);
159     }
160 
161     /**
162      * Obtain Encrypted name.
163      *
164      * @return the bytes
165      */
166     public byte[] getNameBytes() {
167         return getValues().getEncryptedBytes(PrometheusDataResource.DATAITEM_FIELD_NAME);
168     }
169 
170     /**
171      * Obtain Encrypted Name Field.
172      *
173      * @return the Field
174      */
175     private PrometheusEncryptedPair getNameField() {
176         return getValues().getEncryptedPair(PrometheusDataResource.DATAITEM_FIELD_NAME);
177     }
178 
179     /**
180      * Obtain Description.
181      *
182      * @return the description
183      */
184     public String getDesc() {
185         return getValues().getValue(PrometheusDataResource.DATAITEM_FIELD_DESC, String.class);
186     }
187 
188     /**
189      * Obtain Encrypted description.
190      *
191      * @return the bytes
192      */
193     public byte[] getDescBytes() {
194         return getValues().getEncryptedBytes(PrometheusDataResource.DATAITEM_FIELD_DESC);
195     }
196 
197     /**
198      * Obtain Encrypted Description Field.
199      *
200      * @return the Field
201      */
202     private PrometheusEncryptedPair getDescField() {
203         return getValues().getEncryptedPair(PrometheusDataResource.DATAITEM_FIELD_DESC);
204     }
205 
206     /**
207      * Set name value.
208      *
209      * @param pValue the value
210      * @throws OceanusException on error
211      */
212     private void setValueName(final String pValue) throws OceanusException {
213         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pValue);
214     }
215 
216     /**
217      * Set name value.
218      *
219      * @param pBytes the value
220      * @throws OceanusException on error
221      */
222     private void setValueName(final byte[] pBytes) throws OceanusException {
223         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pBytes, String.class);
224     }
225 
226     /**
227      * Set name value.
228      *
229      * @param pValue the value
230      */
231     private void setValueName(final PrometheusEncryptedPair pValue) {
232         getValues().setUncheckedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pValue);
233     }
234 
235     /**
236      * Set description value.
237      *
238      * @param pValue the value
239      * @throws OceanusException on error
240      */
241     private void setValueDesc(final String pValue) throws OceanusException {
242         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pValue);
243     }
244 
245     /**
246      * Set description value.
247      *
248      * @param pBytes the value
249      * @throws OceanusException on error
250      */
251     private void setValueDesc(final byte[] pBytes) throws OceanusException {
252         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pBytes, String.class);
253     }
254 
255     /**
256      * Set description value.
257      *
258      * @param pValue the value
259      */
260     private void setValueDesc(final PrometheusEncryptedPair pValue) {
261         getValues().setUncheckedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pValue);
262     }
263 
264     @Override
265     public MoneyWiseDataSet getDataSet() {
266         return (MoneyWiseDataSet) super.getDataSet();
267     }
268 
269     @Override
270     public MoneyWiseRegion getBase() {
271         return (MoneyWiseRegion) super.getBase();
272     }
273 
274     @Override
275     public MoneyWiseRegionList getList() {
276         return (MoneyWiseRegionList) super.getList();
277     }
278 
279     /**
280      * Set defaults.
281      *
282      * @throws OceanusException on error
283      */
284     public void setDefaults() throws OceanusException {
285         getList().getValidator().setDefaults(this);
286     }
287 
288     @Override
289     public int compareValues(final PrometheusDataItem pThat) {
290         /* Check the names */
291         final MoneyWiseRegion myThat = (MoneyWiseRegion) pThat;
292         return MetisDataDifference.compareObject(getName(), myThat.getName());
293     }
294 
295     /**
296      * Set a new tag name.
297      *
298      * @param pName the new name
299      * @throws OceanusException on error
300      */
301     public void setName(final String pName) throws OceanusException {
302         setValueName(pName);
303     }
304 
305     /**
306      * Set a new description.
307      *
308      * @param pDesc the description
309      * @throws OceanusException on error
310      */
311     public void setDescription(final String pDesc) throws OceanusException {
312         setValueDesc(pDesc);
313     }
314 
315     /**
316      * Update base tag from an edited tag.
317      *
318      * @param pTag the edited tag
319      * @return whether changes have been made
320      */
321     @Override
322     public boolean applyChanges(final PrometheusDataItem pTag) {
323         /* Can only update from a region */
324         if (!(pTag instanceof MoneyWiseRegion)) {
325             return false;
326         }
327         final MoneyWiseRegion myRegion = (MoneyWiseRegion) pTag;
328 
329         /* Store the current detail into history */
330         pushHistory();
331 
332         /* Update the Name if required */
333         if (!MetisDataDifference.isEqual(getName(), myRegion.getName())) {
334             setValueName(myRegion.getNameField());
335         }
336 
337         /* Update the description if required */
338         if (!MetisDataDifference.isEqual(getDesc(), myRegion.getDesc())) {
339             setValueDesc(myRegion.getDescField());
340         }
341 
342         /* Check for changes */
343         return checkForHistory();
344     }
345 
346     @Override
347     public void adjustMapForItem() {
348         final MoneyWiseRegionList myList = getList();
349         final MoneyWiseRegionDataMap myMap = myList.getDataMap();
350         myMap.adjustForItem(this);
351     }
352 
353     /**
354      * The Region List class.
355      */
356     public static class MoneyWiseRegionList
357             extends PrometheusEncryptedList<MoneyWiseRegion> {
358         /**
359          * Report fields.
360          */
361         private static final MetisFieldSet<MoneyWiseRegionList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseRegionList.class);
362 
363         /**
364          * Construct an empty CORE Tag list.
365          *
366          * @param pData the DataSet for the list
367          */
368         protected MoneyWiseRegionList(final MoneyWiseDataSet pData) {
369             super(MoneyWiseRegion.class, pData, MoneyWiseBasicDataType.REGION, PrometheusListStyle.CORE);
370         }
371 
372         /**
373          * Constructor for a cloned List.
374          *
375          * @param pSource the source List
376          */
377         protected MoneyWiseRegionList(final MoneyWiseRegionList pSource) {
378             super(pSource);
379         }
380 
381         @Override
382         public MetisFieldSet<MoneyWiseRegionList> getDataFieldSet() {
383             return FIELD_DEFS;
384         }
385 
386         @Override
387         public String listName() {
388             return LIST_NAME;
389         }
390 
391         @Override
392         public MetisFieldSetDef getItemFields() {
393             return MoneyWiseRegion.FIELD_DEFS;
394         }
395 
396         @Override
397         public MoneyWiseDataSet getDataSet() {
398             return (MoneyWiseDataSet) super.getDataSet();
399         }
400 
401         @Override
402         public MoneyWiseRegionDataMap getDataMap() {
403             return (MoneyWiseRegionDataMap) super.getDataMap();
404         }
405 
406         @Override
407         @SuppressWarnings("unchecked")
408         public MoneyWiseDataValidatorDefaults<MoneyWiseRegion> getValidator() {
409             return (MoneyWiseDataValidatorDefaults<MoneyWiseRegion>) super.getValidator();
410         }
411 
412         @Override
413         protected MoneyWiseRegionList getEmptyList(final PrometheusListStyle pStyle) {
414             final MoneyWiseRegionList myList = new MoneyWiseRegionList(this);
415             myList.setStyle(pStyle);
416             return myList;
417         }
418 
419         /**
420          * Derive Edit list.
421          *
422          * @param pEditSet the editSet
423          * @return the edit list
424          */
425         public MoneyWiseRegionList deriveEditList(final PrometheusEditSet pEditSet) {
426             /* Build an empty List */
427             final MoneyWiseRegionList myList = getEmptyList(PrometheusListStyle.EDIT);
428             myList.ensureMap();
429             pEditSet.setEditEntryList(MoneyWiseBasicDataType.REGION, myList);
430             myList.getValidator().setEditSet(pEditSet);
431 
432             /* Loop through the regions */
433             final Iterator<MoneyWiseRegion> myIterator = iterator();
434             while (myIterator.hasNext()) {
435                 final MoneyWiseRegion myCurr = myIterator.next();
436 
437                 /* Ignore deleted regions */
438                 if (myCurr.isDeleted()) {
439                     continue;
440                 }
441 
442                 /* Build the new linked region and add it to the list */
443                 final MoneyWiseRegion myRegion = new MoneyWiseRegion(myList, myCurr);
444                 myList.add(myRegion);
445 
446                 /* Adjust the map */
447                 myRegion.adjustMapForItem();
448             }
449 
450             /* Return the list */
451             return myList;
452         }
453 
454         /**
455          * Add a new item to the core list.
456          *
457          * @param pRegion item
458          * @return the newly added item
459          */
460         @Override
461         public MoneyWiseRegion addCopyItem(final PrometheusDataItem pRegion) {
462             /* Can only clone a Region */
463             if (!(pRegion instanceof MoneyWiseRegion)) {
464                 throw new UnsupportedOperationException();
465             }
466 
467             final MoneyWiseRegion myRegion = new MoneyWiseRegion(this, (MoneyWiseRegion) pRegion);
468             add(myRegion);
469             return myRegion;
470         }
471 
472         /**
473          * Add a new item to the edit list.
474          *
475          * @return the new item
476          */
477         @Override
478         public MoneyWiseRegion addNewItem() {
479             final MoneyWiseRegion myRegion = new MoneyWiseRegion(this);
480             add(myRegion);
481             return myRegion;
482         }
483 
484         @Override
485         public MoneyWiseRegion findItemByName(final String pName) {
486             /* look up the name in the map */
487             return getDataMap().findItemByName(pName);
488         }
489 
490         @Override
491         public MoneyWiseRegion addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
492             /* Create the region */
493             final MoneyWiseRegion myRegion = new MoneyWiseRegion(this, pValues);
494 
495             /* Check that this regionId has not been previously added */
496             if (!isIdUnique(myRegion.getIndexedId())) {
497                 myRegion.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
498                 throw new MoneyWiseDataException(myRegion, ERROR_VALIDATION);
499             }
500 
501             /* Add to the list */
502             add(myRegion);
503 
504             /* Return it */
505             return myRegion;
506         }
507 
508         @Override
509         protected MoneyWiseRegionDataMap allocateDataMap() {
510             return new MoneyWiseRegionDataMap();
511         }
512     }
513 
514     /**
515      * The dataMap class.
516      */
517     public static class MoneyWiseRegionDataMap
518             extends PrometheusDataInstanceMap<MoneyWiseRegion, String> {
519         @Override
520         public void adjustForItem(final PrometheusDataItem pItem) {
521             /* Access item */
522             final MoneyWiseRegion myItem = (MoneyWiseRegion) pItem;
523 
524             /* Adjust name count */
525             adjustForItem(myItem, myItem.getName());
526         }
527 
528         /**
529          * find item by name.
530          *
531          * @param pName the name to look up
532          * @return the matching item
533          */
534         public MoneyWiseRegion findItemByName(final String pName) {
535             return findItemByKey(pName);
536         }
537 
538         /**
539          * Check validity of name.
540          *
541          * @param pName the name to look up
542          * @return true/false
543          */
544         public boolean validNameCount(final String pName) {
545             return validKeyCount(pName);
546         }
547 
548         /**
549          * Check availability of name.
550          *
551          * @param pName the key to look up
552          * @return true/false
553          */
554         public boolean availableName(final String pName) {
555             return availableKey(pName);
556         }
557     }
558 }