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