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.OceanusDecimal;
21  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
22  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
23  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
24  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
25  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
26  import io.github.tonywasher.joceanus.metis.report.MetisReportBase;
27  import io.github.tonywasher.joceanus.metis.report.MetisReportHTMLBuilder;
28  import io.github.tonywasher.joceanus.metis.report.MetisReportHTMLBuilder.MetisHTMLTable;
29  import io.github.tonywasher.joceanus.metis.report.MetisReportManager;
30  import io.github.tonywasher.joceanus.metis.report.MetisReportReferenceManager.DelayedTable;
31  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
32  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
33  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransAsset;
34  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction;
35  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction.MoneyWiseTransactionList;
36  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransCategoryClass;
37  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysis;
38  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisSecurityBucket;
39  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisSecurityAttr;
40  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisSecurityValues;
41  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter;
42  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseCashType;
43  import org.w3c.dom.Document;
44  import org.w3c.dom.Element;
45  
46  import java.util.Iterator;
47  
48  /**
49   * CapitalGains report builder.
50   */
51  public class MoneyWiseReportCapitalGains
52          extends MetisReportBase<MoneyWiseAnalysis, MoneyWiseAnalysisFilter<?, ?>> {
53      /**
54       * The Title text.
55       */
56      private static final String TEXT_TITLE = MoneyWiseReportResource.CAPITALGAINS_TITLE.getValue();
57  
58      /**
59       * HTML builder.
60       */
61      private final MetisReportHTMLBuilder theBuilder;
62  
63      /**
64       * The Formatter.
65       */
66      private final OceanusDataFormatter theFormatter;
67  
68      /**
69       * The string builder.
70       */
71      private final StringBuilder theStringBuilder;
72  
73      /**
74       * The source SecurityBucket.
75       */
76      private MoneyWiseAnalysisSecurityBucket theSecurity;
77  
78      /**
79       * The transactions.
80       */
81      private MoneyWiseTransactionList theTransactions;
82  
83      /**
84       * The EndDate.
85       */
86      private OceanusDate theEndDate;
87  
88      /**
89       * The table.
90       */
91      private MetisHTMLTable theTable;
92  
93      /**
94       * The attribute table.
95       */
96      private MetisHTMLTable theAttrTable;
97  
98      /**
99       * Constructor.
100      *
101      * @param pManager the Report Manager
102      */
103     protected MoneyWiseReportCapitalGains(final MetisReportManager<MoneyWiseAnalysisFilter<?, ?>> pManager) {
104         /* Access underlying utilities */
105         theBuilder = pManager.getBuilder();
106         theFormatter = theBuilder.getDataFormatter();
107         theStringBuilder = new StringBuilder();
108     }
109 
110     /**
111      * Set the security bucket.
112      *
113      * @param pSecurity the security bucket
114      */
115     protected void setSecurity(final MoneyWiseAnalysisSecurityBucket pSecurity) {
116         theSecurity = pSecurity;
117     }
118 
119     @Override
120     public Document createReport(final MoneyWiseAnalysis pAnalysis) {
121         /* Access the securities and the date */
122         theTransactions = pAnalysis.getEditSet().getDataList(MoneyWiseBasicDataType.TRANSACTION, MoneyWiseTransactionList.class);
123         theEndDate = pAnalysis.getDateRange().getEnd();
124 
125         /* Start the report */
126         final Element myBody = theBuilder.startReport();
127         theBuilder.makeTitle(myBody, TEXT_TITLE, theFormatter.formatObject(theEndDate));
128         theBuilder.makeSubTitle(myBody, theSecurity.getDecoratedName());
129 
130         /* Initialise the table */
131         theTable = theBuilder.startTable(myBody);
132         theBuilder.startHdrRow(theTable);
133         theBuilder.makeTitleCell(theTable, MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE.getValue());
134         theBuilder.makeTitleCell(theTable, MoneyWiseBasicDataType.TRANSACTION.getItemName());
135 
136         /* Format the history */
137         formatHistory();
138 
139         /* Return the document */
140         return theBuilder.getDocument();
141     }
142 
143     /**
144      * format the cost history.
145      */
146     private void formatHistory() {
147         /* Loop through the transactions */
148         final Iterator<MoneyWiseTransaction> myIterator = theTransactions.iterator();
149         while (myIterator.hasNext()) {
150             final MoneyWiseTransaction myTrans = myIterator.next();
151 
152             /* Check for End of report */
153             if (theEndDate != null
154                     && theEndDate.compareTo(myTrans.getDate()) < 0) {
155                 break;
156             }
157 
158             /* If the transaction relates to the security */
159             final MoneyWiseAnalysisSecurityValues myValues = theSecurity.getValuesForTransaction(myTrans);
160             if (myValues != null) {
161                 /* Format the transaction */
162                 formatTransaction(myTrans, myValues);
163 
164                 /* If we have an attribute table */
165                 if (theAttrTable != null) {
166                     /* Embed the table correctly and reset the indicator */
167                     theBuilder.embedTable(theAttrTable);
168                     theAttrTable = null;
169                 }
170             }
171         }
172     }
173 
174     /**
175      * Format the details.
176      *
177      * @param pTrans  the transaction
178      * @param pValues the values for the transaction
179      */
180     private void formatTransaction(final MoneyWiseTransaction pTrans,
181                                    final MoneyWiseAnalysisSecurityValues pValues) {
182         /* Switch on the class */
183         switch (pTrans.getCategoryClass()) {
184             case TRANSFER:
185             case STOCKRIGHTSISSUE:
186             case INHERITED:
187                 formatTransfer(pTrans, pValues);
188                 break;
189             case SECURITYREPLACE:
190             case STOCKTAKEOVER:
191                 formatStockTakeOver(pTrans, pValues);
192                 break;
193             case STOCKDEMERGER:
194                 formatStockDeMerger(pTrans, pValues);
195                 break;
196             case STOCKSPLIT:
197             case UNITSADJUST:
198                 formatUnitsAdjust(pTrans, pValues);
199                 break;
200             case DIVIDEND:
201                 formatDividend(pTrans, pValues);
202                 break;
203             case PORTFOLIOXFER:
204                 formatPortfolioXfer(pTrans, pValues);
205                 break;
206             default:
207                 break;
208         }
209     }
210 
211     /**
212      * Format basic details of a transaction.
213      *
214      * @param pTrans the transaction
215      */
216     private void formatBasicTransaction(final MoneyWiseTransaction pTrans) {
217         /* Create the transaction row */
218         theBuilder.startRow(theTable);
219         theBuilder.makeValueCell(theTable, pTrans.getDate());
220         theBuilder.makeValueCell(theTable, pTrans);
221     }
222 
223     /**
224      * Check whether this is a debit transaction for the security.
225      *
226      * @param pTrans the transaction
227      * @return true/false
228      */
229     private boolean isDebit(final MoneyWiseTransaction pTrans) {
230         final MoneyWiseTransAsset myDebit = pTrans.getDirection().isTo()
231                 ? pTrans.getAccount()
232                 : pTrans.getPartner();
233         return myDebit.equals(theSecurity.getSecurityHolding());
234     }
235 
236     /**
237      * Check whether this is a credit transaction for the security.
238      *
239      * @param pTrans the transaction
240      * @return true/false
241      */
242     private boolean isCredit(final MoneyWiseTransaction pTrans) {
243         final MoneyWiseTransAsset myCredit = pTrans.getDirection().isFrom()
244                 ? pTrans.getAccount()
245                 : pTrans.getPartner();
246         return myCredit.equals(theSecurity.getSecurityHolding());
247     }
248 
249     /**
250      * Ensure the attribute table.
251      */
252     private void ensureAttrTable() {
253         /* If we do not have a current attribute table */
254         if (theAttrTable == null) {
255             /* Create a new table */
256             theAttrTable = theBuilder.createEmbeddedTable(theTable);
257         }
258     }
259 
260     /**
261      * Format a value.
262      *
263      * @param pAttr  the attribute
264      * @param pValue the value
265      */
266     private void formatValue(final MoneyWiseAnalysisSecurityAttr pAttr,
267                              final Object pValue) {
268         /* Ensure that we have an attribute table */
269         ensureAttrTable();
270 
271         /* Format the attribute */
272         theBuilder.startRow(theAttrTable);
273         theBuilder.makeValueCell(theAttrTable, pAttr);
274         theBuilder.makeStretchedValueCell(theAttrTable, pValue);
275     }
276 
277     /**
278      * Format a division.
279      *
280      * @param pAttr      the attribute
281      * @param pValue     the value
282      * @param pNumerator the numerator
283      * @param pDivisor   the divisor
284      */
285     private void formatDivision(final MoneyWiseAnalysisSecurityAttr pAttr,
286                                 final Object pValue,
287                                 final OceanusDecimal pNumerator,
288                                 final OceanusDecimal pDivisor) {
289         /* Ensure that we have an attribute table */
290         ensureAttrTable();
291 
292         /* Format the attribute */
293         theBuilder.startRow(theAttrTable);
294         theBuilder.makeValueCell(theAttrTable, pAttr);
295         theBuilder.makeValueCell(theAttrTable, formatDivision(pNumerator, pDivisor));
296         theBuilder.makeValueCell(theAttrTable, pValue);
297     }
298 
299     /**
300      * Format a division.
301      *
302      * @param pNumerator the numerator
303      * @param pDivisor   the divisor
304      * @return the formatted division
305      */
306     private String formatDivision(final OceanusDecimal pNumerator,
307                                   final OceanusDecimal pDivisor) {
308         return formatCombination(pNumerator, pDivisor, '/');
309     }
310 
311     /**
312      * Format a valuation.
313      *
314      * @param pAttr        the attribute
315      * @param pValue       the value
316      * @param pUnits       the units
317      * @param pPrice       the price
318      * @param pXchangeRate the exchange rate
319      */
320     private void formatValuation(final MoneyWiseAnalysisSecurityAttr pAttr,
321                                  final Object pValue,
322                                  final OceanusUnits pUnits,
323                                  final OceanusPrice pPrice,
324                                  final OceanusRatio pXchangeRate) {
325         /* Ensure that we have an attribute table */
326         ensureAttrTable();
327 
328         /* Format the attribute */
329         theBuilder.startRow(theAttrTable);
330         theBuilder.makeValueCell(theAttrTable, pAttr);
331         theBuilder.makeValueCell(theAttrTable, formatValuation(pUnits, pPrice, pXchangeRate));
332         theBuilder.makeValueCell(theAttrTable, pValue);
333     }
334 
335     /**
336      * Format a valuation.
337      *
338      * @param pUnits       the units
339      * @param pPrice       the price
340      * @param pXchangeRate the exchange rate
341      * @return the formatted valuation
342      */
343     private String formatValuation(final OceanusUnits pUnits,
344                                    final OceanusPrice pPrice,
345                                    final OceanusRatio pXchangeRate) {
346         theStringBuilder.setLength(0);
347         theStringBuilder.append(theFormatter.formatObject(pUnits));
348         theStringBuilder.append('@');
349         theStringBuilder.append(theFormatter.formatObject(pPrice));
350         if (pXchangeRate != null) {
351             theStringBuilder.append('/');
352             theStringBuilder.append(theFormatter.formatObject(pXchangeRate));
353         }
354         return theStringBuilder.toString();
355     }
356 
357     /**
358      * Format a multiplication.
359      *
360      * @param pAttr   the attribute
361      * @param pValue  the value
362      * @param pFirst  the first item
363      * @param pSecond the second item
364      */
365     private void formatMultiplication(final MoneyWiseAnalysisSecurityAttr pAttr,
366                                       final Object pValue,
367                                       final OceanusDecimal pFirst,
368                                       final OceanusDecimal pSecond) {
369         /* Ensure that we have an attribute table */
370         ensureAttrTable();
371 
372         /* Format the attribute */
373         theBuilder.startRow(theAttrTable);
374         theBuilder.makeValueCell(theAttrTable, pAttr);
375         theBuilder.makeValueCell(theAttrTable, formatMultiplication(pFirst, pSecond));
376         theBuilder.makeValueCell(theAttrTable, pValue);
377     }
378 
379     /**
380      * Format a multiplication.
381      *
382      * @param pFirst  the first item
383      * @param pSecond the second item
384      * @return the formatted multiplication
385      */
386     private String formatMultiplication(final OceanusDecimal pFirst,
387                                         final OceanusDecimal pSecond) {
388         return formatCombination(pFirst, pSecond, '*');
389     }
390 
391     /**
392      * Format an addition.
393      *
394      * @param pAttr   the attribute
395      * @param pValue  the value
396      * @param pFirst  the first item
397      * @param pSecond the second item
398      */
399     private void formatAddition(final MoneyWiseAnalysisSecurityAttr pAttr,
400                                 final Object pValue,
401                                 final OceanusDecimal pFirst,
402                                 final OceanusDecimal pSecond) {
403         /* Ensure that we have an attribute table */
404         ensureAttrTable();
405 
406         /* Format the attribute */
407         theBuilder.startRow(theAttrTable);
408         theBuilder.makeValueCell(theAttrTable, pAttr);
409         theBuilder.makeValueCell(theAttrTable, formatAddition(pFirst, pSecond));
410         theBuilder.makeValueCell(theAttrTable, pValue);
411     }
412 
413     /**
414      * Format an addition.
415      *
416      * @param pFirst  the first item
417      * @param pSecond the second item
418      * @return the formatted addition
419      */
420     private String formatAddition(final OceanusDecimal pFirst,
421                                   final OceanusDecimal pSecond) {
422         return formatCombination(pFirst, pSecond, '+');
423     }
424 
425     /**
426      * Format a subtraction.
427      *
428      * @param pAttr   the attribute
429      * @param pValue  the value
430      * @param pFirst  the first item
431      * @param pSecond the second item
432      */
433     private void formatSubtraction(final MoneyWiseAnalysisSecurityAttr pAttr,
434                                    final Object pValue,
435                                    final OceanusDecimal pFirst,
436                                    final OceanusDecimal pSecond) {
437         /* Ensure that we have an attribute table */
438         ensureAttrTable();
439 
440         /* Format the attribute */
441         theBuilder.startRow(theAttrTable);
442         theBuilder.makeValueCell(theAttrTable, pAttr);
443         theBuilder.makeValueCell(theAttrTable, formatSubtraction(pFirst, pSecond));
444         theBuilder.makeValueCell(theAttrTable, pValue);
445     }
446 
447     /**
448      * Format a subtraction.
449      *
450      * @param pFirst  the first item
451      * @param pSecond the second item
452      * @return the formatted subtraction
453      */
454     private String formatSubtraction(final OceanusDecimal pFirst,
455                                      final OceanusDecimal pSecond) {
456         return formatCombination(pFirst, pSecond, '-');
457     }
458 
459     /**
460      * Format a combination.
461      *
462      * @param pFirst  the first item
463      * @param pSecond the second item
464      * @param pSymbol the symbol
465      * @return the formatted combination
466      */
467     private String formatCombination(final OceanusDecimal pFirst,
468                                      final OceanusDecimal pSecond,
469                                      final char pSymbol) {
470         theStringBuilder.setLength(0);
471         theStringBuilder.append(theFormatter.formatObject(pFirst));
472         theStringBuilder.append(pSymbol);
473         theStringBuilder.append(theFormatter.formatObject(pSecond));
474         return theStringBuilder.toString();
475     }
476 
477     /**
478      * Format a Transfer.
479      *
480      * @param pTrans  the transaction
481      * @param pValues the values for the transaction
482      */
483     private void formatTransfer(final MoneyWiseTransaction pTrans,
484                                 final MoneyWiseAnalysisSecurityValues pValues) {
485         /* Format the basic transaction */
486         formatBasicTransaction(pTrans);
487 
488         /* Split workings for transfer in/out */
489         if (isDebit(pTrans)) {
490             formatTransferOut(pTrans, pValues);
491         } else {
492             formatTransferIn(pTrans, pValues);
493         }
494     }
495 
496     /**
497      * Format a Dividend.
498      *
499      * @param pTrans  the transaction
500      * @param pValues the values for the transaction
501      */
502     private void formatDividend(final MoneyWiseTransaction pTrans,
503                                 final MoneyWiseAnalysisSecurityValues pValues) {
504         /* If this is a dividend re-investment */
505         if (isCredit(pTrans)) {
506             /* Format the basic transaction */
507             formatBasicTransaction(pTrans);
508 
509             /* Deal as investment */
510             formatTransferIn(pTrans, pValues);
511         }
512     }
513 
514     /**
515      * Format transfer money in.
516      *
517      * @param pTrans  the transaction
518      * @param pValues the values for the transaction
519      */
520     private void formatTransferIn(final MoneyWiseTransaction pTrans,
521                                   final MoneyWiseAnalysisSecurityValues pValues) {
522 
523         /* Access interesting values */
524         final OceanusUnits myUnits = pValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
525         OceanusUnits myDeltaUnits = pTrans.getAccountDeltaUnits();
526         if (myDeltaUnits == null) {
527             myDeltaUnits = pTrans.getPartnerDeltaUnits();
528         }
529         final OceanusMoney myCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
530         final OceanusMoney myAmount = theSecurity.getMoneyDeltaForTransaction(pTrans, MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
531         final OceanusPrice myPrice = pValues.getPriceValue(MoneyWiseAnalysisSecurityAttr.PRICE);
532         final OceanusRatio myXchangeRate = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE);
533 
534         /* Obtain the original units/cost */
535         final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
536         final OceanusUnits myOriginalUnits = myPreviousValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
537         final OceanusMoney myOriginalCost = myPreviousValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
538 
539         /* If this is an inheritance */
540         if (pTrans.isCategoryClass(MoneyWiseTransCategoryClass.INHERITED)) {
541             formatValuation(MoneyWiseAnalysisSecurityAttr.INVESTED, myAmount, myDeltaUnits, myPrice, myXchangeRate);
542         } else {
543             formatValue(MoneyWiseAnalysisSecurityAttr.INVESTED, myAmount);
544         }
545 
546         /* Record the details */
547         if (myDeltaUnits != null) {
548             formatAddition(MoneyWiseAnalysisSecurityAttr.UNITS, myUnits, myOriginalUnits, myDeltaUnits);
549         }
550         formatAddition(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myCost, myOriginalCost, myAmount);
551     }
552 
553     /**
554      * Format transfer money out.
555      *
556      * @param pTrans  the transaction
557      * @param pValues the values for the transaction
558      */
559     private void formatTransferOut(final MoneyWiseTransaction pTrans,
560                                    final MoneyWiseAnalysisSecurityValues pValues) {
561         /* Access interesting values */
562         final OceanusMoney myGain = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.CAPITALGAIN);
563         final OceanusMoney myAllowedCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.ALLOWEDCOST);
564         final OceanusRatio myCostDilution = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.COSTDILUTION);
565         final OceanusMoney myTotalGains = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.REALISEDGAINS);
566         final OceanusMoney myCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
567         final OceanusUnits myUnits = pValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
568         final OceanusMoney myCash = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RETURNEDCASH);
569         final OceanusMoney myConsideration = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.CONSIDERATION);
570         final MoneyWiseCashType myCashType = pValues.getEnumValue(MoneyWiseAnalysisSecurityAttr.CASHTYPE, MoneyWiseCashType.class);
571 
572         /* Obtain the original values */
573         final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
574         final OceanusMoney myOriginalCost = myPreviousValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
575         final OceanusUnits myOriginalUnits = myPreviousValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
576 
577         /* Obtain the delta in units/money */
578         OceanusUnits myDeltaUnits = theSecurity.getUnitsDeltaForTransaction(pTrans, MoneyWiseAnalysisSecurityAttr.UNITS);
579         final OceanusMoney myAmount = new OceanusMoney(myCash);
580         myAmount.negate();
581 
582         /* Report the returned cash */
583         formatValue(MoneyWiseAnalysisSecurityAttr.RETURNEDCASH, myCash);
584         if (myCashType != null) {
585             formatValue(MoneyWiseAnalysisSecurityAttr.CASHTYPE, myCashType);
586         }
587 
588         /* If we have changed the number of units */
589         if (myDeltaUnits.isNonZero()) {
590             /* Obtain the various values */
591             myDeltaUnits = new OceanusUnits(myDeltaUnits);
592             myDeltaUnits.negate();
593 
594             /* Format the units */
595             formatSubtraction(MoneyWiseAnalysisSecurityAttr.UNITS, myUnits, myOriginalUnits, myDeltaUnits);
596 
597             /* Format the dilution */
598             formatDivision(MoneyWiseAnalysisSecurityAttr.COSTDILUTION, myCostDilution, myUnits, myOriginalUnits);
599 
600             /* Else we need to format the cost dilution */
601         } else if (myConsideration != null) {
602             /* Format the valuation */
603             final OceanusMoney myValuation = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION);
604             final OceanusPrice myPrice = pValues.getPriceValue(MoneyWiseAnalysisSecurityAttr.PRICE);
605             final OceanusRatio myXchangeRate = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE);
606             formatValuation(MoneyWiseAnalysisSecurityAttr.VALUATION, myValuation, myUnits, myPrice, myXchangeRate);
607             formatAddition(MoneyWiseAnalysisSecurityAttr.CONSIDERATION, myConsideration, myCash, myValuation);
608 
609             /* Format the dilution */
610             formatDivision(MoneyWiseAnalysisSecurityAttr.COSTDILUTION, myCostDilution, myValuation, myConsideration);
611         }
612 
613         /* Record the details */
614         if (myCostDilution != null) {
615             formatMultiplication(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myCost, myOriginalCost, myCostDilution);
616             formatSubtraction(MoneyWiseAnalysisSecurityAttr.ALLOWEDCOST, myAllowedCost, myOriginalCost, myCost);
617         } else {
618             formatValue(MoneyWiseAnalysisSecurityAttr.ALLOWEDCOST, myAllowedCost);
619             formatSubtraction(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myCost, myOriginalCost, myAllowedCost);
620         }
621 
622         /* Record the gains allocation */
623         if (myGain != null) {
624             formatSubtraction(MoneyWiseAnalysisSecurityAttr.CAPITALGAIN, myGain, myCash, myAllowedCost);
625             formatValue(MoneyWiseAnalysisSecurityAttr.REALISEDGAINS, myTotalGains);
626         }
627     }
628 
629     /**
630      * Format a Units Adjustment.
631      *
632      * @param pTrans  the transaction
633      * @param pValues the values for the transaction
634      */
635     private void formatUnitsAdjust(final MoneyWiseTransaction pTrans,
636                                    final MoneyWiseAnalysisSecurityValues pValues) {
637         /* Format the basic transaction */
638         formatBasicTransaction(pTrans);
639 
640         /* Access interesting values */
641         final OceanusUnits myUnits = pValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
642         OceanusUnits myDeltaUnits = pTrans.getAccountDeltaUnits();
643 
644         /* Obtain the original units */
645         final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
646         final OceanusUnits myOriginalUnits = myPreviousValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
647 
648         /* Record the details */
649         if (myDeltaUnits.isPositive()) {
650             formatAddition(MoneyWiseAnalysisSecurityAttr.UNITS, myUnits, myOriginalUnits, myDeltaUnits);
651         } else {
652             myDeltaUnits = new OceanusUnits(myDeltaUnits);
653             myDeltaUnits.negate();
654             formatSubtraction(MoneyWiseAnalysisSecurityAttr.UNITS, myUnits, myOriginalUnits, myDeltaUnits);
655         }
656     }
657 
658     /**
659      * Format a Stock DeMerger.
660      *
661      * @param pTrans  the transaction
662      * @param pValues the values for the transaction
663      */
664     private void formatStockDeMerger(final MoneyWiseTransaction pTrans,
665                                      final MoneyWiseAnalysisSecurityValues pValues) {
666         /* Format the basic transaction */
667         formatBasicTransaction(pTrans);
668 
669         /* Split workings for credit and debit */
670         if (isDebit(pTrans)) {
671             formatDebitStockDeMerger(pTrans, pValues);
672         } else {
673             formatCreditStockDeMerger(pTrans, pValues);
674         }
675     }
676 
677     /**
678      * Format debit side of a Stock DeMerger.
679      *
680      * @param pTrans  the transaction
681      * @param pValues the values for the transaction
682      */
683     private void formatDebitStockDeMerger(final MoneyWiseTransaction pTrans,
684                                           final MoneyWiseAnalysisSecurityValues pValues) {
685         /* Access interesting values */
686         final OceanusRatio myCostDilution = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.COSTDILUTION);
687         final OceanusMoney myResidualCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
688         final OceanusMoney myXferredCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST);
689         OceanusUnits myDeltaUnits = theSecurity.getUnitsDeltaForTransaction(pTrans, MoneyWiseAnalysisSecurityAttr.UNITS);
690 
691         /* Check whether the units have changed */
692         final boolean isDeltaUnits = myDeltaUnits.isNonZero();
693 
694         /* Obtain the original cost */
695         final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
696         final OceanusMoney myOriginalCost = myPreviousValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
697 
698         /* If we have changed the number of units */
699         if (isDeltaUnits) {
700             /* Obtain the various values */
701             final OceanusUnits myOriginalUnits = myPreviousValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
702             final OceanusUnits myUnits = pValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
703             myDeltaUnits = new OceanusUnits(myDeltaUnits);
704             myDeltaUnits.negate();
705 
706             /* Format the units/dilution */
707             formatSubtraction(MoneyWiseAnalysisSecurityAttr.UNITS, myUnits, myOriginalUnits, myDeltaUnits);
708             formatDivision(MoneyWiseAnalysisSecurityAttr.COSTDILUTION, myCostDilution, myUnits, myOriginalUnits);
709 
710             /* else just report the dilution */
711         } else {
712             formatValue(MoneyWiseAnalysisSecurityAttr.COSTDILUTION, myCostDilution);
713         }
714 
715         /* Record the details */
716         formatMultiplication(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myResidualCost, myOriginalCost, myCostDilution);
717         formatSubtraction(MoneyWiseAnalysisSecurityAttr.XFERREDCOST, myXferredCost, myOriginalCost, myResidualCost);
718     }
719 
720     /**
721      * Format credit side of a Stock DeMerger.
722      *
723      * @param pTrans  the transaction
724      * @param pValues the values for the transaction
725      */
726     private void formatCreditStockDeMerger(final MoneyWiseTransaction pTrans,
727                                            final MoneyWiseAnalysisSecurityValues pValues) {
728         /* Access interesting values */
729         final OceanusMoney myResidualCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
730         final OceanusMoney myXferredCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST);
731         final OceanusMoney myValueXfer = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDVALUE);
732         final OceanusUnits myUnits = theSecurity.getUnitsDeltaForTransaction(pTrans, MoneyWiseAnalysisSecurityAttr.UNITS);
733         final OceanusPrice myPrice = pValues.getPriceValue(MoneyWiseAnalysisSecurityAttr.PRICE);
734         final OceanusRatio myXchangeRate = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE);
735 
736         /* Record the details */
737         formatValuation(MoneyWiseAnalysisSecurityAttr.XFERREDVALUE, myValueXfer, myUnits, myPrice, myXchangeRate);
738         formatValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST, myXferredCost);
739         formatValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myResidualCost);
740     }
741 
742     /**
743      * Format a Stock TakeOver.
744      *
745      * @param pTrans  the transaction
746      * @param pValues the values for the transaction
747      */
748     private void formatStockTakeOver(final MoneyWiseTransaction pTrans,
749                                      final MoneyWiseAnalysisSecurityValues pValues) {
750         /* Format the basic transaction */
751         formatBasicTransaction(pTrans);
752 
753         /* Split out Stock and Cash TakeOver */
754         final OceanusMoney myCash = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RETURNEDCASH);
755         if (myCash != null) {
756             formatStockAndCashTakeOver(pTrans, pValues, myCash);
757 
758             /* Split workings for credit and debit */
759         } else if (isDebit(pTrans)) {
760             /* Record the transfer of cost for simple replacement takeOver */
761             final OceanusMoney myCostXfer = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST);
762             formatValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST, myCostXfer);
763         } else {
764             formatCreditStockTakeOver(pTrans, pValues);
765         }
766     }
767 
768     /**
769      * Format a StockAndCash TakeOver.
770      *
771      * @param pTrans  the transaction
772      * @param pValues the values for the transaction
773      * @param pCash   the cash consideration
774      */
775     private void formatStockAndCashTakeOver(final MoneyWiseTransaction pTrans,
776                                             final MoneyWiseAnalysisSecurityValues pValues,
777                                             final OceanusMoney pCash) {
778         /* Split workings for credit and debit */
779         if (isDebit(pTrans)) {
780             formatDebitStockAndCashTakeOver(pTrans, pValues, pCash);
781         } else {
782             formatCreditStockTakeOver(pTrans, pValues);
783         }
784     }
785 
786     /**
787      * Format debit side of a StockAndCash TakeOver.
788      *
789      * @param pTrans  the transaction
790      * @param pValues the values for the transaction
791      * @param pCash   the cash consideration
792      */
793     private void formatDebitStockAndCashTakeOver(final MoneyWiseTransaction pTrans,
794                                                  final MoneyWiseAnalysisSecurityValues pValues,
795                                                  final OceanusMoney pCash) {
796         /* Access interesting values */
797         final OceanusMoney myStock = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDVALUE);
798         final OceanusMoney myConsideration = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.CONSIDERATION);
799         final OceanusMoney myCostXfer = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST);
800         final OceanusRatio myCostDilution = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.COSTDILUTION);
801         final OceanusMoney myAllowedCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.ALLOWEDCOST);
802         final OceanusMoney myGain = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.CAPITALGAIN);
803         final OceanusMoney myTotalGains = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.REALISEDGAINS);
804         final MoneyWiseCashType myCashType = pValues.getEnumValue(MoneyWiseAnalysisSecurityAttr.CASHTYPE, MoneyWiseCashType.class);
805 
806         /* Record the calculation of total consideration */
807         formatValue(MoneyWiseAnalysisSecurityAttr.RETURNEDCASH, pCash);
808         formatValue(MoneyWiseAnalysisSecurityAttr.CASHTYPE, myCashType);
809         formatValue(MoneyWiseAnalysisSecurityAttr.XFERREDVALUE, myStock);
810         formatAddition(MoneyWiseAnalysisSecurityAttr.CONSIDERATION, myConsideration, pCash, myStock);
811 
812         /* Obtain the original cost */
813         final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
814         final OceanusMoney myOriginalCost = myPreviousValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
815 
816         /* Format the cost dilution */
817         if (myCostDilution != null) {
818             formatDivision(MoneyWiseAnalysisSecurityAttr.COSTDILUTION, myCostDilution, pCash, myConsideration);
819             formatMultiplication(MoneyWiseAnalysisSecurityAttr.ALLOWEDCOST, myAllowedCost, myOriginalCost, myCostDilution);
820         } else {
821             formatValue(MoneyWiseAnalysisSecurityAttr.ALLOWEDCOST, myAllowedCost);
822         }
823         formatSubtraction(MoneyWiseAnalysisSecurityAttr.XFERREDCOST, myCostXfer, myOriginalCost, myAllowedCost);
824 
825         /* Record the gains allocation */
826         if (myGain != null) {
827             formatSubtraction(MoneyWiseAnalysisSecurityAttr.CAPITALGAIN, myGain, pCash, myAllowedCost);
828             formatValue(MoneyWiseAnalysisSecurityAttr.REALISEDGAINS, myTotalGains);
829         }
830     }
831 
832     /**
833      * Format credit side of a StockAndCash TakeOver.
834      *
835      * @param pTrans  the transaction
836      * @param pValues the values for the transaction
837      */
838     private void formatCreditStockTakeOver(final MoneyWiseTransaction pTrans,
839                                            final MoneyWiseAnalysisSecurityValues pValues) {
840         /* Access interesting values */
841         final OceanusPrice myPrice = pValues.getPriceValue(MoneyWiseAnalysisSecurityAttr.PRICE);
842         final OceanusUnits myUnits = theSecurity.getUnitsDeltaForTransaction(pTrans, MoneyWiseAnalysisSecurityAttr.UNITS);
843         final OceanusMoney myValueXfer = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDVALUE);
844         final OceanusMoney myCostXfer = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST);
845         final OceanusMoney myResidualCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
846         final OceanusRatio myXchangeRate = pValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE);
847 
848         /* Detail the new units and cost */
849         final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
850         final OceanusUnits myNewUnits = pValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
851         final OceanusUnits myOriginalUnits = myPreviousValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
852         formatAddition(MoneyWiseAnalysisSecurityAttr.UNITS, myNewUnits, myOriginalUnits, myUnits);
853 
854         /* Record the transfer of value and cost */
855         formatValuation(MoneyWiseAnalysisSecurityAttr.XFERREDVALUE, myValueXfer, myUnits, myPrice, myXchangeRate);
856         formatValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST, myCostXfer);
857         formatValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myResidualCost);
858     }
859 
860     /**
861      * Format a Stock DeMerger.
862      *
863      * @param pTrans  the transaction
864      * @param pValues the values for the transaction
865      */
866     private void formatPortfolioXfer(final MoneyWiseTransaction pTrans,
867                                      final MoneyWiseAnalysisSecurityValues pValues) {
868         /* Format the basic transaction */
869         formatBasicTransaction(pTrans);
870 
871         /* Determine the direction of transfer */
872         final OceanusMoney myCostXfer = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST);
873         formatValue(MoneyWiseAnalysisSecurityAttr.XFERREDCOST, myCostXfer);
874 
875         final OceanusUnits myUnits = theSecurity.getUnitsDeltaForTransaction(pTrans, MoneyWiseAnalysisSecurityAttr.UNITS);
876         if (myUnits.isPositive()) {
877             /* Detail the new units and cost */
878             final MoneyWiseAnalysisSecurityValues myPreviousValues = theSecurity.getPreviousValuesForTransaction(pTrans);
879             final OceanusUnits myNewUnits = pValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
880             final OceanusUnits myOriginalUnits = myPreviousValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
881             formatAddition(MoneyWiseAnalysisSecurityAttr.UNITS, myNewUnits, myOriginalUnits, myUnits);
882             final OceanusMoney myCost = pValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
883             final OceanusMoney myOriginalCost = myPreviousValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST);
884             formatAddition(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myCost, myOriginalCost, myCostXfer);
885         }
886     }
887 
888     @Override
889     public MoneyWiseAnalysisFilter<?, ?> processFilter(final Object pSource) {
890         return null;
891     }
892 
893     @Override
894     public MetisHTMLTable createDelayedTable(final DelayedTable pTable) {
895         return null;
896     }
897 }