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.metis.data.MetisDataDifference;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataNamedItem;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
23  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataValidator.MoneyWiseDataValidatorDefaults;
25  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
26  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
27  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
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 myRegion)) {
325             return false;
326         }
327 
328         /* Store the current detail into history */
329         pushHistory();
330 
331         /* Update the Name if required */
332         if (!MetisDataDifference.isEqual(getName(), myRegion.getName())) {
333             setValueName(myRegion.getNameField());
334         }
335 
336         /* Update the description if required */
337         if (!MetisDataDifference.isEqual(getDesc(), myRegion.getDesc())) {
338             setValueDesc(myRegion.getDescField());
339         }
340 
341         /* Check for changes */
342         return checkForHistory();
343     }
344 
345     @Override
346     public void adjustMapForItem() {
347         final MoneyWiseRegionList myList = getList();
348         final MoneyWiseRegionDataMap myMap = myList.getDataMap();
349         myMap.adjustForItem(this);
350     }
351 
352     /**
353      * The Region List class.
354      */
355     public static class MoneyWiseRegionList
356             extends PrometheusEncryptedList<MoneyWiseRegion> {
357         /**
358          * Report fields.
359          */
360         private static final MetisFieldSet<MoneyWiseRegionList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseRegionList.class);
361 
362         /**
363          * Construct an empty CORE Tag list.
364          *
365          * @param pData the DataSet for the list
366          */
367         protected MoneyWiseRegionList(final MoneyWiseDataSet pData) {
368             super(MoneyWiseRegion.class, pData, MoneyWiseBasicDataType.REGION, PrometheusListStyle.CORE);
369         }
370 
371         /**
372          * Constructor for a cloned List.
373          *
374          * @param pSource the source List
375          */
376         protected MoneyWiseRegionList(final MoneyWiseRegionList pSource) {
377             super(pSource);
378         }
379 
380         @Override
381         public MetisFieldSet<MoneyWiseRegionList> getDataFieldSet() {
382             return FIELD_DEFS;
383         }
384 
385         @Override
386         public String listName() {
387             return LIST_NAME;
388         }
389 
390         @Override
391         public MetisFieldSetDef getItemFields() {
392             return MoneyWiseRegion.FIELD_DEFS;
393         }
394 
395         @Override
396         public MoneyWiseDataSet getDataSet() {
397             return (MoneyWiseDataSet) super.getDataSet();
398         }
399 
400         @Override
401         public MoneyWiseRegionDataMap getDataMap() {
402             return (MoneyWiseRegionDataMap) super.getDataMap();
403         }
404 
405         @Override
406         @SuppressWarnings("unchecked")
407         public MoneyWiseDataValidatorDefaults<MoneyWiseRegion> getValidator() {
408             return (MoneyWiseDataValidatorDefaults<MoneyWiseRegion>) super.getValidator();
409         }
410 
411         @Override
412         protected MoneyWiseRegionList getEmptyList(final PrometheusListStyle pStyle) {
413             final MoneyWiseRegionList myList = new MoneyWiseRegionList(this);
414             myList.setStyle(pStyle);
415             return myList;
416         }
417 
418         /**
419          * Derive Edit list.
420          *
421          * @param pEditSet the editSet
422          * @return the edit list
423          */
424         public MoneyWiseRegionList deriveEditList(final PrometheusEditSet pEditSet) {
425             /* Build an empty List */
426             final MoneyWiseRegionList myList = getEmptyList(PrometheusListStyle.EDIT);
427             myList.ensureMap();
428             pEditSet.setEditEntryList(MoneyWiseBasicDataType.REGION, myList);
429             myList.getValidator().setEditSet(pEditSet);
430 
431             /* Loop through the regions */
432             final Iterator<MoneyWiseRegion> myIterator = iterator();
433             while (myIterator.hasNext()) {
434                 final MoneyWiseRegion myCurr = myIterator.next();
435 
436                 /* Ignore deleted regions */
437                 if (myCurr.isDeleted()) {
438                     continue;
439                 }
440 
441                 /* Build the new linked region and add it to the list */
442                 final MoneyWiseRegion myRegion = new MoneyWiseRegion(myList, myCurr);
443                 myList.add(myRegion);
444 
445                 /* Adjust the map */
446                 myRegion.adjustMapForItem();
447             }
448 
449             /* Return the list */
450             return myList;
451         }
452 
453         /**
454          * Add a new item to the core list.
455          *
456          * @param pRegion item
457          * @return the newly added item
458          */
459         @Override
460         public MoneyWiseRegion addCopyItem(final PrometheusDataItem pRegion) {
461             /* Can only clone a Region */
462             if (!(pRegion instanceof MoneyWiseRegion)) {
463                 throw new UnsupportedOperationException();
464             }
465 
466             final MoneyWiseRegion myRegion = new MoneyWiseRegion(this, (MoneyWiseRegion) pRegion);
467             add(myRegion);
468             return myRegion;
469         }
470 
471         /**
472          * Add a new item to the edit list.
473          *
474          * @return the new item
475          */
476         @Override
477         public MoneyWiseRegion addNewItem() {
478             final MoneyWiseRegion myRegion = new MoneyWiseRegion(this);
479             add(myRegion);
480             return myRegion;
481         }
482 
483         @Override
484         public MoneyWiseRegion findItemByName(final String pName) {
485             /* look up the name in the map */
486             return getDataMap().findItemByName(pName);
487         }
488 
489         @Override
490         public MoneyWiseRegion addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
491             /* Create the region */
492             final MoneyWiseRegion myRegion = new MoneyWiseRegion(this, pValues);
493 
494             /* Check that this regionId has not been previously added */
495             if (!isIdUnique(myRegion.getIndexedId())) {
496                 myRegion.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
497                 throw new MoneyWiseDataException(myRegion, ERROR_VALIDATION);
498             }
499 
500             /* Add to the list */
501             add(myRegion);
502 
503             /* Return it */
504             return myRegion;
505         }
506 
507         @Override
508         protected MoneyWiseRegionDataMap allocateDataMap() {
509             return new MoneyWiseRegionDataMap();
510         }
511     }
512 
513     /**
514      * The dataMap class.
515      */
516     public static class MoneyWiseRegionDataMap
517             extends PrometheusDataInstanceMap<MoneyWiseRegion, String> {
518         @Override
519         public void adjustForItem(final PrometheusDataItem pItem) {
520             /* Access item */
521             final MoneyWiseRegion myItem = (MoneyWiseRegion) pItem;
522 
523             /* Adjust name count */
524             adjustForItem(myItem, myItem.getName());
525         }
526 
527         /**
528          * find item by name.
529          *
530          * @param pName the name to look up
531          * @return the matching item
532          */
533         public MoneyWiseRegion findItemByName(final String pName) {
534             return findItemByKey(pName);
535         }
536 
537         /**
538          * Check validity of name.
539          *
540          * @param pName the name to look up
541          * @return true/false
542          */
543         public boolean validNameCount(final String pName) {
544             return validKeyCount(pName);
545         }
546 
547         /**
548          * Check availability of name.
549          *
550          * @param pName the key to look up
551          * @return true/false
552          */
553         public boolean availableName(final String pName) {
554             return availableKey(pName);
555         }
556     }
557 }