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.MetisDataResource;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetBase.MoneyWiseAssetBaseList;
23  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseRegion.MoneyWiseRegionList;
24  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
25  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType;
26  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType.MoneyWiseAccountInfoTypeList;
27  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
28  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
29  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
30  import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataSetCtl;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInfoClass;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInfoItem;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInfoSet;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
35  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
36  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
38  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
39  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncrypted.PrometheusDataInfoSetItemCtl;
40  import io.github.tonywasher.joceanus.prometheus.data.PrometheusListStyle;
41  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataItem;
42  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
43  
44  /**
45   * Representation of an information extension of a security.
46   *
47   * @author Tony Washer
48   */
49  public class MoneyWiseSecurityInfo
50          extends PrometheusDataInfoItem {
51      /**
52       * Object name.
53       */
54      public static final String OBJECT_NAME = MoneyWiseBasicDataType.SECURITYINFO.getItemName();
55  
56      /**
57       * List name.
58       */
59      public static final String LIST_NAME = MoneyWiseBasicDataType.SECURITYINFO.getListName();
60  
61      /**
62       * Local Report fields.
63       */
64      private static final MetisFieldSet<MoneyWiseSecurityInfo> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseSecurityInfo.class);
65  
66      /**
67       * Copy Constructor.
68       *
69       * @param pList the list
70       * @param pInfo The Info to copy
71       */
72      protected MoneyWiseSecurityInfo(final MoneyWiseSecurityInfoList pList,
73                                      final MoneyWiseSecurityInfo pInfo) {
74          /* Set standard values */
75          super(pList, pInfo);
76      }
77  
78      /**
79       * Edit Constructor.
80       *
81       * @param pList     the list
82       * @param pSecurity the security
83       * @param pType     the type
84       */
85      private MoneyWiseSecurityInfo(final MoneyWiseSecurityInfoList pList,
86                                    final PrometheusDataItem pSecurity,
87                                    final MoneyWiseAccountInfoType pType) {
88          /* Initialise the item */
89          super(pList);
90          setNextDataKeySet();
91  
92          /* Record the Detail */
93          setValueInfoType(pType);
94          setValueOwner(pSecurity);
95      }
96  
97      /**
98       * Values constructor.
99       *
100      * @param pList   the List to add to
101      * @param pValues the values constructor
102      * @throws OceanusException on error
103      */
104     private MoneyWiseSecurityInfo(final MoneyWiseSecurityInfoList pList,
105                                   final PrometheusDataValues pValues) throws OceanusException {
106         /* Initialise the item */
107         super(pList, pValues);
108 
109         /* Protect against exceptions */
110         try {
111             /* Resolve links */
112             resolveDataLink(PrometheusDataResource.DATAINFO_TYPE, MoneyWiseStaticDataType.ACCOUNTINFOTYPE);
113             resolveDataLink(PrometheusDataResource.DATAINFO_OWNER, MoneyWiseBasicDataType.SECURITY);
114 
115             /* Set the value */
116             setValue(pValues.getValue(PrometheusDataResource.DATAINFO_VALUE));
117 
118             /* Resolve any link value */
119             resolveLink(null);
120 
121             /* Access the SecurityInfoSet and register this data */
122             getInfoSet().registerInfo(this);
123 
124         } catch (OceanusException e) {
125             /* Pass on exception */
126             throw new MoneyWiseDataException(this, ERROR_CREATEITEM, e);
127         }
128     }
129 
130     @Override
131     public MetisFieldSetDef getDataFieldSet() {
132         return FIELD_DEFS;
133     }
134 
135     @Override
136     public MoneyWiseAccountInfoType getInfoType() {
137         return getValues().getValue(PrometheusDataResource.DATAINFO_TYPE, MoneyWiseAccountInfoType.class);
138     }
139 
140     @Override
141     public MoneyWiseAccountInfoClass getInfoClass() {
142         return getInfoType().getInfoClass();
143     }
144 
145     @Override
146     public PrometheusDataItem getOwner() {
147         return getValues().getValue(PrometheusDataResource.DATAINFO_OWNER, PrometheusDataItem.class);
148     }
149 
150     /**
151      * Obtain Region.
152      *
153      * @return the Region
154      */
155     public MoneyWiseRegion getRegion() {
156         return getValues().getValue(PrometheusDataResource.DATAINFO_LINK, MoneyWiseRegion.class);
157     }
158 
159     /**
160      * Obtain Security.
161      *
162      * @return the Security
163      */
164     public MoneyWiseAssetBase getSecurity() {
165         return getValues().getValue(PrometheusDataResource.DATAINFO_LINK, MoneyWiseAssetBase.class);
166     }
167 
168     @Override
169     public String getLinkName() {
170         final PrometheusDataItem myItem = getLink();
171         if (myItem instanceof MoneyWiseRegion myRegion) {
172             return myRegion.getName();
173         }
174         if (myItem instanceof MoneyWiseAssetBase mySecurity) {
175             return mySecurity.getName();
176         }
177         return null;
178     }
179 
180     @Override
181     public MoneyWiseSecurityInfo getBase() {
182         return (MoneyWiseSecurityInfo) super.getBase();
183     }
184 
185     @Override
186     public MoneyWiseSecurityInfoList getList() {
187         return (MoneyWiseSecurityInfoList) super.getList();
188     }
189 
190     /**
191      * Obtain the InfoSet.
192      *
193      * @return the infoSet
194      */
195     @SuppressWarnings("unchecked")
196     private PrometheusDataInfoSet<MoneyWiseSecurityInfo> getInfoSet() {
197         return (PrometheusDataInfoSet<MoneyWiseSecurityInfo>) ((PrometheusDataInfoSetItemCtl<MoneyWiseSecurityInfo>) getOwner()).getInfoSet();
198     }
199 
200     @Override
201     public void deRegister() {
202         /* Access the SecurityInfoSet and register this value */
203         getInfoSet().deRegisterInfo(this);
204     }
205 
206     @Override
207     public void resolveDataSetLinks() throws OceanusException {
208         /* Update the Encryption details */
209         super.resolveDataSetLinks();
210 
211         /* Resolve data links */
212         resolveDataLink(PrometheusDataResource.DATAINFO_TYPE, MoneyWiseStaticDataType.ACCOUNTINFOTYPE);
213         resolveDataLink(PrometheusDataResource.DATAINFO_OWNER, MoneyWiseBasicDataType.SECURITY);
214 
215         /* Resolve any link value */
216         resolveLink(null);
217 
218         /* Access the SecurityInfoSet and register this data */
219         getInfoSet().registerInfo(this);
220     }
221 
222     /**
223      * resolve editSet links.
224      *
225      * @param pEditSet the edit set
226      * @throws OceanusException on error
227      */
228     public void resolveEditSetLinks(final PrometheusEditSet pEditSet) throws OceanusException {
229         /* Update the Encryption details */
230         super.resolveDataSetLinks();
231 
232         /* Resolve data links */
233         resolveDataLink(PrometheusDataResource.DATAINFO_TYPE, pEditSet.getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class));
234         resolveDataLink(PrometheusDataResource.DATAINFO_OWNER, pEditSet.getDataList(MoneyWiseBasicDataType.SECURITY, PrometheusDataList.class));
235 
236         /* Resolve any link value */
237         resolveLink(pEditSet);
238     }
239 
240     /**
241      * Resolve link reference.
242      *
243      * @param pEditSet the edit set
244      * @throws OceanusException on error
245      */
246     private void resolveLink(final PrometheusEditSet pEditSet) throws OceanusException {
247         /* If we have a link */
248         final MoneyWiseAccountInfoType myType = getInfoType();
249         if (myType.isLink()) {
250             /* Access data */
251             final PrometheusDataSetCtl myData = getDataSet();
252             final Object myLinkId = getValues().getValue(PrometheusDataResource.DATAINFO_VALUE);
253 
254             /* Switch on link type */
255             switch (myType.getInfoClass()) {
256                 case REGION:
257                     resolveDataLink(PrometheusDataResource.DATAINFO_LINK, pEditSet == null
258                             ? myData.getDataList(MoneyWiseBasicDataType.REGION, MoneyWiseRegionList.class)
259                             : pEditSet.getDataList(MoneyWiseBasicDataType.REGION, MoneyWiseRegionList.class));
260                     if (myLinkId == null) {
261                         setValueValue(getRegion().getIndexedId());
262                     }
263                     break;
264                 case UNDERLYINGSTOCK:
265                     resolveDataLink(PrometheusDataResource.DATAINFO_LINK, pEditSet == null
266                             ? myData.getDataList(MoneyWiseBasicDataType.SECURITY, MoneyWiseAssetBaseList.class)
267                             : pEditSet.getDataList(MoneyWiseBasicDataType.SECURITY, MoneyWiseAssetBaseList.class));
268                     if (myLinkId == null) {
269                         setValueValue(getSecurity().getIndexedId());
270                     }
271                     break;
272                 default:
273                     break;
274             }
275         }
276     }
277 
278     /**
279      * Update securityInfo from a securityInfo extract.
280      *
281      * @param pInfo the changed securityInfo
282      * @return whether changes have been made
283      */
284     @Override
285     public boolean applyChanges(final PrometheusDataItem pInfo) {
286         /* Can only update from SecurityInfo */
287         if (!(pInfo instanceof MoneyWiseSecurityInfo mySecInfo)) {
288             return false;
289         }
290 
291         /* Store the current detail into history */
292         pushHistory();
293 
294         /* Update the value if required */
295         if (!MetisDataDifference.isEqual(getField(), mySecInfo.getField())) {
296             setValueValue(mySecInfo.getField());
297         }
298 
299         /* Check for changes */
300         return checkForHistory();
301     }
302 
303     @Override
304     public void touchUnderlyingItems() {
305         /* touch info class */
306         super.touchUnderlyingItems();
307 
308         /* Switch on info class */
309         switch (getInfoClass()) {
310             case UNDERLYINGSTOCK:
311                 getSecurity().touchItem(getOwner());
312                 break;
313             case REGION:
314                 getRegion().touchItem(getOwner());
315                 break;
316             default:
317                 break;
318         }
319     }
320 
321     /**
322      * SecurityInfoList.
323      */
324     public static class MoneyWiseSecurityInfoList
325             extends PrometheusDataInfoList<MoneyWiseSecurityInfo> {
326         /**
327          * Report fields.
328          */
329         private static final MetisFieldSet<MoneyWiseSecurityInfoList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseSecurityInfoList.class);
330 
331         /**
332          * Construct an empty CORE info list.
333          *
334          * @param pData the DataSet for the list
335          */
336         protected MoneyWiseSecurityInfoList(final PrometheusDataSet pData) {
337             super(MoneyWiseSecurityInfo.class, pData, MoneyWiseBasicDataType.SECURITYINFO, PrometheusListStyle.CORE);
338         }
339 
340         /**
341          * Constructor for a cloned List.
342          *
343          * @param pSource the source List
344          */
345         private MoneyWiseSecurityInfoList(final MoneyWiseSecurityInfoList pSource) {
346             super(pSource);
347         }
348 
349         @Override
350         public MetisFieldSet<MoneyWiseSecurityInfoList> getDataFieldSet() {
351             return FIELD_DEFS;
352         }
353 
354         @Override
355         public String listName() {
356             return LIST_NAME;
357         }
358 
359         @Override
360         public MetisFieldSetDef getItemFields() {
361             return MoneyWiseSecurityInfo.FIELD_DEFS;
362         }
363 
364         /**
365          * Set base list for Edit InfoList.
366          *
367          * @param pBase the base list
368          */
369         protected void setBase(final MoneyWiseSecurityInfoList pBase) {
370             /* Set the style and base */
371             setStyle(PrometheusListStyle.EDIT);
372             super.setBase(pBase);
373         }
374 
375         @Override
376         protected MoneyWiseSecurityInfoList getEmptyList(final PrometheusListStyle pStyle) {
377             final MoneyWiseSecurityInfoList myList = new MoneyWiseSecurityInfoList(this);
378             myList.setStyle(pStyle);
379             return myList;
380         }
381 
382         @Override
383         public MoneyWiseSecurityInfo addCopyItem(final PrometheusDataItem pItem) {
384             /* Can only clone a SecurityInfo */
385             if (!(pItem instanceof MoneyWiseSecurityInfo)) {
386                 throw new UnsupportedOperationException();
387             }
388 
389             final MoneyWiseSecurityInfo myInfo = new MoneyWiseSecurityInfo(this, (MoneyWiseSecurityInfo) pItem);
390             add(myInfo);
391             return myInfo;
392         }
393 
394         @Override
395         public MoneyWiseSecurityInfo addNewItem() {
396             throw new UnsupportedOperationException();
397         }
398 
399         @Override
400         protected MoneyWiseSecurityInfo addNewItem(final PrometheusDataItem pOwner,
401                                                    final PrometheusStaticDataItem pInfoType) {
402             /* Allocate the new entry and add to list */
403             final MoneyWiseSecurityInfo myInfo = new MoneyWiseSecurityInfo(this, pOwner, (MoneyWiseAccountInfoType) pInfoType);
404             add(myInfo);
405 
406             /* return it */
407             return myInfo;
408         }
409 
410         @Override
411         public void addInfoItem(final Integer pId,
412                                 final PrometheusDataItem pSecurity,
413                                 final PrometheusDataInfoClass pInfoClass,
414                                 final Object pValue) throws OceanusException {
415             /* Ignore item if it is null */
416             if (pValue == null) {
417                 return;
418             }
419 
420             /* Access the accountInfoTypes */
421             final MoneyWiseAccountInfoTypeList myActInfos
422                     = getDataSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
423 
424             /* Look up the Info Type */
425             final MoneyWiseAccountInfoType myInfoType = myActInfos.findItemByClass(pInfoClass);
426             if (myInfoType == null) {
427                 throw new MoneyWiseDataException(pSecurity, ERROR_BADINFOCLASS + " [" + pInfoClass + "]");
428             }
429 
430             /* Create the values */
431             final PrometheusDataValues myValues = new PrometheusDataValues(OBJECT_NAME);
432             myValues.addValue(MetisDataResource.DATA_ID, pId);
433             myValues.addValue(PrometheusDataResource.DATAINFO_TYPE, myInfoType);
434             myValues.addValue(PrometheusDataResource.DATAINFO_OWNER, pSecurity);
435             myValues.addValue(PrometheusDataResource.DATAINFO_VALUE, pValue);
436 
437             /* Create a new Security Info */
438             final MoneyWiseSecurityInfo myInfo = new MoneyWiseSecurityInfo(this, myValues);
439 
440             /* Check that this InfoTypeId has not been previously added */
441             if (!isIdUnique(pId)) {
442                 myInfo.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
443                 throw new MoneyWiseDataException(myInfo, ERROR_VALIDATION);
444             }
445 
446             /* Add the Info to the list */
447             add(myInfo);
448         }
449 
450         @Override
451         public MoneyWiseSecurityInfo addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
452             /* Create the info */
453             final MoneyWiseSecurityInfo myInfo = new MoneyWiseSecurityInfo(this, pValues);
454 
455             /* Check that this InfoId has not been previously added */
456             if (!isIdUnique(myInfo.getIndexedId())) {
457                 myInfo.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
458                 throw new MoneyWiseDataException(myInfo, ERROR_VALIDATION);
459             }
460 
461             /* Add to the list */
462             add(myInfo);
463 
464             /* Return it */
465             return myInfo;
466         }
467 
468         @Override
469         public void postProcessOnLoad() throws OceanusException {
470             /* Validate the SecurityInfo */
471             validateOnLoad();
472 
473             /* Map and Validate the Securities */
474             final PrometheusDataList<?> mySecurities
475                     = getDataSet().getDataList(MoneyWiseBasicDataType.SECURITY, PrometheusDataList.class);
476             mySecurities.mapData();
477             mySecurities.validateOnLoad();
478         }
479     }
480 }