package org.chartsy.main.chart;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.chartsy.main.ChartFrame;
import org.chartsy.main.ChartFrameAdapter;
import org.chartsy.main.data.ChartData;
import org.chartsy.main.data.Dataset;
import org.chartsy.main.managers.DatasetUsage;
import org.chartsy.main.utils.Range;
import org.chartsy.main.utils.SerialVersion;
import org.chartsy.main.utils.XMLUtil;
import org.chartsy.main.utils.XMLUtil.XMLTemplate;
import org.openide.nodes.AbstractNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
*
* @author viorel.gheba
*/
public abstract class Indicator extends ChartFrameAdapter
implements Serializable, XMLTemplate
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
public static final int DEFAULT_HEIGHT = 150;
protected String datasetKey;
protected HashMap<String, Dataset> datasets;
protected boolean maximized = true;
private int maximizedHeight = DEFAULT_HEIGHT;
protected boolean active = true;
public Indicator()
{
datasets = new HashMap<String, Dataset>();
}
public void setMaximizedHeight(int height)
{
this.maximizedHeight = height;
}
public int getMaximizedHeight()
{
return this.maximizedHeight;
}
public String getFontHTML(Color color, String text)
{
String html = "<font color=\"" + Integer.toHexString(color.getRGB() & 0x00ffffff) + "\">" + text + "</font>";
return html;
}
public boolean isMaximized()
{
return maximized;
}
public void setMaximized(boolean b)
{
maximized = b;
}
protected Dataset getDataset()
{
return DatasetUsage.getInstance().getDatasetFromMemory(datasetKey);
}
public void setDatasetKey(String datasetKey)
{
this.datasetKey = datasetKey;
}
protected void addDataset(String key, Dataset value)
{
datasets.put(key, value);
}
protected Dataset getDataset(String key)
{
return datasets.get(key);
}
protected boolean datasetExists(String key)
{
return datasets.containsKey(key);
}
public Dataset visibleDataset(ChartFrame cf, String key)
{
if (datasets.containsKey(key))
{
Dataset d = getDataset(key);
if (d == null)
{
return null;
}
Dataset v = d.getVisibleDataset(cf.getChartData().getPeriod(), cf.getChartData().getLast());
return v;
}
return null;
}
public void clearDatasets()
{
datasets.clear();
}
public abstract String getName();
public abstract String getLabel();
public abstract String getPaintedLabel(ChartFrame cf);
public abstract Indicator newInstance();
public abstract LinkedHashMap getHTML(ChartFrame cf, int i);
public Range getRange(ChartFrame cf)
{
if (datasets.values().isEmpty())
{
return new Range();
}
Range range = null;
Iterator<String> it = datasets.keySet().iterator();
while (it.hasNext())
{
Dataset d = visibleDataset(cf, it.next());
double min = d.getMin(Dataset.CLOSE_PRICE);
double max = d.getMax(Dataset.CLOSE_PRICE);
if (range == null)
{
range = new Range(min - (max - min) * 0.01, max + (max - min) * 0.01);
} else
{
range = Range.combine(range, new Range(min - (max - min) * 0.01, max + (max - min) * 0.01));
}
}
return range;
}
public abstract void paint(Graphics2D g, ChartFrame cf, Rectangle bounds);
public abstract void calculate();
public abstract boolean hasZeroLine();
public abstract boolean getZeroLineVisibility();
public abstract Color getZeroLineColor();
public abstract Stroke getZeroLineStroke();
public abstract boolean hasDelimiters();
public abstract boolean getDelimitersVisibility();
public abstract double[] getDelimitersValues();
public abstract Color getDelimitersColor();
public abstract Stroke getDelimitersStroke();
public abstract Color[] getColors();
public abstract double[] getValues(ChartFrame cf);
public abstract double[] getValues(ChartFrame cf, int i);
public abstract boolean getMarkerVisibility();
public abstract AbstractNode getNode();
public boolean paintValues()
{
return true;
}
public Double[] getPriceValues(ChartFrame cf)
{
List<Double> list = new ArrayList<Double>();
if (!hasZeroLine())
{
list.add(new Double(0));
}
Range range = getRange(cf);
int max = (int) range.getUpperBound();
if (max > 0)
{
max = max - max % 10;
} else
{
int i = Math.abs(max % 10);
max = max - (5 - i);
}
int min = (int) Math.ceil(range.getLowerBound());
if (min > 0)
{
int i = min % 10;
min = min + (i < 5 ? 5 - i : 10 - i);
} else
{
int i = Math.abs(min % 10);
min = min + (i < 5 ? i : i - 5);
}
list.add(new Double((double) min));
list.add(new Double((double) max));
if (Math.abs(max) > Math.abs(min))
{
list.add(new Double(max / 2));
} else
{
list.add(new Double(min / 2));
}
Double[] retval = list.toArray(new Double[list.size()]);
list = null;
return retval;
}
protected void paintFill(Graphics2D g, ChartFrame cf, Dataset dataset, Rectangle bounds, Range range, Color color, double f, double t, boolean upper)
{
double min = Math.min(f, t);
double max = Math.max(f, t);
if (upper)
{
max = Math.max(max, range.getUpperBound());
} else
{
min = Math.max(f, t);
max = Math.min(f, t);
}
ChartData cd = cf.getChartData();
int count = dataset.getItemsCount();
double x, dx, y = cd.getY(min, bounds, range, false);
Range newRange = new Range(min, max);
g.setColor(color);
for (int i = 1; i < count; i++)
{
if (dataset.getDataItem(i - 1) != null && dataset.getDataItem(i) != null)
{
double value1 = dataset.getCloseAt(i - 1);
double value2 = dataset.getCloseAt(i);
Point2D p1 = cd.getPoint(i - 1, value1, range, bounds, false);
Point2D p2 = cd.getPoint(i, value2, range, bounds, false);
if (!newRange.contains(value1) && newRange.contains(value2))
{
dx = (y - p1.getY()) / (p2.getY() - p1.getY());
x = p1.getX() + dx * (p2.getX() - p1.getX());
GeneralPath gp = new GeneralPath();
gp.moveTo((float) x, (float) y);
gp.lineTo((float) p2.getX(), (float) p2.getY());
gp.lineTo((float) p2.getX(), (float) y);
gp.closePath();
g.fill(gp);
} else if (newRange.contains(value1) && newRange.contains(value2))
{
GeneralPath gp = new GeneralPath();
gp.moveTo((float) p1.getX(), (float) y);
gp.lineTo((float) p1.getX(), (float) p1.getY());
gp.lineTo((float) p2.getX(), (float) p2.getY());
gp.lineTo((float) p2.getX(), (float) y);
gp.closePath();
g.fill(gp);
} else if (newRange.contains(value1) && !newRange.contains(value2))
{
dx = (y - p1.getY()) / (p2.getY() - p1.getY());
x = p1.getX() + dx * (p2.getX() - p1.getX());
GeneralPath gp = new GeneralPath();
gp.moveTo((float) p1.getX(), (float) p1.getY());
gp.lineTo((float) x, (float) y);
gp.lineTo((float) p1.getX(), (float) y);
gp.closePath();
g.fill(gp);
}
}
}
}
public void saveToTemplate(Document document, Element element)
{
AbstractPropertiesNode node = (AbstractPropertiesNode) getNode();
AbstractPropertyListener listener = node.getAbstractPropertyListener();
Field[] fields = listener.getClass().getDeclaredFields();
for (Field field : fields)
{
try
{
field.setAccessible(true);
if (field.getModifiers() == Modifier.PRIVATE)
{
XMLUtil.addProperty(document, element, field.getName(), field.get(listener));
}
} catch (Exception ex)
{
Logger.getLogger(getName()).log(Level.SEVERE, "", ex);
}
}
}
public void loadFromTemplate(Element element)
{
AbstractPropertiesNode node = (AbstractPropertiesNode) getNode();
AbstractPropertyListener listener = node.getAbstractPropertyListener();
Field[] fields = listener.getClass().getDeclaredFields();
for (Field field : fields)
{
try
{
field.setAccessible(true);
if (field.getModifiers() == Modifier.PRIVATE)
{
if (XMLUtil.elementExists(element, field.getName()))
{
Class type = field.getType();
if (type.equals(String.class))
{
field.set(listener, XMLUtil.getStringProperty(element, field.getName()));
} else if (type.equals(int.class))
{
field.set(listener, XMLUtil.getIntegerProperty(element, field.getName()));
} else if (type.equals(double.class))
{
field.set(listener, XMLUtil.getDoubleProperty(element, field.getName()));
} else if (type.equals(float.class))
{
field.set(listener, XMLUtil.getFloatProperty(element, field.getName()));
} else if (type.equals(boolean.class))
{
field.set(listener, XMLUtil.getBooleanProperty(element, field.getName()));
} else if (type.equals(Color.class))
{
field.set(listener, XMLUtil.getColorProperty(element, field.getName()));
}
}
}
} catch (Exception ex)
{
Logger.getLogger(getName()).log(Level.SEVERE, "", ex);
}
}
}
public void setActive(boolean active)
{
this.active = active;
}
public boolean isActive()
{
return active;
}
@Override
public void datasetKeyChanged(String datasetKey)
{
setDatasetKey(datasetKey);
calculate();
}
}