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