package org.marketcetera.core.position.impl;
import java.math.BigDecimal;
import org.apache.commons.lang.Validate;
import org.marketcetera.core.position.PositionMetrics;
import org.marketcetera.core.position.PositionRow;
import org.marketcetera.util.misc.ClassVersion;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;
/* $License$ */
/**
* This class maintains a summary position row based on its child positions.
*
* @author <a href="mailto:will@marketcetera.com">Will Horn</a>
* @version $Id: SummaryRowUpdater.java 16154 2012-07-14 16:34:05Z colin $
* @since 1.5.0
*/
@ClassVersion("$Id: SummaryRowUpdater.java 16154 2012-07-14 16:34:05Z colin $")
public class SummaryRowUpdater {
private final EventList<PositionRow> mChildren;
private final PositionRowImpl mPositionRow;
private final ListEventListener<PositionRow> listChangeListener;
/**
* Constructor.
*
* @param summary
* the summary row to be updated, must have a child list
* @throws IllegalArgumentException
* if summary is null or summary.getChildren() is null
*/
public SummaryRowUpdater(PositionRowImpl summary) {
Validate.notNull(summary);
Validate.notNull(summary.getChildren());
mChildren = summary.getChildren();
mPositionRow = summary;
listChangeListener = new ListEventListener<PositionRow>() {
@Override
public void listChanged(ListEvent<PositionRow> listChanges) {
SummaryRowUpdater.this.listChanged(listChanges);
}
};
recalculate();
mChildren.addListEventListener(listChangeListener);
}
/**
* Returns the dynamically updated summary row.
*
* @return the dynamically updated summary row
*/
public PositionRow getSummary() {
return mPositionRow;
}
/**
* Cleanup this object
*/
public void dispose() {
mChildren.removeListEventListener(listChangeListener);
}
private void listChanged(ListEvent<PositionRow> listChanges) {
if (listChanges.getSourceList() != mChildren) {
throw new IllegalStateException();
}
while (listChanges.next()) {
final int changeIndex = listChanges.getIndex();
final int changeType = listChanges.getType();
if (changeType == ListEvent.INSERT) {
// we can optimize on insert
PositionRow row = mChildren.get(changeIndex);
mPositionRow.setPositionMetrics(add(mPositionRow.getPositionMetrics(), row
.getPositionMetrics()));
} else {
// recompute summary from scratch
recalculate();
}
}
}
private void recalculate() {
PositionMetrics metrics = new PositionMetricsImpl(BigDecimal.ZERO, BigDecimal.ZERO,
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
for (PositionRow row : mChildren) {
metrics = add(metrics, row.getPositionMetrics());
}
mPositionRow.setPositionMetrics(metrics);
}
private PositionMetrics add(PositionMetrics current, PositionMetrics augend) {
BigDecimal incomingPosition = add(current.getIncomingPosition(), augend
.getIncomingPosition());
BigDecimal position = add(current.getPosition(), augend.getPosition());
BigDecimal positionPL = add(current.getPositionPL(), augend.getPositionPL());
BigDecimal tradingPL = add(current.getTradingPL(), augend.getTradingPL());
BigDecimal realizedPL = add(current.getRealizedPL(), augend.getRealizedPL());
BigDecimal unrealizedPL = add(current.getUnrealizedPL(), augend.getUnrealizedPL());
BigDecimal totalPL = add(current.getTotalPL(), augend.getTotalPL());
return new PositionMetricsImpl(incomingPosition, position, positionPL, tradingPL,
realizedPL, unrealizedPL, totalPL);
}
private BigDecimal add(BigDecimal current, BigDecimal augend) {
// if either is null (unknown), the result is also unknown
return current == null || augend == null ? null : current.add(augend);
}
}