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.lethe.reports;
18  
19  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
20  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
21  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
23  import io.github.tonywasher.joceanus.metis.report.MetisReportBase;
24  import io.github.tonywasher.joceanus.metis.report.MetisReportHTMLBuilder;
25  import io.github.tonywasher.joceanus.metis.report.MetisReportHTMLBuilder.MetisHTMLTable;
26  import io.github.tonywasher.joceanus.metis.report.MetisReportManager;
27  import io.github.tonywasher.joceanus.metis.report.MetisReportReferenceManager.DelayedTable;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
30  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCashCategory;
31  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDepositCategory;
32  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseLoanCategory;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCashCategoryClass;
34  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseDepositCategoryClass;
35  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseLoanCategoryClass;
36  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysis;
37  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisCashBucket;
38  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisCashBucket.MoneyWiseAnalysisCashBucketList;
39  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisCashCategoryBucket;
40  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisCashCategoryBucket.MoneyWiseAnalysisCashCategoryBucketList;
41  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisDepositBucket;
42  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisDepositBucket.MoneyWiseAnalysisDepositBucketList;
43  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisDepositCategoryBucket;
44  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisDepositCategoryBucket.MoneyWiseAnalysisDepositCategoryBucketList;
45  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisLoanBucket;
46  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisLoanBucket.MoneyWiseAnalysisLoanBucketList;
47  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisLoanCategoryBucket;
48  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisLoanCategoryBucket.MoneyWiseAnalysisLoanCategoryBucketList;
49  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisPortfolioBucket;
50  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisPortfolioBucket.MoneyWiseAnalysisPortfolioBucketList;
51  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisPortfolioCashBucket;
52  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisSecurityBucket;
53  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisSecurityBucket.MoneyWiseAnalysisSecurityBucketList;
54  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisAccountAttr;
55  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisAccountValues;
56  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisSecurityAttr;
57  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisSecurityValues;
58  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter;
59  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisCashFilter;
60  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisDepositFilter;
61  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisLoanFilter;
62  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisPortfolioCashFilter;
63  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisSecurityFilter;
64  import org.w3c.dom.Document;
65  import org.w3c.dom.Element;
66  
67  import java.util.Iterator;
68  
69  /**
70   * BalanceSheet report builder.
71   */
72  public class MoneyWiseReportBalanceSheet
73          extends MetisReportBase<MoneyWiseAnalysis, MoneyWiseAnalysisFilter<?, ?>> {
74      /**
75       * The Title text.
76       */
77      private static final String TEXT_TITLE = MoneyWiseReportResource.BALANCESHEET_TITLE.getValue();
78  
79      /**
80       * The Portfolio cash account name.
81       */
82      protected static final String TEXT_CASH = MoneyWiseBasicResource.CASH_NAME.getValue();
83  
84      /**
85       * HTML builder.
86       */
87      private final MetisReportHTMLBuilder theBuilder;
88  
89      /**
90       * The Formatter.
91       */
92      private final OceanusDataFormatter theFormatter;
93  
94      /**
95       * Data Analysis.
96       */
97      private MoneyWiseAnalysis theAnalysis;
98  
99      /**
100      * Constructor.
101      *
102      * @param pManager the Report Manager
103      */
104     protected MoneyWiseReportBalanceSheet(final MetisReportManager<MoneyWiseAnalysisFilter<?, ?>> pManager) {
105         /* Access underlying utilities */
106         theBuilder = pManager.getBuilder();
107         theFormatter = theBuilder.getDataFormatter();
108     }
109 
110     @Override
111     public Document createReport(final MoneyWiseAnalysis pAnalysis) {
112         /* Access the bucket lists */
113         theAnalysis = pAnalysis;
114         final MoneyWiseAnalysisDepositCategoryBucketList myDeposits = theAnalysis.getDepositCategories();
115         final MoneyWiseAnalysisCashCategoryBucketList myCash = theAnalysis.getCashCategories();
116         final MoneyWiseAnalysisLoanCategoryBucketList myLoans = theAnalysis.getLoanCategories();
117         final MoneyWiseAnalysisPortfolioBucketList myPortfolios = theAnalysis.getPortfolios();
118         final OceanusDateRange myDateRange = theAnalysis.getDateRange();
119 
120         /* Create the totals */
121         final OceanusMoney myTotal = new OceanusMoney();
122         final OceanusMoney myBase = new OceanusMoney();
123         final OceanusMoney myDelta = new OceanusMoney();
124 
125         /* Start the report */
126         final Element myBody = theBuilder.startReport();
127         theBuilder.makeTitle(myBody, TEXT_TITLE, theFormatter.formatObject(myDateRange));
128 
129         /* Initialise the table */
130         final MetisHTMLTable myTable = theBuilder.startTable(myBody);
131         theBuilder.startTotalRow(myTable);
132         theBuilder.makeTitleCell(myTable);
133         theBuilder.makeTitleCell(myTable, theFormatter.formatObject(myDateRange.getEnd()));
134         theBuilder.makeTitleCell(myTable, theFormatter.formatObject(myDateRange.getStart()));
135         theBuilder.makeTitleCell(myTable, MoneyWiseReportBuilder.TEXT_PROFIT);
136 
137         /* If we have deposits */
138         if (!myDeposits.isEmpty()) {
139             /* Loop through the SubTotal Buckets */
140             final Iterator<MoneyWiseAnalysisDepositCategoryBucket> myIterator = myDeposits.iterator();
141             while (myIterator.hasNext()) {
142                 final MoneyWiseAnalysisDepositCategoryBucket myBucket = myIterator.next();
143 
144                 /* Only process subTotal items */
145                 if (!myBucket.getAccountCategory().isCategoryClass(MoneyWiseDepositCategoryClass.PARENT)) {
146                     continue;
147                 }
148 
149                 /* Access values */
150                 final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
151                 final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
152 
153                 /* Format the Category Total */
154                 theBuilder.startRow(myTable);
155                 theBuilder.makeTableLinkCell(myTable, myBucket.getName());
156                 theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
157                 theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
158                 theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
159 
160                 /* Add the category report */
161                 makeDepositCategoryReport(myTable, myBucket);
162             }
163 
164             /* Access totals */
165             final MoneyWiseAnalysisDepositCategoryBucket myTotals = myDeposits.getTotals();
166             final MoneyWiseAnalysisAccountValues myValues = myTotals.getValues();
167             final MoneyWiseAnalysisAccountValues myBaseValues = myTotals.getBaseValues();
168 
169             /* Add to running totals */
170             myTotal.addAmount(myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
171             myBase.addAmount(myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
172             myDelta.addAmount(myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
173         }
174 
175         /* If we have cash */
176         if (!myCash.isEmpty()) {
177             /* Loop through the SubTotal Buckets */
178             final Iterator<MoneyWiseAnalysisCashCategoryBucket> myIterator = myCash.iterator();
179             while (myIterator.hasNext()) {
180                 final MoneyWiseAnalysisCashCategoryBucket myBucket = myIterator.next();
181 
182                 /* Only process subTotal items */
183                 if (!myBucket.getAccountCategory().isCategoryClass(MoneyWiseCashCategoryClass.PARENT)) {
184                     continue;
185                 }
186 
187                 /* Access values */
188                 final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
189                 final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
190 
191                 /* Format the Category Total */
192                 theBuilder.startRow(myTable);
193                 theBuilder.makeTableLinkCell(myTable, myBucket.getName());
194                 theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
195                 theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
196                 theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
197 
198                 /* Add the category report */
199                 makeCashCategoryReport(myTable, myBucket);
200             }
201 
202             /* Access totals */
203             final MoneyWiseAnalysisCashCategoryBucket myTotals = myCash.getTotals();
204             final MoneyWiseAnalysisAccountValues myValues = myTotals.getValues();
205             final MoneyWiseAnalysisAccountValues myBaseValues = myTotals.getBaseValues();
206 
207             /* Add to running totals */
208             myTotal.addAmount(myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
209             myBase.addAmount(myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
210             myDelta.addAmount(myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
211         }
212 
213         /* If we have portfolios */
214         if (!myPortfolios.isEmpty()) {
215             /* Access totals */
216             final MoneyWiseAnalysisPortfolioBucket myTotals = myPortfolios.getTotals();
217             final MoneyWiseAnalysisSecurityValues myValues = myTotals.getValues();
218             final MoneyWiseAnalysisSecurityValues myBaseValues = myTotals.getBaseValues();
219 
220             /* Access interesting values */
221             final OceanusMoney myValuation = myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION);
222             final OceanusMoney myBaseValuation = myBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION);
223             final OceanusMoney myDeltaValuation = myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA);
224 
225             /* Format the Portfolios Total */
226             theBuilder.startRow(myTable);
227             theBuilder.makeTableLinkCell(myTable, MoneyWiseBasicDataType.PORTFOLIO.getListName());
228             theBuilder.makeTotalCell(myTable, myValuation);
229             theBuilder.makeTotalCell(myTable, myBaseValuation);
230             theBuilder.makeTotalCell(myTable, myDeltaValuation);
231 
232             /* Make the portfolio report */
233             makePortfolioReport(myTable);
234 
235             /* Add to running totals */
236             myTotal.addAmount(myValuation);
237             myBase.addAmount(myBaseValuation);
238             myDelta.addAmount(myDeltaValuation);
239         }
240 
241         /* If we have loans */
242         if (!myLoans.isEmpty()) {
243             /* Loop through the SubTotal Buckets */
244             final Iterator<MoneyWiseAnalysisLoanCategoryBucket> myIterator = myLoans.iterator();
245             while (myIterator.hasNext()) {
246                 final MoneyWiseAnalysisLoanCategoryBucket myBucket = myIterator.next();
247 
248                 /* Only process subTotal items */
249                 if (!myBucket.getAccountCategory().isCategoryClass(MoneyWiseLoanCategoryClass.PARENT)) {
250                     continue;
251                 }
252 
253                 /* Access values */
254                 final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
255                 final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
256 
257                 /* Format the Category Total */
258                 theBuilder.startRow(myTable);
259                 theBuilder.makeTableLinkCell(myTable, myBucket.getName());
260                 theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
261                 theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
262                 theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
263 
264                 /* Add the category report */
265                 makeLoanCategoryReport(myTable, myBucket);
266             }
267 
268             /* Access totals */
269             final MoneyWiseAnalysisLoanCategoryBucket myTotals = myLoans.getTotals();
270             final MoneyWiseAnalysisAccountValues myValues = myTotals.getValues();
271             final MoneyWiseAnalysisAccountValues myBaseValues = myTotals.getBaseValues();
272 
273             /* Add to running totals */
274             myTotal.addAmount(myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
275             myBase.addAmount(myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
276             myDelta.addAmount(myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
277         }
278 
279         /* Format the total */
280         theBuilder.startTotalRow(myTable);
281         theBuilder.makeTitleCell(myTable, MoneyWiseReportBuilder.TEXT_TOTAL);
282         theBuilder.makeTotalCell(myTable, myTotal);
283         theBuilder.makeTotalCell(myTable, myBase);
284         theBuilder.makeTotalCell(myTable, myDelta);
285 
286         /* Return the document */
287         return theBuilder.getDocument();
288     }
289 
290     /**
291      * Build a category report.
292      *
293      * @param pParent   the table parent
294      * @param pCategory the category bucket
295      */
296     private void makeDepositCategoryReport(final MetisHTMLTable pParent,
297                                            final MoneyWiseAnalysisDepositCategoryBucket pCategory) {
298         /* Access the category */
299         final MoneyWiseAnalysisDepositCategoryBucketList myCategories = theAnalysis.getDepositCategories();
300         final MoneyWiseDepositCategory myCategory = pCategory.getAccountCategory();
301 
302         /* Create an embedded table */
303         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
304 
305         /* Loop through the Category Buckets */
306         final Iterator<MoneyWiseAnalysisDepositCategoryBucket> myIterator = myCategories.iterator();
307         while (myIterator.hasNext()) {
308             final MoneyWiseAnalysisDepositCategoryBucket myBucket = myIterator.next();
309 
310             /* Skip record if incorrect category */
311             final MoneyWiseDepositCategory myCurr = myBucket.getAccountCategory();
312             if (!MetisDataDifference.isEqual(myCurr.getParentCategory(), myCategory)) {
313                 continue;
314             }
315 
316             /* Access bucket name */
317             final String myName = myBucket.getName();
318 
319             /* Access values */
320             final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
321             final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
322 
323             /* Create the SubCategory row */
324             theBuilder.startRow(myTable);
325             theBuilder.makeDelayLinkCell(myTable, myName, myCurr.getSubCategory());
326             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
327             theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
328             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
329 
330             /* Note the delayed subTable */
331             setDelayedTable(myName, myTable, myBucket);
332         }
333 
334         /* Embed the table correctly */
335         theBuilder.embedTable(myTable, pCategory.getName());
336     }
337 
338     /**
339      * Build a category report.
340      *
341      * @param pParent   the table parent
342      * @param pCategory the category bucket
343      */
344     private void makeCashCategoryReport(final MetisHTMLTable pParent,
345                                         final MoneyWiseAnalysisCashCategoryBucket pCategory) {
346         /* Access the category */
347         final MoneyWiseAnalysisCashCategoryBucketList myCategories = theAnalysis.getCashCategories();
348         final MoneyWiseCashCategory myCategory = pCategory.getAccountCategory();
349 
350         /* Create an embedded table */
351         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
352 
353         /* Loop through the Category Buckets */
354         final Iterator<MoneyWiseAnalysisCashCategoryBucket> myIterator = myCategories.iterator();
355         while (myIterator.hasNext()) {
356             final MoneyWiseAnalysisCashCategoryBucket myBucket = myIterator.next();
357 
358             /* Skip record if incorrect category */
359             final MoneyWiseCashCategory myCurr = myBucket.getAccountCategory();
360             if (!MetisDataDifference.isEqual(myCurr.getParentCategory(), myCategory)) {
361                 continue;
362             }
363 
364             /* Access bucket name */
365             final String myName = myBucket.getName();
366 
367             /* Access values */
368             final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
369             final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
370 
371             /* Create the SubCategory row */
372             theBuilder.startRow(myTable);
373             theBuilder.makeDelayLinkCell(myTable, myName, myCurr.getSubCategory());
374             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
375             theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
376             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
377 
378             /* Note the delayed subTable */
379             setDelayedTable(myName, myTable, myBucket);
380         }
381 
382         /* Embed the table correctly */
383         theBuilder.embedTable(myTable, pCategory.getName());
384     }
385 
386     /**
387      * Build a category report.
388      *
389      * @param pParent   the table parent
390      * @param pCategory the category bucket
391      */
392     private void makeLoanCategoryReport(final MetisHTMLTable pParent,
393                                         final MoneyWiseAnalysisLoanCategoryBucket pCategory) {
394         /* Access the category */
395         final MoneyWiseAnalysisLoanCategoryBucketList myCategories = theAnalysis.getLoanCategories();
396         final MoneyWiseLoanCategory myCategory = pCategory.getAccountCategory();
397 
398         /* Create an embedded table */
399         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
400 
401         /* Loop through the Category Buckets */
402         final Iterator<MoneyWiseAnalysisLoanCategoryBucket> myIterator = myCategories.iterator();
403         while (myIterator.hasNext()) {
404             final MoneyWiseAnalysisLoanCategoryBucket myBucket = myIterator.next();
405 
406             /* Skip record if incorrect category */
407             final MoneyWiseLoanCategory myCurr = myBucket.getAccountCategory();
408             if (!MetisDataDifference.isEqual(myCurr.getParentCategory(), myCategory)) {
409                 continue;
410             }
411 
412             /* Access bucket name */
413             final String myName = myBucket.getName();
414 
415             /* Access values */
416             final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
417             final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
418 
419             /* Create the SubCategory row */
420             theBuilder.startRow(myTable);
421             theBuilder.makeDelayLinkCell(myTable, myName, myCurr.getSubCategory());
422             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
423             theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
424             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
425 
426             /* Note the delayed subTable */
427             setDelayedTable(myName, myTable, myBucket);
428         }
429 
430         /* Embed the table correctly */
431         theBuilder.embedTable(myTable, pCategory.getName());
432     }
433 
434     /**
435      * Build a portfolio report.
436      *
437      * @param pParent the table parent
438      */
439     private void makePortfolioReport(final MetisHTMLTable pParent) {
440         /* Access the portfolios */
441         final MoneyWiseAnalysisPortfolioBucketList myPortfolios = theAnalysis.getPortfolios();
442 
443         /* Create an embedded table */
444         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
445 
446         /* Loop through the Portfolio Buckets */
447         final Iterator<MoneyWiseAnalysisPortfolioBucket> myIterator = myPortfolios.iterator();
448         while (myIterator.hasNext()) {
449             final MoneyWiseAnalysisPortfolioBucket myBucket = myIterator.next();
450 
451             /* Access bucket name */
452             final String myName = myBucket.getName();
453 
454             /* Access values */
455             final MoneyWiseAnalysisSecurityValues myValues = myBucket.getValues();
456             final MoneyWiseAnalysisSecurityValues myBaseValues = myBucket.getBaseValues();
457 
458             /* Create the SubCategory row */
459             theBuilder.startRow(myTable);
460             theBuilder.makeDelayLinkCell(myTable, myName);
461             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
462             theBuilder.makeTotalCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
463             theBuilder.makeTotalCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA));
464 
465             /* Note the delayed subTable */
466             setDelayedTable(myName, myTable, myBucket);
467         }
468 
469         /* Embed the table correctly */
470         theBuilder.embedTable(myTable, MoneyWiseBasicDataType.PORTFOLIO.getListName());
471     }
472 
473     @Override
474     public MetisHTMLTable createDelayedTable(final DelayedTable pTable) {
475         /* Access the source */
476         final Object mySource = pTable.getSource();
477         if (mySource instanceof MoneyWiseAnalysisDepositCategoryBucket mySourceBucket) {
478             return createDelayedDeposit(pTable.getParent(), mySourceBucket);
479         } else if (mySource instanceof MoneyWiseAnalysisCashCategoryBucket mySourceBucket) {
480             return createDelayedCash(pTable.getParent(), mySourceBucket);
481         } else if (mySource instanceof MoneyWiseAnalysisLoanCategoryBucket mySourceBucket) {
482             return createDelayedLoan(pTable.getParent(), mySourceBucket);
483         } else if (mySource instanceof MoneyWiseAnalysisPortfolioBucket mySourceBucket) {
484             return createDelayedPortfolio(pTable.getParent(), mySourceBucket);
485         }
486 
487         /* Return the null table */
488         return null;
489     }
490 
491     /**
492      * Create a delayed deposit category table.
493      *
494      * @param pParent the parent table
495      * @param pSource the source bucket
496      * @return the new document fragment
497      */
498     private MetisHTMLTable createDelayedDeposit(final MetisHTMLTable pParent,
499                                                 final MoneyWiseAnalysisDepositCategoryBucket pSource) {
500         /* Access the category */
501         final MoneyWiseAnalysisDepositBucketList myDeposits = theAnalysis.getDeposits();
502         final MoneyWiseDepositCategory myCategory = pSource.getAccountCategory();
503         final boolean isForeign = pSource.hasForeignCurrency();
504 
505         /* Create an embedded table */
506         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
507 
508         /* Loop through the Deposit Buckets */
509         final Iterator<MoneyWiseAnalysisDepositBucket> myIterator = myDeposits.iterator();
510         while (myIterator.hasNext()) {
511             final MoneyWiseAnalysisDepositBucket myBucket = myIterator.next();
512 
513             /* Skip record if incorrect category */
514             if (!MetisDataDifference.isEqual(myBucket.getCategory(), myCategory)) {
515                 continue;
516             }
517 
518             /* Access bucket name */
519             final String myName = myBucket.getName();
520 
521             /* Access values */
522             final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
523             final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
524 
525             /* Create the detail row */
526             theBuilder.startRow(myTable);
527             theBuilder.makeFilterLinkCell(myTable, myName);
528 
529             /* Handle foreign accounts */
530             if (isForeign) {
531                 if (myBucket.isForeignCurrency()) {
532                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
533                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
534                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
535                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
536                 } else {
537                     theBuilder.makeStretchedValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
538                     theBuilder.makeStretchedValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
539                 }
540             } else {
541                 theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
542                 theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
543             }
544             theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
545 
546             /* Record the filter */
547             setFilterForId(myName, myBucket);
548         }
549 
550         /* Return the table */
551         return myTable;
552     }
553 
554     /**
555      * Create a delayed cash category table.
556      *
557      * @param pParent the parent table
558      * @param pSource the source bucket
559      * @return the new document fragment
560      */
561     private MetisHTMLTable createDelayedCash(final MetisHTMLTable pParent,
562                                              final MoneyWiseAnalysisCashCategoryBucket pSource) {
563         /* Access the category */
564         final MoneyWiseAnalysisCashBucketList myCash = theAnalysis.getCash();
565         final MoneyWiseCashCategory myCategory = pSource.getAccountCategory();
566         final boolean isForeign = pSource.hasForeignCurrency();
567 
568         /* Create an embedded table */
569         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
570 
571         /* Loop through the Cash Buckets */
572         final Iterator<MoneyWiseAnalysisCashBucket> myIterator = myCash.iterator();
573         while (myIterator.hasNext()) {
574             final MoneyWiseAnalysisCashBucket myBucket = myIterator.next();
575 
576             /* Skip record if incorrect category */
577             if (!MetisDataDifference.isEqual(myBucket.getCategory(), myCategory)) {
578                 continue;
579             }
580 
581             /* Access bucket name */
582             final String myName = myBucket.getName();
583 
584             /* Access values */
585             final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
586             final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
587 
588             /* Create the detail row */
589             theBuilder.startRow(myTable);
590             theBuilder.makeFilterLinkCell(myTable, myName);
591 
592             /* Handle foreign accounts */
593             if (isForeign) {
594                 if (myBucket.isForeignCurrency()) {
595                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
596                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
597                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
598                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
599                 } else {
600                     theBuilder.makeStretchedValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
601                     theBuilder.makeStretchedValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
602                 }
603             } else {
604                 theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
605                 theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
606             }
607             theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
608 
609             /* Record the filter */
610             setFilterForId(myName, myBucket);
611         }
612 
613         /* Return the table */
614         return myTable;
615     }
616 
617     /**
618      * Create a delayed loan category table.
619      *
620      * @param pParent the parent table
621      * @param pSource the source bucket
622      * @return the new document fragment
623      */
624     private MetisHTMLTable createDelayedLoan(final MetisHTMLTable pParent,
625                                              final MoneyWiseAnalysisLoanCategoryBucket pSource) {
626         /* Access the category */
627         final MoneyWiseAnalysisLoanBucketList myLoans = theAnalysis.getLoans();
628         final MoneyWiseLoanCategory myCategory = pSource.getAccountCategory();
629         final boolean isForeign = pSource.hasForeignCurrency();
630 
631         /* Create an embedded table */
632         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
633 
634         /* Loop through the Loan Buckets */
635         final Iterator<MoneyWiseAnalysisLoanBucket> myIterator = myLoans.iterator();
636         while (myIterator.hasNext()) {
637             final MoneyWiseAnalysisLoanBucket myBucket = myIterator.next();
638 
639             /* Skip record if incorrect category */
640             if (!MetisDataDifference.isEqual(myBucket.getCategory(), myCategory)) {
641                 continue;
642             }
643 
644             /* Access bucket name */
645             final String myName = myBucket.getName();
646 
647             /* Access values */
648             final MoneyWiseAnalysisAccountValues myValues = myBucket.getValues();
649             final MoneyWiseAnalysisAccountValues myBaseValues = myBucket.getBaseValues();
650 
651             /* Create the detail row */
652             theBuilder.startRow(myTable);
653             theBuilder.makeFilterLinkCell(myTable, myName);
654 
655             /* Handle foreign accounts */
656             if (isForeign) {
657                 if (myBucket.isForeignCurrency()) {
658                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
659                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
660                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
661                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
662                 } else {
663                     theBuilder.makeStretchedValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
664                     theBuilder.makeStretchedValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
665                 }
666             } else {
667                 theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
668                 theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
669             }
670             theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
671 
672             /* Record the filter */
673             setFilterForId(myName, myBucket);
674         }
675 
676         /* Return the table */
677         return myTable;
678     }
679 
680     /**
681      * Create a delayed portfolio table.
682      *
683      * @param pParent the parent table
684      * @param pSource the source bucket
685      * @return the new document fragment
686      */
687     private MetisHTMLTable createDelayedPortfolio(final MetisHTMLTable pParent,
688                                                   final MoneyWiseAnalysisPortfolioBucket pSource) {
689         /* Access the securities */
690         final MoneyWiseAnalysisPortfolioCashBucket myCash = pSource.getPortfolioCash();
691         final MoneyWiseAnalysisSecurityBucketList mySecurities = pSource.getSecurities();
692         final boolean isForeign = pSource.hasForeignCurrency();
693 
694         /* Create an embedded table */
695         final MetisHTMLTable myTable = theBuilder.createEmbeddedTable(pParent);
696 
697         /* If the portfolio cash is not idle */
698         if (!myCash.isIdle()) {
699             /* Access values */
700             final MoneyWiseAnalysisAccountValues myValues = myCash.getValues();
701             final MoneyWiseAnalysisAccountValues myBaseValues = myCash.getBaseValues();
702 
703             /* Access bucket name */
704             final String myName = pSource.getName();
705 
706             /* Create the detail row */
707             theBuilder.startRow(myTable);
708             theBuilder.makeFilterLinkCell(myTable, myName, TEXT_CASH);
709 
710             /* Handle foreign accounts */
711             if (isForeign) {
712                 if (myCash.isForeignCurrency()) {
713                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
714                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
715                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.FOREIGNVALUE));
716                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
717                 } else {
718                     theBuilder.makeStretchedValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
719                     theBuilder.makeStretchedValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
720                 }
721             } else {
722                 theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
723                 theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUATION));
724             }
725             theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisAccountAttr.VALUEDELTA));
726 
727             /* Record the filter */
728             setFilterForId(myName, pSource);
729         }
730 
731         /* Loop through the Security Buckets */
732         final Iterator<MoneyWiseAnalysisSecurityBucket> myIterator = mySecurities.iterator();
733         while (myIterator.hasNext()) {
734             final MoneyWiseAnalysisSecurityBucket myBucket = myIterator.next();
735 
736             /* Access bucket name */
737             final String myName = myBucket.getSecurityName();
738             String myFullName = myBucket.getDecoratedName();
739             myFullName = myFullName.replace(':', '-');
740 
741             /* Access values */
742             final MoneyWiseAnalysisSecurityValues myValues = myBucket.getValues();
743             final MoneyWiseAnalysisSecurityValues myBaseValues = myBucket.getBaseValues();
744 
745             /* Create the detail row */
746             theBuilder.startRow(myTable);
747             theBuilder.makeFilterLinkCell(myTable, myFullName, myName);
748 
749             /* Handle foreign accounts */
750             if (isForeign) {
751                 if (myBucket.isForeignCurrency()) {
752                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUE));
753                     theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
754                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUE));
755                     theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
756                 } else {
757                     theBuilder.makeStretchedValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
758                     theBuilder.makeStretchedValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
759                 }
760             } else {
761                 theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
762                 theBuilder.makeValueCell(myTable, myBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
763             }
764             theBuilder.makeValueCell(myTable, myValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA));
765 
766             /* Record the filter */
767             setFilterForId(myFullName, myBucket);
768         }
769 
770         /* Return the table */
771         return myTable;
772     }
773 
774     @Override
775     public MoneyWiseAnalysisFilter<?, ?> processFilter(final Object pSource) {
776         /* If this is a DepositBucket */
777         if (pSource instanceof MoneyWiseAnalysisDepositBucket mySource) {
778             /* Create the new filter */
779             return new MoneyWiseAnalysisDepositFilter(mySource);
780         }
781         /* If this is a CashBucket */
782         if (pSource instanceof MoneyWiseAnalysisCashBucket mySource) {
783             /* Create the new filter */
784             return new MoneyWiseAnalysisCashFilter(mySource);
785         }
786         /* If this is a LoanBucket */
787         if (pSource instanceof MoneyWiseAnalysisLoanBucket mySource) {
788             /* Create the new filter */
789             return new MoneyWiseAnalysisLoanFilter(mySource);
790         }
791         /* If this is a SecurityBucket */
792         if (pSource instanceof MoneyWiseAnalysisSecurityBucket mySource) {
793             /* Create the new filter */
794             return new MoneyWiseAnalysisSecurityFilter(mySource);
795         }
796         /* If this is a PortfolioBucket */
797         if (pSource instanceof MoneyWiseAnalysisPortfolioBucket mySource) {
798             /* Create the new filter */
799             return new MoneyWiseAnalysisPortfolioCashFilter(mySource);
800         }
801         return null;
802     }
803 }