/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.core.historicaltimeseries;
import java.util.Stack;
import com.opengamma.core.historicaltimeseries.impl.SimpleHistoricalTimeSeries;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries;
/**
* Historical time series adjustment operations that can be string encoded.
*/
public abstract class HistoricalTimeSeriesAdjustment {
// TODO: review this -- something based on EL probably be better
protected HistoricalTimeSeriesAdjustment() {
}
public abstract LocalDateDoubleTimeSeries adjust(LocalDateDoubleTimeSeries timeSeries);
public abstract double adjust(double value);
public HistoricalTimeSeries adjust(final HistoricalTimeSeries timeSeries) {
return new SimpleHistoricalTimeSeries(timeSeries.getUniqueId(), adjust(timeSeries.getTimeSeries()));
}
/**
* The division operation. Every point in the time series is divided by an amount.
*/
public static class DivideBy extends HistoricalTimeSeriesAdjustment {
private final double _amountToDivideBy;
public DivideBy(final double amountToDivideBy) {
_amountToDivideBy = amountToDivideBy;
}
protected double getAmountToDivideBy() {
return _amountToDivideBy;
}
@Override
public LocalDateDoubleTimeSeries adjust(final LocalDateDoubleTimeSeries timeSeries) {
return (LocalDateDoubleTimeSeries) timeSeries.divide(getAmountToDivideBy());
}
@Override
public double adjust(final double value) {
return value / getAmountToDivideBy();
}
@Override
public String toString() {
return getAmountToDivideBy() + " /";
}
}
/**
* A subtraction operation. Every point in the time series is subtracted by an amount.
*/
public static class Subtract extends HistoricalTimeSeriesAdjustment {
private final double _amountToSubtract;
public Subtract(final double amountToSubtract) {
_amountToSubtract = amountToSubtract;
}
protected double getAmountToSubtract() {
return _amountToSubtract;
}
@Override
public LocalDateDoubleTimeSeries adjust(final LocalDateDoubleTimeSeries timeSeries) {
return (LocalDateDoubleTimeSeries) timeSeries.subtract(getAmountToSubtract());
}
@Override
public double adjust(final double value) {
return value - getAmountToSubtract();
}
@Override
public String toString() {
return getAmountToSubtract() + " -";
}
}
/**
* A sequence of two operations. The first is applied to a time series and the second applies to the resulting time series.
*/
public static final class Sequence extends HistoricalTimeSeriesAdjustment {
private final HistoricalTimeSeriesAdjustment _first;
private final HistoricalTimeSeriesAdjustment _second;
public Sequence(final HistoricalTimeSeriesAdjustment first, final HistoricalTimeSeriesAdjustment second) {
_first = first;
_second = second;
}
protected HistoricalTimeSeriesAdjustment getFirst() {
return _first;
}
protected HistoricalTimeSeriesAdjustment getSecond() {
return _second;
}
@Override
public LocalDateDoubleTimeSeries adjust(final LocalDateDoubleTimeSeries timeSeries) {
return getSecond().adjust(getFirst().adjust(timeSeries));
}
@Override
public double adjust(final double value) {
return getSecond().adjust(getFirst().adjust(value));
}
@Override
public String toString() {
return getFirst().toString() + " " + getSecond().toString();
}
}
/**
* A no-op. Every point in the time series is unchanged.
*/
public static final class NoOp extends HistoricalTimeSeriesAdjustment {
/**
* Singleton.
*/
public static final NoOp INSTANCE = new NoOp();
private NoOp() {
}
@Override
public LocalDateDoubleTimeSeries adjust(final LocalDateDoubleTimeSeries timeSeries) {
return timeSeries;
}
@Override
public HistoricalTimeSeries adjust(final HistoricalTimeSeries timeSeries) {
return timeSeries;
}
@Override
public double adjust(final double value) {
return value;
}
@Override
public String toString() {
return "";
}
}
/**
* Produces an instance based on the string representation returned by {@link #toString}. Strings are not intended to be human writable, but should be created by forming the adjustment objects and
* calling {@code toString} on them.
*
* @param str the string to parse, not null
* @return the adjustment instance, not null
*/
public static HistoricalTimeSeriesAdjustment parse(final String str) {
final String[] elements = str.split("\\s+");
final Stack<Object> stack = new Stack<Object>();
for (String element : elements) {
if ("/".equals(element)) {
stack.push(new DivideBy(Double.parseDouble((String) stack.pop())));
} else if ("-".equals(element)) {
stack.push(new Subtract(Double.parseDouble((String) stack.pop())));
} else if ("".equals(element)) {
stack.push(NoOp.INSTANCE);
} else {
stack.push(element);
}
}
while (stack.size() > 1) {
final HistoricalTimeSeriesAdjustment second = (HistoricalTimeSeriesAdjustment) stack.pop();
final HistoricalTimeSeriesAdjustment first = (HistoricalTimeSeriesAdjustment) stack.pop();
stack.push(new Sequence(first, second));
}
return (HistoricalTimeSeriesAdjustment) stack.pop();
}
/**
* Produces a string representation that can be parsed by {@link #parse}.
*
* @return the string
*/
@Override
public abstract String toString();
}