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.format.OceanusDataFormatter;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataMap;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataObjectFormat;
22  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
23  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio.MoneyWisePortfolioList;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity.MoneyWiseSecurityList;
26  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
27  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityClass;
28  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
29  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
30  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
31  
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.Currency;
35  import java.util.HashMap;
36  import java.util.Iterator;
37  import java.util.List;
38  import java.util.Map;
39  
40  /**
41   * Portfolio/Security combination.
42   */
43  public final class MoneyWiseSecurityHolding
44          implements MetisFieldItem, MoneyWiseTransAsset, Comparable<Object> {
45      /**
46       * Name separator.
47       */
48      public static final String SECURITYHOLDING_SEP = ":";
49  
50      /**
51       * New Security Holding text.
52       */
53      public static final String SECURITYHOLDING_NEW = MoneyWiseBasicResource.SECURITYHOLDING_NEW.getValue();
54  
55      /**
56       * Report fields.
57       */
58      private static final MetisFieldSet<MoneyWiseSecurityHolding> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseSecurityHolding.class);
59  
60      /*
61       * UnderlyingMap Field Id.
62       */
63      static {
64          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_ID, MoneyWiseSecurityHolding::getExternalId);
65          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_FIELD_NAME, MoneyWiseSecurityHolding::getName);
66          FIELD_DEFS.declareLocalField(MoneyWiseBasicDataType.PORTFOLIO, MoneyWiseSecurityHolding::getPortfolio);
67          FIELD_DEFS.declareLocalField(MoneyWiseBasicDataType.SECURITY, MoneyWiseSecurityHolding::getSecurity);
68      }
69  
70      /**
71       * The id of the holding.
72       */
73      private final Long theId;
74  
75      /**
76       * The portfolio of the holding.
77       */
78      private MoneyWisePortfolio thePortfolio;
79  
80      /**
81       * The security of the holding.
82       */
83      private MoneyWiseSecurity theSecurity;
84  
85      /**
86       * Constructor.
87       *
88       * @param pPortfolio the portfolio
89       * @param pSecurity  the security
90       */
91      private MoneyWiseSecurityHolding(final MoneyWisePortfolio pPortfolio,
92                                       final MoneyWiseSecurity pSecurity) {
93          /* Set portfolio and security */
94          thePortfolio = pPortfolio;
95          theSecurity = pSecurity;
96  
97          /* Generate the id */
98          theId = MoneyWiseAssetType.createExternalId(MoneyWiseAssetType.SECURITYHOLDING, thePortfolio.getIndexedId(), theSecurity.getIndexedId());
99      }
100 
101     @Override
102     public MetisFieldSet<MoneyWiseSecurityHolding> getDataFieldSet() {
103         return FIELD_DEFS;
104     }
105 
106     @Override
107     public String formatObject(final OceanusDataFormatter pFormatter) {
108         return toString();
109     }
110 
111     @Override
112     public String toString() {
113         return getName();
114     }
115 
116     @Override
117     public Boolean isClosed() {
118         /* Access constituent parts */
119         final MoneyWisePortfolio myPortfolio = getPortfolio();
120         final MoneyWiseSecurity mySecurity = getSecurity();
121 
122         /* Test underlying items */
123         return myPortfolio.isClosed()
124                 || mySecurity.isClosed();
125     }
126 
127     /**
128      * Is the holding deleted?
129      *
130      * @return true/false
131      */
132     public boolean isDeleted() {
133         /* Access constituent parts */
134         final MoneyWisePortfolio myPortfolio = getPortfolio();
135         final MoneyWiseSecurity mySecurity = getSecurity();
136 
137         /* Test underlying items */
138         return myPortfolio.isDeleted()
139                 || mySecurity.isDeleted();
140     }
141 
142     @Override
143     public Long getExternalId() {
144         return theId;
145     }
146 
147     @Override
148     public String getName() {
149         return generateName();
150     }
151 
152     @Override
153     public MoneyWisePayee getParent() {
154         return theSecurity.getParent();
155     }
156 
157     @Override
158     public boolean isTaxFree() {
159         return thePortfolio.isTaxFree();
160     }
161 
162     @Override
163     public boolean isGross() {
164         return thePortfolio.isGross();
165     }
166 
167     @Override
168     public boolean isShares() {
169         return theSecurity.isShares();
170     }
171 
172     @Override
173     public boolean isCapital() {
174         return theSecurity.isCapital();
175     }
176 
177     @Override
178     public boolean isAutoExpense() {
179         return false;
180     }
181 
182     @Override
183     public boolean isHidden() {
184         return false;
185     }
186 
187     /**
188      * Obtain Portfolio.
189      *
190      * @return the portfolio
191      */
192     public MoneyWisePortfolio getPortfolio() {
193         return thePortfolio;
194     }
195 
196     /**
197      * Obtain Security.
198      *
199      * @return the security
200      */
201     public MoneyWiseSecurity getSecurity() {
202         return theSecurity;
203     }
204 
205     @Override
206     public MoneyWiseAssetType getAssetType() {
207         return MoneyWiseAssetType.SECURITYHOLDING;
208     }
209 
210     @Override
211     public MoneyWiseCurrency getAssetCurrency() {
212         return theSecurity.getAssetCurrency();
213     }
214 
215     @Override
216     public Currency getCurrency() {
217         return getAssetCurrency().getCurrency();
218     }
219 
220     @Override
221     public boolean isForeign() {
222         final MoneyWiseCurrency myDefault = thePortfolio.getDataSet().getReportingCurrency();
223         return !myDefault.equals(getAssetCurrency());
224     }
225 
226     /**
227      * Generate the name.
228      *
229      * @return the name.
230      */
231     private String generateName() {
232         /* Build and return the name */
233         final StringBuilder myBuilder = new StringBuilder();
234         myBuilder.append(thePortfolio.getName());
235         myBuilder.append(SECURITYHOLDING_SEP);
236         myBuilder.append(theSecurity.getName());
237         return myBuilder.toString();
238     }
239 
240     /**
241      * Obtain the security class.
242      *
243      * @return the security class.
244      */
245     private MoneyWiseSecurityClass getSecurityTypeClass() {
246         /* Check for match */
247         return theSecurity.getCategoryClass();
248     }
249 
250     /**
251      * Is this holding the required security class.
252      *
253      * @param pClass the required security class.
254      * @return true/false
255      */
256     public boolean isSecurityClass(final MoneyWiseSecurityClass pClass) {
257         /* Check for match */
258         return getSecurityTypeClass() == pClass;
259     }
260 
261     @Override
262     public void touchItem(final PrometheusDataItem pSource) {
263         /* Touch references */
264         thePortfolio.touchItem(pSource);
265         theSecurity.touchItem(pSource);
266     }
267 
268     @Override
269     public boolean equals(final Object pThat) {
270         /* Handle the trivial cases */
271         if (this == pThat) {
272             return true;
273         }
274         if (pThat == null) {
275             return false;
276         }
277         if (!(pThat instanceof MoneyWiseSecurityHolding)) {
278             return false;
279         }
280 
281         /* Compare the Portfolios */
282         final MoneyWiseSecurityHolding myThat = (MoneyWiseSecurityHolding) pThat;
283         if (!getPortfolio().equals(myThat.getPortfolio())) {
284             return false;
285         }
286 
287         /* Compare securities */
288         return getSecurity().equals(myThat.getSecurity());
289     }
290 
291     @Override
292     public int hashCode() {
293         final int myHash = MetisFieldSet.HASH_PRIME * getPortfolio().hashCode();
294         return myHash + getSecurity().hashCode();
295     }
296 
297     @Override
298     public int compareTo(final Object pThat) {
299         /* Handle the trivial cases */
300         if (this.equals(pThat)) {
301             return 0;
302         }
303         if (pThat == null) {
304             return -1;
305         }
306 
307         /* If the Asset is not a SecurityHolding we are last */
308         if (!(pThat instanceof MoneyWiseSecurityHolding)) {
309             return 1;
310         }
311 
312         /* Access as AssetBase */
313         final MoneyWiseSecurityHolding myThat = (MoneyWiseSecurityHolding) pThat;
314 
315         /* Compare portfolios */
316         int iDiff = getPortfolio().compareTo(myThat.getPortfolio());
317         if (iDiff == 0) {
318             /* Compare securities */
319             iDiff = getSecurity().compareTo(myThat.getSecurity());
320         }
321 
322         /* Return the result */
323         return iDiff;
324     }
325 
326     /**
327      * Are the currencies the same?
328      *
329      * @return true/false
330      */
331     protected boolean validCurrencies() {
332         return thePortfolio.getCurrency().equals(theSecurity.getCurrency());
333     }
334 
335     /**
336      * SecurityHolding Map.
337      */
338     public static class MoneyWiseSecurityHoldingMap
339             implements MetisDataObjectFormat, MetisDataMap<Integer, MoneyWisePortfolioHoldingsMap> {
340         /**
341          * Underlying portfolio list.
342          */
343         private final MoneyWisePortfolioList thePortfolios;
344 
345         /**
346          * Underlying security list.
347          */
348         private final MoneyWiseSecurityList theSecurities;
349 
350         /**
351          * The underlying map.
352          */
353         private final Map<Integer, MoneyWisePortfolioHoldingsMap> theMap;
354 
355         /**
356          * Constructor.
357          *
358          * @param pData the dataSet
359          */
360         public MoneyWiseSecurityHoldingMap(final MoneyWiseDataSet pData) {
361             /* Access lists */
362             thePortfolios = pData.getPortfolios();
363             theSecurities = pData.getSecurities();
364             theMap = new HashMap<>();
365         }
366 
367         /**
368          * Constructor.
369          *
370          * @param pEditSet the editSet
371          */
372         public MoneyWiseSecurityHoldingMap(final PrometheusEditSet pEditSet) {
373             /* Access lists */
374             thePortfolios = pEditSet.getDataList(MoneyWiseBasicDataType.PORTFOLIO, MoneyWisePortfolioList.class);
375             theSecurities = pEditSet.getDataList(MoneyWiseBasicDataType.SECURITY, MoneyWiseSecurityList.class);
376             theMap = new HashMap<>();
377         }
378 
379         @Override
380         public Map<Integer, MoneyWisePortfolioHoldingsMap> getUnderlyingMap() {
381             return theMap;
382         }
383 
384         @Override
385         public String formatObject(final OceanusDataFormatter pFormatter) {
386             return MoneyWiseSecurityHoldingMap.class.getSimpleName();
387         }
388 
389         /**
390          * Clear the map.
391          */
392         public void clear() {
393             theMap.clear();
394         }
395 
396         /**
397          * Look up a security holding.
398          *
399          * @param pId the id of the security holding
400          * @return the security holding
401          */
402         public MoneyWiseSecurityHolding findHoldingById(final Long pId) {
403             /* Access the component IDs */
404             final Integer myPortId = getPortfolioId(pId);
405             final Integer mySecId = getSecurityId(pId);
406 
407             /* Look up security map for portfolio */
408             final MoneyWisePortfolioHoldingsMap myMap = getMapForPortfolio(myPortId);
409             return myMap == null
410                     ? null
411                     : myMap.getHoldingForSecurity(mySecId);
412         }
413 
414         /**
415          * Look up a security holding.
416          *
417          * @param pName the name of the security holding
418          * @return the security holding
419          */
420         public MoneyWiseSecurityHolding findHoldingByName(final String pName) {
421             /* Access the component Names */
422             final String myPortName = getPortfolioName(pName);
423             final String mySecName = getSecurityName(pName);
424 
425             /* Look up security map for portfolio */
426             final MoneyWisePortfolioHoldingsMap myMap = getMapForPortfolio(myPortName);
427             return myMap == null
428                     ? null
429                     : myMap.getHoldingForSecurity(mySecName);
430         }
431 
432         /**
433          * Obtain portfolio name from composite name.
434          *
435          * @param pName the composite name
436          * @return the portfolio name
437          */
438         private static String getPortfolioName(final String pName) {
439             final int iIndex = pName.indexOf(SECURITYHOLDING_SEP);
440             return iIndex == -1
441                     ? pName
442                     : pName.substring(0, iIndex);
443         }
444 
445         /**
446          * Obtain security name from composite name.
447          *
448          * @param pName the composite name
449          * @return the security name
450          */
451         private static String getSecurityName(final String pName) {
452             final int iIndex = pName.indexOf(SECURITYHOLDING_SEP);
453             return iIndex == -1
454                     ? ""
455                     : pName.substring(iIndex + 1);
456         }
457 
458         /**
459          * Obtain portfolio id from composite id.
460          *
461          * @param pId the composite id
462          * @return the portfolio id
463          */
464         private static Integer getPortfolioId(final Long pId) {
465             return MoneyWiseAssetType.getMajorId(pId);
466         }
467 
468         /**
469          * Obtain security id from composite id.
470          *
471          * @param pId the composite id
472          * @return the security id
473          */
474         private static Integer getSecurityId(final Long pId) {
475             return MoneyWiseAssetType.getBaseId(pId);
476         }
477 
478         /**
479          * Declare holding.
480          *
481          * @param pPortfolio the portfolio
482          * @param pSecurity  the security
483          * @return the holding
484          */
485         public MoneyWiseSecurityHolding declareHolding(final MoneyWisePortfolio pPortfolio,
486                                                        final MoneyWiseSecurity pSecurity) {
487             /* Access the portfolio map */
488             final MoneyWisePortfolioHoldingsMap myPortMap = getMapForPortfolio(pPortfolio.getIndexedId());
489             if (myPortMap == null) {
490                 throw new IllegalStateException("Invalid Portfolio");
491             }
492             final Map<Integer, MoneyWiseSecurityHolding> myMap = myPortMap.getUnderlyingMap();
493 
494             /* Look up existing holding */
495             final Integer myId = pSecurity.getIndexedId();
496             return myMap.computeIfAbsent(myId, i -> new MoneyWiseSecurityHolding(pPortfolio, pSecurity));
497         }
498 
499         /**
500          * Obtain or allocate the map for the portfolio.
501          *
502          * @param pId the id of the portfolio
503          * @return the map
504          */
505         private MoneyWisePortfolioHoldingsMap getMapForPortfolio(final Integer pId) {
506             /* Look up in the map */
507             MoneyWisePortfolioHoldingsMap myMap = theMap.get(pId);
508 
509             /* If the Id is not found */
510             if (myMap == null) {
511                 /* Look up the portfolio as a double check */
512                 final MoneyWisePortfolio myPortfolio = thePortfolios.findItemById(pId);
513 
514                 /* Reject if no such portfolio */
515                 if (myPortfolio == null
516                         || myPortfolio.isDeleted()) {
517                     return null;
518                 }
519 
520                 /* Allocate and store the map */
521                 myMap = new MoneyWisePortfolioHoldingsMap(myPortfolio, theSecurities);
522                 theMap.put(pId, myMap);
523             }
524 
525             /* Return the map */
526             return myMap;
527         }
528 
529         /**
530          * Obtain or allocate the map for the portfolio.
531          *
532          * @param pName the name of the portfolio
533          * @return the map
534          */
535         private MoneyWisePortfolioHoldingsMap getMapForPortfolio(final String pName) {
536             /* Look up the portfolio */
537             final MoneyWisePortfolio myPortfolio = thePortfolios.findItemByName(pName);
538 
539             /* Reject if no such portfolio */
540             if (myPortfolio == null) {
541                 return null;
542             }
543 
544             /* Look up in the map */
545             final Integer myId = myPortfolio.getIndexedId();
546             return theMap.computeIfAbsent(myId, i -> new MoneyWisePortfolioHoldingsMap(myPortfolio, theSecurities));
547         }
548 
549         /**
550          * DeRegister Portfolio.
551          *
552          * @param pPortfolio the portfolio
553          */
554         public void deRegister(final MoneyWisePortfolio pPortfolio) {
555             /* Ensure that we do not reference this portfolio */
556             final Integer myId = pPortfolio.getIndexedId();
557             theMap.remove(myId);
558         }
559 
560         /**
561          * DeRegister Security.
562          *
563          * @param pSecurity the security
564          */
565         public void deRegister(final MoneyWiseSecurity pSecurity) {
566             /* Access the id */
567             final Integer myId = pSecurity.getIndexedId();
568 
569             /* Iterate through the portfolio maps */
570             final Iterator<MoneyWisePortfolioHoldingsMap> myIterator = theMap.values().iterator();
571             while (myIterator.hasNext()) {
572                 final MoneyWisePortfolioHoldingsMap myMap = myIterator.next();
573 
574                 /* Ensure that we do not reference this security */
575                 myMap.getUnderlyingMap().remove(myId);
576             }
577         }
578 
579         /**
580          * Obtain existing holding list for Portfolio.
581          *
582          * @param pPortfolio the portfolio
583          * @return the iterator
584          */
585         public Iterator<MoneyWiseSecurityHolding> existingIterator(final MoneyWisePortfolio pPortfolio) {
586             /* Look up in the map */
587             final MoneyWisePortfolioHoldingsMap myMap = theMap.get(pPortfolio.getIndexedId());
588 
589             /* return the iterator */
590             return myMap == null
591                     ? null
592                     : myMap.existingIterator();
593         }
594 
595         /**
596          * Obtain new holding list for Portfolio.
597          *
598          * @param pPortfolio the portfolio
599          * @return the iterator
600          */
601         public Iterator<MoneyWiseSecurityHolding> newIterator(final MoneyWisePortfolio pPortfolio) {
602             return newIterator(pPortfolio, null);
603         }
604 
605         /**
606          * Obtain new holding list for Portfolio.
607          *
608          * @param pPortfolio the portfolio
609          * @param pClass     the class of holdings or null for all
610          * @return the iterator
611          */
612         public Iterator<MoneyWiseSecurityHolding> newIterator(final MoneyWisePortfolio pPortfolio,
613                                                               final MoneyWiseSecurityClass pClass) {
614             /* Look up in the map */
615             final MoneyWisePortfolioHoldingsMap myMap = theMap.get(pPortfolio.getIndexedId());
616 
617             /* return the iterator */
618             return myMap == null
619                     ? fullIterator(pPortfolio, pClass)
620                     : myMap.newIterator(pClass);
621         }
622 
623         /**
624          * Obtain new holding list for Portfolio.
625          *
626          * @param pPortfolio the portfolio
627          * @param pClass     the class of holdings or null for all
628          * @return the iterator
629          */
630         private Iterator<MoneyWiseSecurityHolding> fullIterator(final MoneyWisePortfolio pPortfolio,
631                                                                 final MoneyWiseSecurityClass pClass) {
632             /* If the portfolio is closed/deleted */
633             if (pPortfolio.isClosed() || pPortfolio.isDeleted()) {
634                 /* No iterator */
635                 return null;
636             }
637 
638             /* Create an empty list */
639             List<MoneyWiseSecurityHolding> myList = new ArrayList<>();
640 
641             /* Loop through the securities */
642             final Iterator<MoneyWiseSecurity> myIterator = theSecurities.iterator();
643             while (myIterator.hasNext()) {
644                 final MoneyWiseSecurity mySecurity = myIterator.next();
645 
646                 /* Ignore closed/deleted and wrong class */
647                 boolean bIgnore = mySecurity.isClosed() || mySecurity.isDeleted();
648                 bIgnore |= pClass != null && !pClass.equals(mySecurity.getCategoryClass());
649                 if (bIgnore) {
650                     continue;
651                 }
652 
653                 /* Create a new holding and add to the list */
654                 final MoneyWiseSecurityHolding myHolding = new MoneyWiseSecurityHolding(pPortfolio, mySecurity);
655                 myList.add(myHolding);
656             }
657 
658             /* Sort list or delete if empty */
659             if (myList.isEmpty()) {
660                 myList = null;
661             } else {
662                 Collections.sort(myList);
663             }
664 
665             /* return iterator */
666             return myList == null
667                     ? null
668                     : myList.iterator();
669         }
670     }
671 
672     /**
673      * PortfolioHoldings Map.
674      */
675     public static final class MoneyWisePortfolioHoldingsMap
676             implements MetisDataObjectFormat, MetisDataMap<Integer, MoneyWiseSecurityHolding> {
677         /**
678          * Portfolio.
679          */
680         private final MoneyWisePortfolio thePortfolio;
681 
682         /**
683          * Underlying security list.
684          */
685         private final MoneyWiseSecurityList theSecurities;
686 
687         /**
688          * The underlying map.
689          */
690         private final Map<Integer, MoneyWiseSecurityHolding> theMap;
691 
692         /**
693          * Constructor.
694          *
695          * @param pPortfolio  the portfolio
696          * @param pSecurities the security list
697          */
698         private MoneyWisePortfolioHoldingsMap(final MoneyWisePortfolio pPortfolio,
699                                               final MoneyWiseSecurityList pSecurities) {
700             thePortfolio = pPortfolio;
701             theSecurities = pSecurities;
702             theMap = new HashMap<>();
703         }
704 
705         @Override
706         public Map<Integer, MoneyWiseSecurityHolding> getUnderlyingMap() {
707             return theMap;
708         }
709 
710         @Override
711         public String formatObject(final OceanusDataFormatter pFormatter) {
712             return thePortfolio.formatObject(pFormatter);
713         }
714 
715         @Override
716         public String toString() {
717             return thePortfolio.toString();
718         }
719 
720         /**
721          * Obtain or allocate the holding for the security.
722          *
723          * @param pId the id of the security
724          * @return the holding
725          */
726         private MoneyWiseSecurityHolding getHoldingForSecurity(final Integer pId) {
727             /* Look up in the map */
728             MoneyWiseSecurityHolding myHolding = theMap.get(pId);
729 
730             /* If the Id is not found */
731             if (myHolding == null) {
732                 /* Look up the security as a double check */
733                 final MoneyWiseSecurity mySecurity = theSecurities.findItemById(pId);
734 
735                 /* Reject if no such security */
736                 if (mySecurity == null || mySecurity.isDeleted()) {
737                     return null;
738                 }
739 
740                 /* Allocate and store the holding */
741                 myHolding = new MoneyWiseSecurityHolding(thePortfolio, mySecurity);
742                 theMap.put(pId, myHolding);
743             }
744 
745             /* Return the holding */
746             return myHolding;
747         }
748 
749         /**
750          * Obtain or allocate the holding for the security.
751          *
752          * @param pName the name of the security
753          * @return the holding
754          */
755         private MoneyWiseSecurityHolding getHoldingForSecurity(final String pName) {
756             /* Look up the security */
757             final MoneyWiseSecurity mySecurity = theSecurities.findItemByName(pName);
758 
759             /* Reject if no such security */
760             if (mySecurity == null) {
761                 return null;
762             }
763 
764             /* Look up in the map */
765             final Integer myId = mySecurity.getIndexedId();
766             return theMap.computeIfAbsent(myId, i -> new MoneyWiseSecurityHolding(thePortfolio, mySecurity));
767         }
768 
769         /**
770          * Obtain existing holding list for Portfolio.
771          *
772          * @return the iterator
773          */
774         private Iterator<MoneyWiseSecurityHolding> existingIterator() {
775             /* If the portfolio is closed/deleted */
776             if (thePortfolio.isClosed() || thePortfolio.isDeleted()) {
777                 /* No iterator */
778                 return null;
779             }
780 
781             /* Create an empty list */
782             List<MoneyWiseSecurityHolding> myList = new ArrayList<>();
783 
784             /* Loop through the holdings */
785             final Iterator<MoneyWiseSecurityHolding> myIterator = theMap.values().iterator();
786             while (myIterator.hasNext()) {
787                 final MoneyWiseSecurityHolding myHolding = myIterator.next();
788                 final MoneyWiseSecurity mySecurity = myHolding.getSecurity();
789 
790                 /* Ignore closed/deleted */
791                 if (!mySecurity.isClosed() && !mySecurity.isDeleted()) {
792                     /* Add to the list */
793                     myList.add(myHolding);
794                 }
795             }
796 
797             /* Sort list or delete if empty */
798             if (myList.isEmpty()) {
799                 myList = null;
800             } else {
801                 Collections.sort(myList);
802             }
803 
804             /* return iterator */
805             return myList == null
806                     ? null
807                     : myList.iterator();
808         }
809 
810         /**
811          * Obtain new holding list for Portfolio.
812          *
813          * @param pClass the class of holdings or null for all
814          * @return the iterator
815          */
816         private Iterator<MoneyWiseSecurityHolding> newIterator(final MoneyWiseSecurityClass pClass) {
817             /* If the portfolio is closed/deleted */
818             if (thePortfolio.isClosed() || thePortfolio.isDeleted()) {
819                 /* No iterator */
820                 return null;
821             }
822 
823             /* Create an empty list */
824             List<MoneyWiseSecurityHolding> myList = new ArrayList<>();
825 
826             /* Loop through the securities */
827             final Iterator<MoneyWiseSecurity> myIterator = theSecurities.iterator();
828             while (myIterator.hasNext()) {
829                 final MoneyWiseSecurity mySecurity = myIterator.next();
830 
831                 /* Ignore closed/deleted and wrong class/currency */
832                 boolean bIgnore = mySecurity.isClosed() || mySecurity.isDeleted();
833                 bIgnore |= pClass != null && pClass.equals(mySecurity.getCategoryClass());
834                 if (bIgnore) {
835                     continue;
836                 }
837 
838                 /* Only add if not currently present */
839                 if (theMap.get(mySecurity.getIndexedId()) == null) {
840                     /* Create a new holding and add to the list */
841                     final MoneyWiseSecurityHolding myHolding = new MoneyWiseSecurityHolding(thePortfolio, mySecurity);
842                     myList.add(myHolding);
843                 }
844             }
845 
846             /* Sort list or delete if empty */
847             if (myList.isEmpty()) {
848                 myList = null;
849             } else {
850                 Collections.sort(myList);
851             }
852 
853             /* return iterator */
854             return myList == null
855                     ? null
856                     : myList.iterator();
857         }
858     }
859 }