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