/* * Copyright (c) 2004-2011 Marco Maccaferri and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marco Maccaferri - initial API and implementation */ package org.eclipsetrader.core.charts; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.eclipse.core.runtime.IAdaptable; import org.eclipsetrader.core.feed.IOHLC; /** * Default implementation of a data series. * * @since 1.0 */ public class DataSeries implements IDataSeries { private final String name; private final IAdaptable[] values; private IAdaptable first; private IAdaptable last; private IAdaptable highest; private IAdaptable lowest; private IDataSeries[] childrens; private boolean highestOverride = false; private boolean lowestOverride = false; private class RangeVisitor implements IDataSeriesVisitor { private Double lowestValue; private Double highestValue; private Date firstValue; private Date lastValue; public RangeVisitor() { } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeriesVisitor#visit(org.eclipsetrader.charts.core.IDataSeries) */ @Override public boolean visit(IDataSeries data) { for (IAdaptable v : data.getValues()) { IOHLC ohlc = (IOHLC) v.getAdapter(IOHLC.class); if (ohlc != null) { updateHighestLowest(ohlc.getLow() != null ? ohlc.getLow() : ohlc.getClose(), v); updateHighestLowest(ohlc.getHigh() != null ? ohlc.getHigh() : ohlc.getClose(), v); if (ohlc.getDate() != null) { updateFirstLast(ohlc.getDate(), v); } } else { Number value = (Number) v.getAdapter(Number.class); updateHighestLowest(value, v); Date date = (Date) v.getAdapter(Date.class); if (date != null) { updateFirstLast(date, v); } } } if (data instanceof DataSeries) { if (((DataSeries) data).highestOverride) { highest = data.getHighest(); } if (((DataSeries) data).lowestOverride) { lowest = data.getLowest(); } } return true; } private void updateHighestLowest(Number value, IAdaptable reference) { if (lowestValue == null || value.doubleValue() < lowestValue) { lowestValue = value.doubleValue(); lowest = reference; } if (highestValue == null || value.doubleValue() > highestValue) { highestValue = value.doubleValue(); highest = reference; } } private void updateFirstLast(Date date, IAdaptable reference) { if (firstValue == null || date.before(firstValue)) { firstValue = date; first = reference; } if (lastValue == null || date.after(lastValue)) { lastValue = date; last = reference; } } } public DataSeries(String name, IAdaptable[] values) { this.name = name; this.values = values; accept(new RangeVisitor()); } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getName() */ @Override public String getName() { return name; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getFirst() */ @Override public IAdaptable getFirst() { return first; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getLast() */ @Override public IAdaptable getLast() { return last; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getHighest() */ @Override public IAdaptable getHighest() { return highest; } public void setHighest(IAdaptable highest) { this.highest = highest; this.highestOverride = true; } protected boolean isHighestOverride() { return highestOverride; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getLowest() */ @Override public IAdaptable getLowest() { return lowest; } public void setLowest(IAdaptable lowest) { this.lowest = lowest; this.lowestOverride = true; } protected boolean isLowestOverride() { return lowestOverride; } /* (non-Javadoc) * @see org.eclipsetrader.core.charts.IDataSeries#size() */ @Override public int size() { return values.length; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getValues() */ @Override public IAdaptable[] getValues() { return values; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getSeries(org.eclipse.core.runtime.IAdaptable, org.eclipse.core.runtime.IAdaptable) */ @Override public IDataSeries getSeries(IAdaptable first, IAdaptable last) { DataSeries series = new DataSeries(getName(), getSubset(first, last)); if (highestOverride) { series.setHighest(getHighest()); } if (lowestOverride) { series.setLowest(getLowest()); } return series; } protected IAdaptable[] getSubset(IAdaptable first, IAdaptable last) { Date firstValue = first != null ? (Date) first.getAdapter(Date.class) : null; Date lastValue = last != null ? (Date) last.getAdapter(Date.class) : null; List<IAdaptable> list = new ArrayList<IAdaptable>(values.length); for (int i = 0; i < values.length; i++) { Date date = (Date) values[i].getAdapter(Date.class); if ((firstValue == null || !date.before(firstValue)) && (lastValue == null || !date.after(lastValue))) { list.add(values[i]); } } return list.toArray(new IAdaptable[list.size()]); } /* (non-Javadoc) * @see org.eclipsetrader.core.charts.IDataSeries#cross(org.eclipsetrader.core.charts.IDataSeries, org.eclipse.core.runtime.IAdaptable) */ @Override public int cross(IDataSeries series, IAdaptable value) { if (values.length <= 1 || series.size() <= 1) { return NONE; } int index = indexOf(this, value); if (index <= 0) { return NONE; } int otherIndex = indexOf(series, value); if (otherIndex <= 0) { return NONE; } Number ourValue = (Number) values[index - 1].getAdapter(Number.class); Number ourNextValue = (Number) values[index].getAdapter(Number.class); Number otherValue = (Number) series.getValues()[otherIndex - 1].getAdapter(Number.class); Number otherNextValue = (Number) series.getValues()[otherIndex].getAdapter(Number.class); if (ourValue.doubleValue() < otherValue.doubleValue() && ourNextValue.doubleValue() > otherNextValue.doubleValue()) { return ABOVE; } if (ourValue.doubleValue() > otherValue.doubleValue() && ourNextValue.doubleValue() < otherNextValue.doubleValue()) { return BELOW; } return NONE; } protected int indexOf(IDataSeries series, IAdaptable value) { IAdaptable[] values = series.getValues(); Date valueDate = (Date) value.getAdapter(Date.class); for (int i = 0; i < values.length; i++) { if (values[i].equals(value)) { return i; } Date date = (Date) values[i].getAdapter(Date.class); if (date != null && date.equals(valueDate)) { return i; } } return -1; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#getChildren() */ @Override public IDataSeries[] getChildren() { return childrens; } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#setChildren(org.eclipsetrader.charts.core.IDataSeries[]) */ @Override public void setChildren(IDataSeries[] childrens) { this.childrens = childrens; first = null; last = null; highest = null; lowest = null; accept(new RangeVisitor()); } /* (non-Javadoc) * @see org.eclipsetrader.charts.core.IDataSeries#accept(org.eclipsetrader.charts.core.IDataSeriesVisitor) */ @Override public void accept(IDataSeriesVisitor visitor) { if (visitor.visit(this)) { if (childrens != null) { for (int i = 0; i < childrens.length; i++) { childrens[i].accept(visitor); } } } } }