package imseProc.graph;

import jafama.FastMath;


import java.awt.Color;
import java.awt.Font;
import java.text.ChoiceFormat;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.urls.StandardXYURLGenerator;
import org.jfree.chart.urls.XYURLGenerator;
import org.jfree.chart.util.RectangleInsets;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.experimental.chart.swt.ChartComposite;

import otherSupport.ScientificNumberFormat;

public class JFreeChartGraph {
	
	private ChartComposite frame;
	private XYSeriesCollection dataset;
	
	/** Stops the range shrinking */
	private boolean rangeHold = false; 
	private double rangeHoldMin, rangeHoldMax; 
	private NumberAxis xAxis;
	private NumberAxis valueAxis;
	private XYPlot plot;
	
    public JFreeChartGraph(Composite parent, int style){
    	    
    	XYSeries series = new XYSeries("Series 1");
        
        double value = 100.0;
        for (int i = 0; i < 200; i++) {
            series.add(i+100, value);    
            value = value * (1 + (Math.random() - 0.495) / 10.0);
        }
        
        dataset = new XYSeriesCollection();
        dataset.addSeries(series);

        initB(parent, style, dataset);
    }
     
    public JFreeChartGraph(Composite parent, int style, XYDataset dataset){
    	init(parent, style, dataset);
    }
    
    private void init(Composite parent, int style, XYDataset dataset){

        StandardChartTheme currentTheme = new StandardChartTheme("JFree");
        
        ScientificNumberFormat format = new ScientificNumberFormat();
        //format.
        
        xAxis = new NumberAxis(null);
        xAxis.setLowerMargin(0.00);  // reduce the default margins
        xAxis.setUpperMargin(0.00);
        xAxis.setAutoRangeIncludesZero(false);  // override default
        xAxis.setNumberFormatOverride(format);
        
        valueAxis = new NumberAxis(null);
        valueAxis.setLowerMargin(0.10);  // reduce the default margins
        valueAxis.setUpperMargin(0.10);
        valueAxis.setAutoRangeIncludesZero(false);  // override default
        valueAxis.setNumberFormatOverride(format);
        
        plot = new XYPlot(dataset, xAxis, valueAxis, null);

        XYToolTipGenerator toolTipGenerator = StandardXYToolTipGenerator.getTimeSeriesInstance();

        //XYURLGenerator urlGenerator = new StandardXYURLGenerator();

        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
        renderer.setBaseToolTipGenerator(toolTipGenerator);
        //renderer.setURLGenerator(urlGenerator);
        renderer.setSeriesPaint(0, Color.BLACK);
        renderer.setSeriesPaint(1, Color.BLUE);
        renderer.setSeriesPaint(2, Color.RED);
        renderer.setSeriesPaint(3, Color.GREEN);
        plot.setRenderer(renderer);
        
        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
        currentTheme.apply(chart);
        
        chart.setBackgroundPaint(Color.white);
        chart.setBorderVisible(true);
        chart.setBorderPaint(Color.BLACK);
                
        plot.setOrientation(PlotOrientation.VERTICAL);
        plot.setBackgroundPaint(Color.lightGray);
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);
        
        //plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
        plot.setAxisOffset(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        //plot.getRangeAxis().setFixedDimension(15.0);
        //XYItemRenderer renderer = plot.getRenderer();
        renderer.setSeriesPaint(0, Color.black);
        
        
       
        frame = new ChartComposite(parent, SWT.NONE, chart, 
        		300,300,
        		10, 10, 1000, 1000, true, true, true, true, true, true);
        frame.setDisplayToolTips(true);
        frame.setHorizontalAxisTrace(true);
        frame.setVerticalAxisTrace(true);
        frame.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(Event event) { resizeEvent(event); } });
        
        chart.setPadding(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        plot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        xAxis.setTickLabelInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        valueAxis.setTickLabelInsets(new RectangleInsets(0.0, 4.0, 0.0, 0.0));
        
        Font f = xAxis.getTickLabelFont().deriveFont(10.0f);
        xAxis.setTickLabelFont(f);
        valueAxis.setTickLabelFont(f);
                
    }
    

    private void initB(Composite parent, int style, XYDataset dataset){
            
        
        StandardChartTheme currentTheme = new StandardChartTheme("JFree");
        
        ScientificNumberFormat format = new ScientificNumberFormat();
        
        xAxis = new NumberAxis(null);
        xAxis.setLowerMargin(0.00);  // reduce the default margins
        xAxis.setUpperMargin(0.00);
        xAxis.setAutoRangeIncludesZero(false);  // override default
        xAxis.setNumberFormatOverride(format);
        
        valueAxis = new NumberAxis(null);
        valueAxis.setLowerMargin(0.10);  // reduce the default margins
        valueAxis.setUpperMargin(0.10);
        valueAxis.setAutoRangeIncludesZero(false);  // override default
        valueAxis.setNumberFormatOverride(format);
        
        plot = new XYPlot(dataset, xAxis, valueAxis, null);

        XYToolTipGenerator toolTipGenerator = StandardXYToolTipGenerator.getTimeSeriesInstance();

        //XYURLGenerator urlGenerator = new StandardXYURLGenerator();

        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
        renderer.setBaseToolTipGenerator(toolTipGenerator);
        //renderer.setURLGenerator(urlGenerator);
        renderer.setSeriesPaint(0, Color.BLACK);
        renderer.setSeriesPaint(1, Color.BLUE);
        renderer.setSeriesPaint(2, Color.RED);
        renderer.setSeriesPaint(3, Color.GREEN);
        plot.setRenderer(renderer);

        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
        currentTheme.apply(chart);
        
        chart.setBackgroundPaint(Color.white);
        chart.setBorderVisible(true);
        chart.setBorderPaint(Color.BLACK);
        
        
        plot.setOrientation(PlotOrientation.VERTICAL);
        plot.setBackgroundPaint(Color.lightGray);
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);
        
        
        plot.setAxisOffset(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
       
        renderer.setSeriesPaint(0, Color.black);
        
        frame = new ChartComposite(parent, SWT.NONE, chart, 
        		300,300,
        		10, 10, 1000, 1000, true, true, true, true, true, true);
        frame.setDisplayToolTips(true);
        frame.setHorizontalAxisTrace(true);
        frame.setVerticalAxisTrace(true);
        frame.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(Event event) { resizeEvent(event); } });
        
        chart.setPadding(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        plot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        xAxis.setTickLabelInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
        valueAxis.setTickLabelInsets(new RectangleInsets(0.0, 4.0, 0.0, 0.0));
        
        Font f = xAxis.getTickLabelFont().deriveFont(10.0f);
        xAxis.setTickLabelFont(f);
        valueAxis.setTickLabelFont(f);
                
    }
    
    public void resizeEvent(Event event){
    	//System.out.println("Graph frame resize: " + event.width + " x " + event.height );
    	frame.layout();
    }
    
    public ChartComposite getComposite() { return frame; }
    
    //public void setData(double x[], double data[]){
    //	setData(x, null, new double[][]{ data });
    //}
    
    public void setData(List<Series> seriesList){    	
    	synchronized (dataset) {
			dataset.removeAllSeries();
	    	   	
	    	//XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer)((XYPlot)frame.getChart().getPlot()).getRenderer();
	
	      //some protection for silly data lengths and useful display for single values
	    	if(seriesList == null || seriesList.size() <= 0)
	    		return;
	    	
	    	for(int j=0; j < seriesList.size(); j++){
	    		Series series = seriesList.get(j);

		    	//if a single value, make a series from [0,v] to [1,v]
		    	if(series.data.length == 1){
		    		series.x = new double[]{ 0, 1 };		    		
		    		series.data = new double[]{ series.data[0], series.data[0] };
		    	}		    	
	    		
	        	if(series.data == null || series.data.length != series.x.length)
	    			continue; //skip empty or invalid length data
	    		
		    	XYSeries xySeries = new XYSeries((series.name == null) ? ("Series " + j) : series.name);
		        
		    	for (int i = 0; i < series.data.length; i++) {
		        	xySeries.add(series.x[i], series.data[i]);    
		        }
		        
		    	dataset.addSeries(xySeries);
		    	
		    	if(rangeHold){
		    		double newMin = xySeries.getMinY();
		    		double newMax = xySeries.getMaxY();
		    		if(newMin < rangeHoldMin) rangeHoldMin = newMin;
		    		if(newMax > rangeHoldMax) rangeHoldMax = newMax;
		    	}
	    	}
	    	
	    	if(rangeHold){
		    		NumberAxis valueAxis = (NumberAxis) ((XYPlot)frame.getChart().getPlot()).getRangeAxis();
		    		valueAxis.setRange(rangeHoldMin, rangeHoldMax);        	
	    	}
    	}
    }
    
    public void setAutoRangeIncludesZero(boolean autoRangeIncludesZero){
    	//NumberAxis valueAxis = (NumberAxis) ((XYPlot)frame.getChart().getPlot()).getRangeAxis();
    	valueAxis.setAutoRangeIncludesZero(autoRangeIncludesZero);
    }
    
    public void setRangeHold(boolean rangeHold){
    	NumberAxis valueAxis = (NumberAxis) ((XYPlot)frame.getChart().getPlot()).getRangeAxis();
    	Range range = valueAxis.getRange();
    	this.rangeHold = rangeHold;
    	if(rangeHold){
    		rangeHoldMin = range.getLowerBound();
    		rangeHoldMax = range.getUpperBound();
    		valueAxis.setAutoRange(false);
    	}else{
    		valueAxis.setAutoRange(true);
    	}
    }
    
    public void setRangeX(int x0, int x1){
    	
    }
    
    public void setDataset(XYDataset dataset) {
		plot.setDataset(dataset);
	}

	public void setColours(Color[] colors) {		
		AbstractXYItemRenderer renderer = (AbstractXYItemRenderer)plot.getRenderer();
		for(int i=0; i < colors.length; i++)
			renderer.setSeriesPaint(i, colors[i]);		
	}
}
