/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2023 Cloud Software Group, Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.jasperreports.chartthemes.spring;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.SortedSet;
import java.util.TimeZone;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.Axis;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockFrame;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ThermometerPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.plot.dial.DialBackground;
import org.jfree.chart.plot.dial.DialCap;
import org.jfree.chart.plot.dial.DialPlot;
import org.jfree.chart.plot.dial.DialPointer;
import org.jfree.chart.plot.dial.DialTextAnnotation;
import org.jfree.chart.plot.dial.DialValueIndicator;
import org.jfree.chart.plot.dial.StandardDialFrame;
import org.jfree.chart.plot.dial.StandardDialRange;
import org.jfree.chart.plot.dial.StandardDialScale;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.BarRenderer3D;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StackedBarRenderer3D;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.HighLowRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYBubbleRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.Range;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.gantt.GanttCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.general.ValueDataset;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.DefaultHighLowDataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;
import org.jfree.ui.VerticalAlignment;
import org.jfree.util.UnitType;

import net.sf.jasperreports.charts.ChartContext;
import net.sf.jasperreports.charts.ChartTheme;
import net.sf.jasperreports.charts.JRAreaPlot;
import net.sf.jasperreports.charts.JRBar3DPlot;
import net.sf.jasperreports.charts.JRBarPlot;
import net.sf.jasperreports.charts.JRBubblePlot;
import net.sf.jasperreports.charts.JRCandlestickPlot;
import net.sf.jasperreports.charts.JRChartAxis;
import net.sf.jasperreports.charts.JRDataRange;
import net.sf.jasperreports.charts.JRHighLowPlot;
import net.sf.jasperreports.charts.JRItemLabel;
import net.sf.jasperreports.charts.JRLinePlot;
import net.sf.jasperreports.charts.JRMeterPlot;
import net.sf.jasperreports.charts.JRPie3DPlot;
import net.sf.jasperreports.charts.JRPiePlot;
import net.sf.jasperreports.charts.JRScatterPlot;
import net.sf.jasperreports.charts.JRThermometerPlot;
import net.sf.jasperreports.charts.JRTimeSeriesPlot;
import net.sf.jasperreports.charts.JRValueDisplay;
import net.sf.jasperreports.charts.type.EdgeEnum;
import net.sf.jasperreports.charts.type.MeterShapeEnum;
import net.sf.jasperreports.charts.type.PlotOrientationEnum;
import net.sf.jasperreports.charts.type.ScaleTypeEnum;
import net.sf.jasperreports.charts.type.ValueLocationEnum;
import net.sf.jasperreports.charts.util.ChartUtil;
import net.sf.jasperreports.charts.util.JRMeterInterval;
import net.sf.jasperreports.engine.JRChart;
import net.sf.jasperreports.engine.JRChartDataset;
import net.sf.jasperreports.engine.JRChartPlot;
import net.sf.jasperreports.engine.JRChartPlot.JRSeriesColor;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRFont;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.base.JRBaseFont;
import net.sf.jasperreports.engine.fill.DefaultChartTheme;
import net.sf.jasperreports.engine.fonts.FontUtil;
import net.sf.jasperreports.engine.type.ModeEnum;


/**
 * @author Sanda Zaharia (shertage@users.sourceforge.net)
 */
public class GenericChartTheme implements ChartTheme
{
	/**
	 *
	 */

	protected Map<String, ?> defaultChartPropertiesMap;
	protected Map<String, ?> defaultPlotPropertiesMap;
	protected Map<String, ?> defaultAxisPropertiesMap;
	protected Map<String, ?> defaultChartTypePropertiesMap;
	
	/**
	 *
	 */
	protected ThreadLocal<ChartContext> threadLocalChartContext = new ThreadLocal<>();
	protected ThreadLocal<FontUtil> threadLocalFontUtil = new ThreadLocal<>();
	

	/**
	 *
	 */
	protected GenericChartTheme()
	{
	}
	
	
	/**
	 *
	 */
	protected ChartContext getChartContext()
	{
		return threadLocalChartContext.get();
	}
	
	
	/**
	 *
	 */
	private void setChartContext(ChartContext chartContext)
	{
		this.threadLocalChartContext.set(chartContext);
		this.threadLocalFontUtil.set(FontUtil.getInstance(chartContext.getJasperReportsContext()));
	}

	
	/**
	 *
	 */
	private FontUtil getFontUtil()
	{
		return threadLocalFontUtil.get();
	}
	
	
	/**
	 *
	 */
	protected JRChart getChart()
	{
		return getChartContext().getChart();
	}
	
	
	/**
	 *
	 */
	protected JRChartPlot getPlot()
	{
		return getChart().getPlot();
	}
	
	
	/**
	 *
	 */
	protected Dataset getDataset()
	{
		return getChartContext().getDataset();
	}
	
	
	/**
	 *
	 */
	protected Object getLabelGenerator()
	{
		return getChartContext().getLabelGenerator();
	}
	
	
	/**
	 *
	 */
	protected Locale getLocale()
	{
		return getChartContext().getLocale();
	}
	
	
	/**
	 *
	 */
	protected final Object evaluateExpression(JRExpression expression) throws JRException
	{
		return getChartContext().evaluateExpression(expression);
	}

	
	/**
	 *
	 */
	protected final String evaluateTextExpression(JRExpression expression) throws JRException
	{
		return getChartContext().evaluateTextExpression(expression);
	}

	@Override
	public JFreeChart createChart(ChartContext chartContext) throws JRException
	{
		setChartContext(chartContext);
		
		JFreeChart jfreeChart = null;
		
		switch(getChart().getChartType()) {
			case JRChart.CHART_TYPE_AREA:
				jfreeChart = createAreaChart();
				break;
			case JRChart.CHART_TYPE_BAR:
				jfreeChart = createBarChart();
				break;
			case JRChart.CHART_TYPE_BAR3D:
				jfreeChart = createBar3DChart();
				break;
			case JRChart.CHART_TYPE_BUBBLE:
				jfreeChart = createBubbleChart();
				break;
			case JRChart.CHART_TYPE_CANDLESTICK:
				jfreeChart = createCandlestickChart();
				break;
			case JRChart.CHART_TYPE_HIGHLOW:
				jfreeChart = createHighLowChart();
				break;
			case JRChart.CHART_TYPE_LINE:
				jfreeChart = createLineChart();
				break;
			case JRChart.CHART_TYPE_METER:
				jfreeChart = createMeterChart();
				break;
			case JRChart.CHART_TYPE_MULTI_AXIS:
				//multi-axis charts are dealt with in JRChart
				break;
			case JRChart.CHART_TYPE_PIE:
				jfreeChart = createPieChart();
				break;
			case JRChart.CHART_TYPE_PIE3D:
				jfreeChart = createPie3DChart();
				break;
			case JRChart.CHART_TYPE_SCATTER:
				jfreeChart = createScatterChart();
				break;
			case JRChart.CHART_TYPE_STACKEDBAR:
				jfreeChart = createStackedBarChart();
				break;
			case JRChart.CHART_TYPE_STACKEDBAR3D:
				jfreeChart = createStackedBar3DChart();
				break;
			case JRChart.CHART_TYPE_THERMOMETER:
				jfreeChart = createThermometerChart();
				break;
			case JRChart.CHART_TYPE_TIMESERIES:
				jfreeChart = createTimeSeriesChart();
				break;
			case JRChart.CHART_TYPE_XYAREA:
				jfreeChart = createXyAreaChart();
				break;
			case JRChart.CHART_TYPE_XYBAR:
				jfreeChart = createXYBarChart();
				break;
			case JRChart.CHART_TYPE_XYLINE:
				jfreeChart = createXyLineChart();
				break;
			case JRChart.CHART_TYPE_STACKEDAREA:
				jfreeChart = createStackedAreaChart();
				break;
			case JRChart.CHART_TYPE_GANTT:
				jfreeChart = createGanttChart();
				break;
			default:
				throw new JRRuntimeException("Chart type " + getChart().getChartType() + " not supported.");
		}

		return jfreeChart;
	}

	/**
	 *
	 */
	protected void configureChart(JFreeChart jfreeChart, JRChartPlot jrPlot) throws JRException
	{	
		Integer defaultBaseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
		
		setChartBackground(jfreeChart);
		setChartTitle(jfreeChart, defaultBaseFontSize);
		setChartSubtitles(jfreeChart, defaultBaseFontSize);
		setChartLegend(jfreeChart, defaultBaseFontSize);
		setChartBorder(jfreeChart);
		
		Boolean isAntiAlias = (Boolean)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.CHART_ANTI_ALIAS);
		if (isAntiAlias != null)
			jfreeChart.setAntiAlias(isAntiAlias);
		
		Double padding = (Double)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.CHART_PADDING);
		UnitType unitType = (UnitType)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.UNIT_TYPE);
		if (padding != null && unitType != null)
		{
			jfreeChart.setPadding(new RectangleInsets(unitType, padding, padding, padding, padding));
		}
		configurePlot(jfreeChart.getPlot(), jrPlot);
	}


	/**
	 *
	 */
	protected void configurePlot(Plot p, JRChartPlot jrPlot)
	{
		RectangleInsets defaultPlotInsets = (RectangleInsets)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_INSETS);
		Paint defaultPlotOutlinePaint = (Paint)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_PAINT);
		Stroke defaultPlotOutlineStroke = (Stroke)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_STROKE);
		Boolean defaultPlotOutlineVisible = (Boolean)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_VISIBLE);
		if (defaultPlotInsets != null) 
			p.setInsets(defaultPlotInsets);

		if (defaultPlotOutlineVisible != null) 
		{
			if (defaultPlotOutlineVisible)
			{
				if (defaultPlotOutlinePaint != null)
					p.setOutlinePaint(defaultPlotOutlinePaint);
				
				if (defaultPlotOutlineStroke != null)
					p.setOutlineStroke(defaultPlotOutlineStroke);
				
				p.setOutlineVisible(true);
			}
			else
			{
				p.setOutlineVisible(false);
			}
		}
		
		setPlotBackground(p, jrPlot);
		if (p instanceof CategoryPlot)
		{
			handleCategoryPlotSettings((CategoryPlot)p, jrPlot);
		}

		setPlotDrawingDefaults(p, jrPlot);
	}

	/**
	 * Sets all the axis formatting options.  This includes the colors and fonts to use on
	 * the axis as well as the color to use when drawing the axis line.
	 *
	 * @param axis the axis to format
	 * @param labelFont the font to use for the axis label
	 * @param labelColor the color of the axis label
	 * @param tickLabelFont the font to use for each tick mark value label
	 * @param tickLabelColor the color of each tick mark value label
	 * @param tickLabelMask formatting mask for the label.  If the axis is a NumberAxis then
	 * 						the mask should be <code>java.text.DecimalFormat</code> mask, and
	 * 						if it is a DateAxis then the mask should be a
	 * 						<code>java.text.SimpleDateFormat</code> mask.
	 * @param verticalTickLabels flag to draw tick labels at 90 degrees
	 * @param lineColor color to use when drawing the axis line and any tick marks
	 * @param isRangeAxis used to distinguish between range and domain axis type
	 */
	protected void configureAxis(
			Axis axis,
			JRFont labelFont,
			Color labelColor,
			JRFont tickLabelFont,
			Color tickLabelColor,
			String tickLabelMask,
			Boolean verticalTickLabels,
			Paint lineColor,
			boolean isRangeAxis,
			Comparable<?> axisMinValue,
			Comparable<?> axisMaxValue
			) throws JRException
	{
		Boolean axisVisible = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_VISIBLE);
		
		if (axisVisible != null && axisVisible)
		{
			setAxisLine(axis, lineColor);

			Double defaultFixedDimension = (Double)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_FIXED_DIMENSION);
			if (defaultFixedDimension != null)
			{
				axis.setFixedDimension(defaultFixedDimension);
			}
			
			Integer baseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
			setAxisLabel(axis, labelFont, labelColor, baseFontSize);
			setAxisTickLabels(axis, tickLabelFont, tickLabelColor, tickLabelMask, baseFontSize);
			setAxisTickMarks(axis, lineColor);
			String timePeriodUnit = isRangeAxis 
				? (String)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.RANGE_AXIS_TIME_PERIOD_UNIT)
				: (String)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.DOMAIN_AXIS_TIME_PERIOD_UNIT);
			setAxisBounds(axis, isRangeAxis, timePeriodUnit, axisMinValue, axisMaxValue);
			
			if (verticalTickLabels != null && axis instanceof ValueAxis)
			{
				((ValueAxis)axis).setVerticalTickLabels(verticalTickLabels);
			}
		}
		else
		{
			axis.setVisible(false);
		}
	}

	/**
	 *
	 */
	protected JFreeChart createAreaChart() throws JRException 
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart = 
			ChartFactory.createAreaChart( 
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRAreaPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRAreaPlot)getPlot()).getValueAxisLabelExpression()),
				(CategoryDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false);

		configureChart(jfreeChart, getPlot());
		JRAreaPlot areaPlot = (JRAreaPlot)getPlot();
		// Handle the axis formating for the category axis
		configureAxis(((CategoryPlot)jfreeChart.getPlot()).getDomainAxis(), areaPlot.getCategoryAxisLabelFont(),
				areaPlot.getCategoryAxisLabelColor(), areaPlot.getCategoryAxisTickLabelFont(),
				areaPlot.getCategoryAxisTickLabelColor(), areaPlot.getCategoryAxisTickLabelMask(), areaPlot.getCategoryAxisVerticalTickLabels(),
				areaPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(areaPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(areaPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(((CategoryPlot)jfreeChart.getPlot()).getRangeAxis(), areaPlot.getValueAxisLabelFont(),
				areaPlot.getValueAxisLabelColor(), areaPlot.getValueAxisTickLabelFont(),
				areaPlot.getValueAxisTickLabelColor(), areaPlot.getValueAxisTickLabelMask(), areaPlot.getValueAxisVerticalTickLabels(),
				areaPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(areaPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(areaPlot.getRangeAxisMaxValueExpression()));
				
		return jfreeChart;
	}


	protected JFreeChart createBar3DChart() throws JRException 
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createBarChart3D(
					evaluateTextExpression(getChart().getTitleExpression()),
					evaluateTextExpression(((JRBar3DPlot)getPlot()).getCategoryAxisLabelExpression()),
					evaluateTextExpression(((JRBar3DPlot)getPlot()).getValueAxisLabelExpression()),
					(CategoryDataset)getDataset(),
					ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
					isShowLegend(),
					true,
					false );

		configureChart(jfreeChart, getPlot());

		CategoryPlot categoryPlot = (CategoryPlot)jfreeChart.getPlot();
		JRBar3DPlot bar3DPlot = (JRBar3DPlot)getPlot();

		BarRenderer3D barRenderer3D =
			new BarRenderer3D(
				bar3DPlot.getXOffsetDouble() == null ? BarRenderer3D.DEFAULT_X_OFFSET : bar3DPlot.getXOffsetDouble(),
				bar3DPlot.getYOffsetDouble() == null ? BarRenderer3D.DEFAULT_Y_OFFSET : bar3DPlot.getYOffsetDouble()
				);

		boolean isShowLabels = bar3DPlot.getShowLabels() == null ? false : bar3DPlot.getShowLabels();
		barRenderer3D.setBaseItemLabelsVisible( isShowLabels );
		if (isShowLabels)
		{
			JRItemLabel itemLabel = bar3DPlot.getItemLabel();
			Integer baseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
			JRFont font = itemLabel != null && itemLabel.getFont() != null ? itemLabel.getFont() : null;
			barRenderer3D.setBaseItemLabelFont(getFont(new JRBaseFont(getChart(), null), font, baseFontSize));
			
			if (itemLabel != null)
			{
				if (itemLabel.getColor() != null)
				{
					barRenderer3D.setBaseItemLabelPaint(itemLabel.getColor());
				}
				else
				{
					barRenderer3D.setBaseItemLabelPaint(getChart().getForecolor());
				}
//				categoryRenderer.setBaseFillPaint(itemLabel.getBackgroundColor());
//				if (itemLabel.getMask() != null)
//				{
//					barRenderer3D.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator(
//							StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, 
//							new DecimalFormat(itemLabel.getMask())));
//				}
//				else
//				{
					barRenderer3D.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
//				}
			}
			else
			{
				barRenderer3D.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
				barRenderer3D.setBaseItemLabelPaint(getChart().getForecolor());
			}
		}

		categoryPlot.setRenderer(barRenderer3D);
		
		// Handle the axis formating for the category axis
		configureAxis(categoryPlot.getDomainAxis(), bar3DPlot.getCategoryAxisLabelFont(),
				bar3DPlot.getCategoryAxisLabelColor(), bar3DPlot.getCategoryAxisTickLabelFont(),
				bar3DPlot.getCategoryAxisTickLabelColor(), bar3DPlot.getCategoryAxisTickLabelMask(), bar3DPlot.getCategoryAxisVerticalTickLabels(),
				bar3DPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(bar3DPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(bar3DPlot.getDomainAxisMaxValueExpression()));


		// Handle the axis formating for the value axis
		configureAxis(categoryPlot.getRangeAxis(), bar3DPlot.getValueAxisLabelFont(),
				bar3DPlot.getValueAxisLabelColor(), bar3DPlot.getValueAxisTickLabelFont(),
				bar3DPlot.getValueAxisTickLabelColor(), bar3DPlot.getValueAxisTickLabelMask(), bar3DPlot.getValueAxisVerticalTickLabels(),
				bar3DPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(bar3DPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(bar3DPlot.getRangeAxisMaxValueExpression()));
		
		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createBarChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createBarChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getValueAxisLabelExpression()),
				(CategoryDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());

		CategoryPlot categoryPlot = (CategoryPlot)jfreeChart.getPlot();
		//plot.setNoDataMessage("No data to display");
		
		JRBarPlot barPlot = (JRBarPlot)getPlot();
		boolean isShowTickMarks = barPlot.getShowTickMarks() == null ? true : barPlot.getShowTickMarks();
		boolean isShowTickLabels = barPlot.getShowTickLabels() == null ? true : barPlot.getShowTickLabels();

		categoryPlot.getDomainAxis().setTickMarksVisible(isShowTickMarks);
		categoryPlot.getDomainAxis().setTickLabelsVisible(isShowTickLabels);
		// Handle the axis formating for the category axis
		configureAxis(categoryPlot.getDomainAxis(), barPlot.getCategoryAxisLabelFont(),
				barPlot.getCategoryAxisLabelColor(), barPlot.getCategoryAxisTickLabelFont(),
				barPlot.getCategoryAxisTickLabelColor(), barPlot.getCategoryAxisTickLabelMask(), barPlot.getCategoryAxisVerticalTickLabels(),
				barPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(barPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(barPlot.getDomainAxisMaxValueExpression()));

		((NumberAxis)categoryPlot.getRangeAxis()).setTickMarksVisible(isShowTickMarks);
		((NumberAxis)categoryPlot.getRangeAxis()).setTickLabelsVisible(isShowTickLabels);
		// Handle the axis formating for the value axis
		Comparable<?> rangeAxisMaxValue = (Comparable<?>)evaluateExpression(barPlot.getRangeAxisMaxValueExpression());
		configureAxis(categoryPlot.getRangeAxis(), barPlot.getValueAxisLabelFont(),
				barPlot.getValueAxisLabelColor(), barPlot.getValueAxisTickLabelFont(),
				barPlot.getValueAxisTickLabelColor(), barPlot.getValueAxisTickLabelMask(), barPlot.getValueAxisVerticalTickLabels(),
				barPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(barPlot.getRangeAxisMinValueExpression()),
				rangeAxisMaxValue);


		BarRenderer categoryRenderer = (BarRenderer)categoryPlot.getRenderer();
		boolean isShowLabels = barPlot.getShowLabels() == null ? false : barPlot.getShowLabels();
		categoryRenderer.setBaseItemLabelsVisible( isShowLabels );
		if (isShowLabels)
		{
			if (rangeAxisMaxValue == null)
			{
				//in case the bars are horizontal and there was no range max value specified, 
				//we try to make the axis a little longer for labels to fit on the plot
				Axis axis = categoryPlot.getRangeAxis();
				if (axis instanceof ValueAxis)
				{
					if (!(axis instanceof DateAxis))
					{
						float rangeAxisMaxRatio = 1f;
						
						if (barPlot.getOrientationValue() == PlotOrientationEnum.HORIZONTAL)
						{
							rangeAxisMaxRatio = 
								JRPropertiesUtil.getInstance(getChartContext().getJasperReportsContext()).getFloatProperty(
									getChart(), "net.sf.jasperreports.chart.bar.horizontal.range.max.value.ratio", 1.25f
									);
						}
						else
						{
							rangeAxisMaxRatio = 
								JRPropertiesUtil.getInstance(getChartContext().getJasperReportsContext()).getFloatProperty(
									getChart(), "net.sf.jasperreports.chart.bar.vertical.range.max.value.ratio", 1.1f
									);
						}
						
						((ValueAxis)axis).setUpperBound(((ValueAxis)axis).getUpperBound() * rangeAxisMaxRatio);
					}
				}
			}

			JRItemLabel itemLabel = barPlot.getItemLabel();
			Integer baseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
			JRFont font = itemLabel != null && itemLabel.getFont() != null ? itemLabel.getFont() : null;
			categoryRenderer.setBaseItemLabelFont(getFont(new JRBaseFont(getChart(), null), font, baseFontSize));

			if (itemLabel != null)
			{
				if (itemLabel.getColor() != null)
				{
					categoryRenderer.setBaseItemLabelPaint(itemLabel.getColor());
				}
				else
				{
					categoryRenderer.setBaseItemLabelPaint(getChart().getForecolor());
				}
//				categoryRenderer.setBaseFillPaint(itemLabel.getBackgroundColor());
//				if (itemLabel.getMask() != null)
//				{
//					categoryRenderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator(
//							StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, 
//							new DecimalFormat(itemLabel.getMask())));
//				}
//				else
//				{
					categoryRenderer.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
//				}
			}
			else
			{
				categoryRenderer.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
				categoryRenderer.setBaseItemLabelPaint(getChart().getForecolor());
			}
		}
		categoryRenderer.setShadowVisible(false);
		
		return jfreeChart;
	}


	protected JFreeChart createBubbleChart() throws JRException 
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart = 
			ChartFactory.createBubbleChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRBubblePlot)getPlot()).getXAxisLabelExpression()),
				evaluateTextExpression(((JRBubblePlot)getPlot()).getYAxisLabelExpression()),
				 (XYZDataset)getDataset(),
				 ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				 isShowLegend(),
				 true,
				 false);

		configureChart(jfreeChart, getPlot());

		XYPlot xyPlot = (XYPlot)jfreeChart.getPlot();
		JRBubblePlot bubblePlot = (JRBubblePlot)getPlot();
		ScaleTypeEnum scaleType = bubblePlot.getScaleTypeValue() == null ? ScaleTypeEnum.ON_RANGE_AXIS : bubblePlot.getScaleTypeValue();
		XYBubbleRenderer bubbleRenderer = new XYBubbleRenderer( ChartUtil.getScaleType(scaleType) );
		xyPlot.setRenderer( bubbleRenderer );

		// Handle the axis formating for the category axis
		configureAxis(xyPlot.getDomainAxis(), bubblePlot.getXAxisLabelFont(),
				bubblePlot.getXAxisLabelColor(), bubblePlot.getXAxisTickLabelFont(),
				bubblePlot.getXAxisTickLabelColor(), bubblePlot.getXAxisTickLabelMask(), bubblePlot.getXAxisVerticalTickLabels(),
				bubblePlot.getOwnXAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(bubblePlot.getDomainAxisMinValueExpression()), 
				(Comparable<?>)evaluateExpression(bubblePlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(xyPlot.getRangeAxis(), bubblePlot.getYAxisLabelFont(),
				bubblePlot.getYAxisLabelColor(), bubblePlot.getYAxisTickLabelFont(),
				bubblePlot.getYAxisTickLabelColor(), bubblePlot.getYAxisTickLabelMask(), bubblePlot.getYAxisVerticalTickLabels(),
				bubblePlot.getOwnYAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(bubblePlot.getRangeAxisMinValueExpression()), 
				(Comparable<?>)evaluateExpression(bubblePlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createCandlestickChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createCandlestickChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRCandlestickPlot)getPlot()).getTimeAxisLabelExpression()),
				evaluateTextExpression(((JRCandlestickPlot)getPlot()).getValueAxisLabelExpression()),
				(DefaultHighLowDataset)getDataset(),
				isShowLegend()
				);

		configureChart(jfreeChart, getPlot());

		XYPlot xyPlot = (XYPlot) jfreeChart.getPlot();
		JRCandlestickPlot candlestickPlot = (JRCandlestickPlot)getPlot();
		CandlestickRenderer candlestickRenderer = (CandlestickRenderer) xyPlot.getRenderer();
		boolean isShowVolume = candlestickPlot.getShowVolume() == null ? true : candlestickPlot.getShowVolume();
		candlestickRenderer.setDrawVolume(isShowVolume);

		// Handle the axis formating for the category axis
		configureAxis(xyPlot.getDomainAxis(), candlestickPlot.getTimeAxisLabelFont(),
				candlestickPlot.getTimeAxisLabelColor(), candlestickPlot.getTimeAxisTickLabelFont(),
				candlestickPlot.getTimeAxisTickLabelColor(), candlestickPlot.getTimeAxisTickLabelMask(), candlestickPlot.getTimeAxisVerticalTickLabels(),
				candlestickPlot.getOwnTimeAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(candlestickPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(candlestickPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(xyPlot.getRangeAxis(), candlestickPlot.getValueAxisLabelFont(),
				candlestickPlot.getValueAxisLabelColor(), candlestickPlot.getValueAxisTickLabelFont(),
				candlestickPlot.getValueAxisTickLabelColor(), candlestickPlot.getValueAxisTickLabelMask(), candlestickPlot.getValueAxisVerticalTickLabels(),
				candlestickPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(candlestickPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(candlestickPlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createHighLowChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createHighLowChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRHighLowPlot)getPlot()).getTimeAxisLabelExpression()),
				evaluateTextExpression(((JRHighLowPlot)getPlot()).getValueAxisLabelExpression()),
				(DefaultHighLowDataset)getDataset(),
				isShowLegend()
				);

		configureChart(jfreeChart, getPlot());
		XYPlot xyPlot = (XYPlot) jfreeChart.getPlot();
		JRHighLowPlot highLowPlot = (JRHighLowPlot)getPlot();
		HighLowRenderer hlRenderer = (HighLowRenderer) xyPlot.getRenderer();
		boolean isShowOpenTicks = highLowPlot.getShowOpenTicks() == null ? false : highLowPlot.getShowOpenTicks();
		boolean isShowCloseTicks = highLowPlot.getShowCloseTicks() == null ? false : highLowPlot.getShowCloseTicks();
		
		hlRenderer.setDrawOpenTicks(isShowOpenTicks);
		hlRenderer.setDrawCloseTicks(isShowCloseTicks);

		// Handle the axis formating for the category axis
		configureAxis(xyPlot.getDomainAxis(), highLowPlot.getTimeAxisLabelFont(),
				highLowPlot.getTimeAxisLabelColor(), highLowPlot.getTimeAxisTickLabelFont(),
				highLowPlot.getTimeAxisTickLabelColor(), highLowPlot.getTimeAxisTickLabelMask(), highLowPlot.getTimeAxisVerticalTickLabels(),
				highLowPlot.getOwnTimeAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(highLowPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(highLowPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(xyPlot.getRangeAxis(), highLowPlot.getValueAxisLabelFont(),
				highLowPlot.getValueAxisLabelColor(), highLowPlot.getValueAxisTickLabelFont(),
				highLowPlot.getValueAxisTickLabelColor(), highLowPlot.getValueAxisTickLabelMask(), highLowPlot.getValueAxisVerticalTickLabels(),
				highLowPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(highLowPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(highLowPlot.getRangeAxisMaxValueExpression()));
		
		return jfreeChart;
	}


	protected JFreeChart createLineChart() throws JRException 
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart freeChart = 
			ChartFactory.createLineChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression( ((JRLinePlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRLinePlot)getPlot()).getValueAxisLabelExpression()),
				(CategoryDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false);

		configureChart(freeChart, getPlot());

		CategoryPlot categoryPlot = (CategoryPlot)freeChart.getPlot();
		JRLinePlot linePlot = (JRLinePlot)getPlot();

		LineAndShapeRenderer lineRenderer = (LineAndShapeRenderer)categoryPlot.getRenderer();
		boolean isShowShapes = linePlot.getShowShapes() == null ? true : linePlot.getShowShapes();
		boolean isShowLines = linePlot.getShowLines() == null ? true : linePlot.getShowLines();
		
		lineRenderer.setBaseShapesVisible( isShowShapes );//FIXMECHART check this
		lineRenderer.setBaseLinesVisible( isShowLines );
		
		//FIXME labels?

		// Handle the axis formating for the category axis
		configureAxis(categoryPlot.getDomainAxis(), linePlot.getCategoryAxisLabelFont(),
				linePlot.getCategoryAxisLabelColor(), linePlot.getCategoryAxisTickLabelFont(),
				linePlot.getCategoryAxisTickLabelColor(), linePlot.getCategoryAxisTickLabelMask(), linePlot.getCategoryAxisVerticalTickLabels(),
				linePlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(linePlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(linePlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(categoryPlot.getRangeAxis(), linePlot.getValueAxisLabelFont(),
				linePlot.getValueAxisLabelColor(), linePlot.getValueAxisTickLabelFont(),
				linePlot.getValueAxisTickLabelColor(), linePlot.getValueAxisTickLabelMask(), linePlot.getValueAxisVerticalTickLabels(),
				linePlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(linePlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(linePlot.getRangeAxisMaxValueExpression()));

		return freeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createPie3DChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createPieChart3D(
				evaluateTextExpression(getChart().getTitleExpression()),
				(PieDataset)getDataset(),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());

		PiePlot3D piePlot3D = (PiePlot3D) jfreeChart.getPlot();
		//plot.setStartAngle(290);
		//plot.setDirection(Rotation.CLOCKWISE);
		//plot.setNoDataMessage("No data to display");
		JRPie3DPlot jrPie3DPlot = (JRPie3DPlot)getPlot();
		double depthFactor = jrPie3DPlot.getDepthFactorDouble() == null ? JRPie3DPlot.DEPTH_FACTOR_DEFAULT : jrPie3DPlot.getDepthFactorDouble();
		boolean isCircular =  jrPie3DPlot.getCircular() == null ? false : jrPie3DPlot.getCircular();
		piePlot3D.setDepthFactor(depthFactor);
		piePlot3D.setCircular(isCircular);

		boolean isShowLabels = jrPie3DPlot.getShowLabels() == null ? true : jrPie3DPlot.getShowLabels();
		
		if (isShowLabels)
		{
			PieSectionLabelGenerator labelGenerator = (PieSectionLabelGenerator)getLabelGenerator();
			JRItemLabel itemLabel = jrPie3DPlot.getItemLabel();
			if (labelGenerator != null)
			{
				piePlot3D.setLabelGenerator(labelGenerator);
			}
			else if (jrPie3DPlot.getLabelFormat() != null)
			{
				piePlot3D.setLabelGenerator(
					new StandardPieSectionLabelGenerator(jrPie3DPlot.getLabelFormat(), 
							NumberFormat.getNumberInstance(getLocale()),
			                NumberFormat.getPercentInstance(getLocale()))
					);
			}
	//		else if (itemLabel != null && itemLabel.getMask() != null)
	//		{
	//			piePlot3D.setLabelGenerator(
	//				new StandardPieSectionLabelGenerator(itemLabel.getMask())
	//				);
	//		}
			else
			{
				piePlot3D.setLabelGenerator(
						new StandardPieSectionLabelGenerator()
						);
			}
	
			Integer baseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
			JRFont font = itemLabel != null && itemLabel.getFont() != null ? itemLabel.getFont() : null;
			piePlot3D.setLabelFont(getFont(new JRBaseFont(getChart(), null), font, baseFontSize));
	
			if (itemLabel != null && itemLabel.getColor() != null)
			{
				piePlot3D.setLabelPaint(itemLabel.getColor());
			}
			else
			{
				piePlot3D.setLabelPaint(getChart().getForecolor());
			}
	
			if (itemLabel != null && itemLabel.getBackgroundColor() != null)
			{
				piePlot3D.setLabelBackgroundPaint(itemLabel.getBackgroundColor());
			}
			else
			{
				piePlot3D.setLabelBackgroundPaint(getChart().getBackcolor());
			}
		}
		else
		{
			piePlot3D.setLabelGenerator(null);
		}
		
		if (jrPie3DPlot.getLegendLabelFormat() != null)
		{
			piePlot3D.setLegendLabelGenerator(
				new StandardPieSectionLabelGenerator(jrPie3DPlot.getLegendLabelFormat(), 
						NumberFormat.getNumberInstance(getLocale()),
		                NumberFormat.getPercentInstance(getLocale()))
				);
		}
		
		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createPieChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createPieChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				(PieDataset)getDataset(),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());
		PiePlot piePlot = (PiePlot)jfreeChart.getPlot();
		//plot.setStartAngle(290);
		//plot.setDirection(Rotation.CLOCKWISE);
		//plot.setNoDataMessage("No data to display");
		JRPiePlot jrPiePlot = (JRPiePlot)getPlot();
		boolean isCircular = jrPiePlot.getCircular() == null ? true : jrPiePlot.getCircular();
		piePlot.setCircular(isCircular);

		boolean isShowLabels = jrPiePlot.getShowLabels() == null ? true : jrPiePlot.getShowLabels();
		
		if (isShowLabels)
		{
			PieSectionLabelGenerator labelGenerator = (PieSectionLabelGenerator)getLabelGenerator();
			JRItemLabel itemLabel = jrPiePlot.getItemLabel();
	
			if (labelGenerator != null)
			{
				piePlot.setLabelGenerator(labelGenerator);
			}
			else if (jrPiePlot.getLabelFormat() != null)
			{
				piePlot.setLabelGenerator(
					new StandardPieSectionLabelGenerator(jrPiePlot.getLabelFormat(), 
							NumberFormat.getNumberInstance(getLocale()),
			                NumberFormat.getPercentInstance(getLocale()))
					);
			}
	//		else if (itemLabel != null && itemLabel.getMask() != null)
	//		{
	//			piePlot.setLabelGenerator(
	//					new StandardPieSectionLabelGenerator(itemLabel.getMask())
	//					);
	//
	//		}
	
			Integer baseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
			JRFont font = itemLabel != null && itemLabel.getFont() != null ? itemLabel.getFont() : null;
			
			piePlot.setLabelFont(getFont(new JRBaseFont(getChart(), null), font, baseFontSize));
	
			if (itemLabel != null && itemLabel.getColor() != null)
			{
				piePlot.setLabelPaint(itemLabel.getColor());
			}
			else
			{
				piePlot.setLabelPaint(getChart().getForecolor());
			}
	
			if (itemLabel != null && itemLabel.getBackgroundColor() != null)
			{
				piePlot.setLabelBackgroundPaint(itemLabel.getBackgroundColor());
			}
			else
			{
				piePlot.setLabelBackgroundPaint(getChart().getBackcolor());
			}
		}
		else
		{
			piePlot.setLabelGenerator(null);
		}
		
		
		if (jrPiePlot.getLegendLabelFormat() != null)
		{
			piePlot.setLegendLabelGenerator(
				new StandardPieSectionLabelGenerator(jrPiePlot.getLegendLabelFormat(), 
						NumberFormat.getNumberInstance(getLocale()),
		                NumberFormat.getPercentInstance(getLocale()))
				);
		}
		
		return jfreeChart;
	}


	protected JFreeChart createScatterChart() throws JRException 
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart = 
			ChartFactory.createScatterPlot(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRScatterPlot)getPlot()).getXAxisLabelExpression()),
				evaluateTextExpression(((JRScatterPlot)getPlot()).getYAxisLabelExpression()),
				(XYDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false);

		configureChart(jfreeChart, getPlot());
		XYLineAndShapeRenderer plotRenderer = (XYLineAndShapeRenderer) ((XYPlot)jfreeChart.getPlot()).getRenderer();

		JRScatterPlot scatterPlot = (JRScatterPlot) getPlot();
		boolean isShowLines = scatterPlot.getShowLines() == null ? true : scatterPlot.getShowLines();
		boolean isShowShapes = scatterPlot.getShowShapes() == null ? true : scatterPlot.getShowShapes();
		
		plotRenderer.setBaseLinesVisible(isShowLines);
		plotRenderer.setBaseShapesVisible(isShowShapes);

		// Handle the axis formating for the category axis
		configureAxis(jfreeChart.getXYPlot().getDomainAxis(), scatterPlot.getXAxisLabelFont(),
				scatterPlot.getXAxisLabelColor(), scatterPlot.getXAxisTickLabelFont(),
				scatterPlot.getXAxisTickLabelColor(), scatterPlot.getXAxisTickLabelMask(), scatterPlot.getXAxisVerticalTickLabels(),
				scatterPlot.getOwnXAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(scatterPlot.getDomainAxisMinValueExpression()), 
				(Comparable<?>)evaluateExpression(scatterPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(jfreeChart.getXYPlot().getRangeAxis(), scatterPlot.getYAxisLabelFont(),
				scatterPlot.getYAxisLabelColor(), scatterPlot.getYAxisTickLabelFont(),
				scatterPlot.getYAxisTickLabelColor(), scatterPlot.getYAxisTickLabelMask(), scatterPlot.getYAxisVerticalTickLabels(),
				scatterPlot.getOwnYAxisLineColor(), true, 
				(Comparable<?>)evaluateExpression(scatterPlot.getRangeAxisMinValueExpression()), 
				(Comparable<?>)evaluateExpression(scatterPlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createStackedBar3DChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createStackedBarChart3D(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRBar3DPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRBar3DPlot)getPlot()).getValueAxisLabelExpression()),
				(CategoryDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());

		CategoryPlot categoryPlot = (CategoryPlot)jfreeChart.getPlot();
		JRBar3DPlot bar3DPlot = (JRBar3DPlot)getPlot();

		StackedBarRenderer3D stackedBarRenderer3D =
			new StackedBarRenderer3D(
				bar3DPlot.getXOffsetDouble() == null ? StackedBarRenderer3D.DEFAULT_X_OFFSET : bar3DPlot.getXOffsetDouble(),
				bar3DPlot.getYOffsetDouble() == null ? StackedBarRenderer3D.DEFAULT_Y_OFFSET : bar3DPlot.getYOffsetDouble()
				);

		boolean isShowLabels = bar3DPlot.getShowLabels() == null ? false : bar3DPlot.getShowLabels();
		stackedBarRenderer3D.setBaseItemLabelsVisible(isShowLabels);
		if(isShowLabels)
		{
			JRItemLabel itemLabel = bar3DPlot.getItemLabel();

			stackedBarRenderer3D.setBaseItemLabelFont(
				getFontUtil().getAwtFont(
					getFont(itemLabel == null ? null : itemLabel.getFont()), 
					getLocale()
					)
				);
			
			if(itemLabel != null)
			{
				if(itemLabel.getColor() != null)
				{
					stackedBarRenderer3D.setBaseItemLabelPaint(itemLabel.getColor());
				}
				else
				{
					stackedBarRenderer3D.setBaseItemLabelPaint(getChart().getForecolor());
				}
//				categoryRenderer.setBaseFillPaint(itemLabel.getBackgroundColor());
//				if(itemLabel.getMask() != null)
//				{
//					barRenderer3D.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator(
//							StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, 
//							new DecimalFormat(itemLabel.getMask())));
//				}
//				else
//				{
				stackedBarRenderer3D.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
//				}
			}
			else
			{
				stackedBarRenderer3D.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
				stackedBarRenderer3D.setBaseItemLabelPaint(getChart().getForecolor());
			}
		}
		categoryPlot.setRenderer(stackedBarRenderer3D);

		// Handle the axis formating for the category axis
		configureAxis(categoryPlot.getDomainAxis(), bar3DPlot.getCategoryAxisLabelFont(),
				bar3DPlot.getCategoryAxisLabelColor(), bar3DPlot.getCategoryAxisTickLabelFont(),
				bar3DPlot.getCategoryAxisTickLabelColor(), bar3DPlot.getCategoryAxisTickLabelMask(), bar3DPlot.getCategoryAxisVerticalTickLabels(),
				bar3DPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(bar3DPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(bar3DPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(categoryPlot.getRangeAxis(), bar3DPlot.getValueAxisLabelFont(),
				bar3DPlot.getValueAxisLabelColor(), bar3DPlot.getValueAxisTickLabelFont(),
				bar3DPlot.getValueAxisTickLabelColor(), bar3DPlot.getValueAxisTickLabelMask(), bar3DPlot.getValueAxisVerticalTickLabels(),
				bar3DPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(bar3DPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(bar3DPlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createStackedBarChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createStackedBarChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getValueAxisLabelExpression()),
				(CategoryDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());

		CategoryPlot categoryPlot = (CategoryPlot)jfreeChart.getPlot();
		JRBarPlot barPlot = (JRBarPlot)getPlot();
		//plot.setNoDataMessage("No data to display");
		boolean isShowTickMarks = barPlot.getShowTickMarks() == null ? true : barPlot.getShowTickMarks();
		boolean isShowTickLabels = barPlot.getShowTickLabels() == null ? true : barPlot.getShowTickLabels();
		boolean isShowLabels = barPlot.getShowLabels() == null ? false : barPlot.getShowLabels();
		
		categoryPlot.getDomainAxis().setTickMarksVisible(isShowTickMarks);
		categoryPlot.getDomainAxis().setTickLabelsVisible(isShowTickLabels);
		((NumberAxis)categoryPlot.getRangeAxis()).setTickMarksVisible(isShowTickMarks);
		((NumberAxis)categoryPlot.getRangeAxis()).setTickLabelsVisible(isShowTickLabels);

		BarRenderer categoryRenderer = (BarRenderer)categoryPlot.getRenderer();
		categoryRenderer.setBaseItemLabelsVisible( isShowLabels );
		Comparable<?> rangeAxisMaxValue = (Comparable<?>)evaluateExpression(barPlot.getRangeAxisMaxValueExpression());
		if(isShowLabels)
		{
			if (rangeAxisMaxValue == null)
			{
				//in case the bars are horizontal and there was no range max value specified, 
				//we try to make the axis a little longer for labels to fit on the plot
				Axis axis = categoryPlot.getRangeAxis();
				if (axis instanceof ValueAxis)
				{
					if(!(axis instanceof DateAxis))
					{
						float rangeAxisMaxRatio = 1f;
						
						if (barPlot.getOrientationValue() == PlotOrientationEnum.HORIZONTAL)
						{
							rangeAxisMaxRatio = 
								JRPropertiesUtil.getInstance(getChartContext().getJasperReportsContext()).getFloatProperty(
									getChart(), "net.sf.jasperreports.chart.bar.horizontal.range.max.value.ratio", 1.25f
									);
						}
						else
						{
							rangeAxisMaxRatio = 
								JRPropertiesUtil.getInstance(getChartContext().getJasperReportsContext()).getFloatProperty(
									getChart(), "net.sf.jasperreports.chart.bar.vertical.range.max.value.ratio", 1.1f
									);
						}
						
						((ValueAxis)axis).setUpperBound(((ValueAxis)axis).getUpperBound() * rangeAxisMaxRatio);
					}
				}
			}

			JRItemLabel itemLabel = barPlot.getItemLabel();
			
			categoryRenderer.setBaseItemLabelFont(
					getFontUtil().getAwtFont(
					getFont(itemLabel == null ? null : itemLabel.getFont()), 
					getLocale()
					)
				);
			
			if(itemLabel != null)
			{
				if(itemLabel.getColor() != null)
				{
					categoryRenderer.setBaseItemLabelPaint(itemLabel.getColor());
				}
				else
				{
					categoryRenderer.setBaseItemLabelPaint(getChart().getForecolor());
				}
//				categoryRenderer.setBaseFillPaint(itemLabel.getBackgroundColor());
//				if(itemLabel.getMask() != null)
//				{
//					categoryRenderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator(
//							StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, 
//							new DecimalFormat(itemLabel.getMask())));
//				}
//				else
//				{
					categoryRenderer.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
//				}
			}
			else
			{
				categoryRenderer.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
				categoryRenderer.setBaseItemLabelPaint(getChart().getForecolor());
			}
		}
		categoryRenderer.setShadowVisible(false);

		// Handle the axis formating for the category axis
		configureAxis(categoryPlot.getDomainAxis(), barPlot.getCategoryAxisLabelFont(),
				barPlot.getCategoryAxisLabelColor(), barPlot.getCategoryAxisTickLabelFont(),
				barPlot.getCategoryAxisTickLabelColor(), barPlot.getCategoryAxisTickLabelMask(), barPlot.getCategoryAxisVerticalTickLabels(),
				barPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(barPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(barPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(categoryPlot.getRangeAxis(), barPlot.getValueAxisLabelFont(),
				barPlot.getValueAxisLabelColor(), barPlot.getValueAxisTickLabelFont(),
				barPlot.getValueAxisTickLabelColor(), barPlot.getValueAxisTickLabelMask(), barPlot.getValueAxisVerticalTickLabels(),
				barPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(barPlot.getRangeAxisMinValueExpression()),
				rangeAxisMaxValue);

		return jfreeChart;
	}

	/**
	 *
	 */
	protected JFreeChart createStackedAreaChart() throws JRException
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createStackedAreaChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRAreaPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRAreaPlot)getPlot()).getValueAxisLabelExpression()),
				(CategoryDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());
		JRAreaPlot areaPlot = (JRAreaPlot)getPlot();

		// Handle the axis formating for the category axis
		configureAxis(((CategoryPlot)jfreeChart.getPlot()).getDomainAxis(), areaPlot.getCategoryAxisLabelFont(),
				areaPlot.getCategoryAxisLabelColor(), areaPlot.getCategoryAxisTickLabelFont(),
				areaPlot.getCategoryAxisTickLabelColor(), areaPlot.getCategoryAxisTickLabelMask(), areaPlot.getCategoryAxisVerticalTickLabels(),
				areaPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(areaPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(areaPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(((CategoryPlot)jfreeChart.getPlot()).getRangeAxis(), areaPlot.getValueAxisLabelFont(),
				areaPlot.getValueAxisLabelColor(), areaPlot.getValueAxisTickLabelFont(),
				areaPlot.getValueAxisTickLabelColor(), areaPlot.getValueAxisTickLabelMask(), areaPlot.getValueAxisVerticalTickLabels(),
				areaPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(areaPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(areaPlot.getRangeAxisMaxValueExpression()));

		((CategoryPlot)jfreeChart.getPlot()).getDomainAxis().setCategoryMargin(0);
		
		return jfreeChart;
	}

	protected JFreeChart createXyAreaChart() throws JRException 
	{
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart = 
			ChartFactory.createXYAreaChart(
				evaluateTextExpression(getChart().getTitleExpression() ),
				evaluateTextExpression(((JRAreaPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRAreaPlot)getPlot()).getValueAxisLabelExpression()),
				(XYDataset)getDataset(),
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());
		JRAreaPlot areaPlot = (JRAreaPlot)getPlot();

		// Handle the axis formating for the category axis
		configureAxis(jfreeChart.getXYPlot().getDomainAxis(), areaPlot.getCategoryAxisLabelFont(),
				areaPlot.getCategoryAxisLabelColor(), areaPlot.getCategoryAxisTickLabelFont(),
				areaPlot.getCategoryAxisTickLabelColor(), areaPlot.getCategoryAxisTickLabelMask(), areaPlot.getCategoryAxisVerticalTickLabels(),
				areaPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(areaPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(areaPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(jfreeChart.getXYPlot().getRangeAxis(), areaPlot.getValueAxisLabelFont(),
				areaPlot.getValueAxisLabelColor(), areaPlot.getValueAxisTickLabelFont(),
				areaPlot.getValueAxisTickLabelColor(), areaPlot.getValueAxisTickLabelMask(), areaPlot.getValueAxisVerticalTickLabels(),
				areaPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(areaPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(areaPlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}


	/**
	 *
	 */
	protected JFreeChart createXYBarChart() throws JRException
	{
		IntervalXYDataset tmpDataset = (IntervalXYDataset)getDataset();

		boolean isDate = true;
		if ( getChart().getDataset().getDatasetType() == JRChartDataset.XY_DATASET ){
			isDate = false;
		}

		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createXYBarChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getCategoryAxisLabelExpression()),
				isDate,
				evaluateTextExpression(((JRBarPlot)getPlot()).getValueAxisLabelExpression()),
				tmpDataset,
				ChartUtil.getPlotOrientation(getPlot().getOrientationValue()),
				isShowLegend(),
				true,
				false
				);

		configureChart(jfreeChart, getPlot());

		XYPlot xyPlot = (XYPlot)jfreeChart.getPlot();
		//plot.setNoDataMessage("No data to display");
//		((XYPlot)plot.getDomainAxis()).setTickMarksVisible(
//			((JRBarPlot)getPlot()).isShowTickMarks()
//			);
//		((CategoryAxis)plot.getDomainAxis()).setTickLabelsVisible(
//				((JRBarPlot)getPlot()).isShowTickLabels()
//				);
//		((NumberAxis)plot.getRangeAxis()).setTickMarksVisible(
//				((JRBarPlot)getPlot()).isShowTickMarks()
//				);
//		((NumberAxis)plot.getRangeAxis()).setTickLabelsVisible(
//				((JRBarPlot)getPlot()).isShowTickLabels()
//				);


		XYBarRenderer itemRenderer = (XYBarRenderer)xyPlot.getRenderer();
		itemRenderer.setBaseItemLabelGenerator((XYItemLabelGenerator)getLabelGenerator());
		itemRenderer.setShadowVisible(false);

		JRBarPlot barPlot = (JRBarPlot)getPlot();
		boolean isShowLabels = barPlot.getShowLabels() == null ? false : barPlot.getShowLabels();
		
		itemRenderer.setBaseItemLabelsVisible( isShowLabels );

		// Handle the axis formating for the category axis
		configureAxis(xyPlot.getDomainAxis(), barPlot.getCategoryAxisLabelFont(),
				barPlot.getCategoryAxisLabelColor(), barPlot.getCategoryAxisTickLabelFont(),
				barPlot.getCategoryAxisTickLabelColor(), barPlot.getCategoryAxisTickLabelMask(), barPlot.getCategoryAxisVerticalTickLabels(),
				barPlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(barPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(barPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(xyPlot.getRangeAxis(), barPlot.getValueAxisLabelFont(),
				barPlot.getValueAxisLabelColor(), barPlot.getValueAxisTickLabelFont(),
				barPlot.getValueAxisTickLabelColor(), barPlot.getValueAxisTickLabelMask(), barPlot.getValueAxisVerticalTickLabels(),
				barPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(barPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(barPlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}


	protected JFreeChart createXyLineChart() throws JRException 
	{
		JRLinePlot linePlot = (JRLinePlot) getPlot();

		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart = 
			ChartFactory.createXYLineChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(linePlot.getCategoryAxisLabelExpression()),
				evaluateTextExpression(linePlot.getValueAxisLabelExpression()),
				(XYDataset)getDataset(),
				ChartUtil.getPlotOrientation(linePlot.getOrientationValue()),
				isShowLegend(),
				true,
				false);

		configureChart(jfreeChart, getPlot());

		// Handle the axis formating for the category axis
		configureAxis(jfreeChart.getXYPlot().getDomainAxis(), linePlot.getCategoryAxisLabelFont(),
				linePlot.getCategoryAxisLabelColor(), linePlot.getCategoryAxisTickLabelFont(),
				linePlot.getCategoryAxisTickLabelColor(), linePlot.getCategoryAxisTickLabelMask(), linePlot.getCategoryAxisVerticalTickLabels(),
				linePlot.getOwnCategoryAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(linePlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(linePlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(jfreeChart.getXYPlot().getRangeAxis(), linePlot.getValueAxisLabelFont(),
				linePlot.getValueAxisLabelColor(), linePlot.getValueAxisTickLabelFont(),
				linePlot.getValueAxisTickLabelColor(), linePlot.getValueAxisTickLabelMask(), linePlot.getValueAxisVerticalTickLabels(),
				linePlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(linePlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(linePlot.getRangeAxisMaxValueExpression()));

		XYLineAndShapeRenderer lineRenderer = (XYLineAndShapeRenderer) jfreeChart.getXYPlot().getRenderer();
		boolean isShowShapes = linePlot.getShowShapes() == null ? true : linePlot.getShowShapes();
		boolean isShowLines = linePlot.getShowLines() == null ? true : linePlot.getShowLines();
		lineRenderer.setBaseShapesVisible(isShowShapes);
		lineRenderer.setBaseLinesVisible(isShowLines);

		return jfreeChart;
	}

	protected JFreeChart createTimeSeriesChart() throws JRException 
	{
		String timeAxisLabel = evaluateTextExpression(((JRTimeSeriesPlot)getPlot()).getTimeAxisLabelExpression());
		String valueAxisLabel = evaluateTextExpression(((JRTimeSeriesPlot)getPlot()).getValueAxisLabelExpression());

		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart = 
			ChartFactory.createTimeSeriesChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				timeAxisLabel,
				valueAxisLabel,
				(TimeSeriesCollection)getDataset(),
				isShowLegend(),
				true,
				false );

		configureChart(jfreeChart, getPlot());

		XYPlot xyPlot = (XYPlot)jfreeChart.getPlot();
		JRTimeSeriesPlot timeSeriesPlot = (JRTimeSeriesPlot)getPlot();
		
		XYLineAndShapeRenderer lineRenderer = (XYLineAndShapeRenderer)xyPlot.getRenderer();
		
		boolean isShowShapes = timeSeriesPlot.getShowShapes() == null ? true : timeSeriesPlot.getShowShapes();
		boolean isShowLines = timeSeriesPlot.getShowLines() == null ? true : timeSeriesPlot.getShowLines();
		lineRenderer.setBaseLinesVisible(isShowLines);
		lineRenderer.setBaseShapesVisible(isShowShapes);
		
		// Handle the axis formating for the category axis
		configureAxis(xyPlot.getDomainAxis(), timeSeriesPlot.getTimeAxisLabelFont(),
				timeSeriesPlot.getTimeAxisLabelColor(), timeSeriesPlot.getTimeAxisTickLabelFont(),
				timeSeriesPlot.getTimeAxisTickLabelColor(), timeSeriesPlot.getTimeAxisTickLabelMask(), timeSeriesPlot.getTimeAxisVerticalTickLabels(),
				timeSeriesPlot.getOwnTimeAxisLineColor(), false,
				(Comparable<?>)evaluateExpression(timeSeriesPlot.getDomainAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(timeSeriesPlot.getDomainAxisMaxValueExpression()));

		// Handle the axis formating for the value axis
		configureAxis(xyPlot.getRangeAxis(), timeSeriesPlot.getValueAxisLabelFont(),
				timeSeriesPlot.getValueAxisLabelColor(), timeSeriesPlot.getValueAxisTickLabelFont(),
				timeSeriesPlot.getValueAxisTickLabelColor(), timeSeriesPlot.getValueAxisTickLabelMask(), timeSeriesPlot.getValueAxisVerticalTickLabels(),
				timeSeriesPlot.getOwnValueAxisLineColor(), true,
				(Comparable<?>)evaluateExpression(timeSeriesPlot.getRangeAxisMinValueExpression()),
				(Comparable<?>)evaluateExpression(timeSeriesPlot.getRangeAxisMaxValueExpression()));

		return jfreeChart;
	}

	/**
	 *
	 */
	protected JFreeChart createGanttChart() throws JRException
	{
		//FIXMECHART legend/tooltip/url should come from plot?
		
		ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
		JFreeChart jfreeChart =
			ChartFactory.createGanttChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getCategoryAxisLabelExpression()),
				evaluateTextExpression(((JRBarPlot)getPlot()).getValueAxisLabelExpression()),
				(GanttCategoryDataset)getDataset(),
				isShowLegend(),
				true,  //FIXMECHART tooltip: I guess BarPlot is not the best for gantt
				false
				);

		configureChart(jfreeChart, getPlot());
		
		CategoryPlot categoryPlot = (CategoryPlot)jfreeChart.getPlot();
		//plot.setNoDataMessage("No data to display");
		
		JRBarPlot barPlot = (JRBarPlot)getPlot();
		boolean isShowTickMarks = barPlot.getShowTickMarks() == null ? true : barPlot.getShowTickMarks();
		boolean isShowTickLabels = barPlot.getShowTickLabels() == null ? true : barPlot.getShowTickLabels();
		boolean isShowLabels = barPlot.getShowLabels() == null ? false : barPlot.getShowLabels();
		
		categoryPlot.getDomainAxis().setTickMarksVisible(isShowTickMarks);
		categoryPlot.getDomainAxis().setTickLabelsVisible(isShowTickLabels);
		// Handle the axis formating for the category axis
		configureAxis(
			categoryPlot.getDomainAxis(), barPlot.getCategoryAxisLabelFont(),
			barPlot.getCategoryAxisLabelColor(), barPlot.getCategoryAxisTickLabelFont(),
			barPlot.getCategoryAxisTickLabelColor(), barPlot.getCategoryAxisTickLabelMask(), barPlot.getCategoryAxisVerticalTickLabels(),
			barPlot.getOwnCategoryAxisLineColor(), false, null, null
			);
		((DateAxis)categoryPlot.getRangeAxis()).setTickMarksVisible(isShowTickMarks);
		((DateAxis)categoryPlot.getRangeAxis()).setTickLabelsVisible(isShowTickLabels);
		// Handle the axis formating for the value axis
		configureAxis(
			categoryPlot.getRangeAxis(), barPlot.getValueAxisLabelFont(),
			barPlot.getValueAxisLabelColor(), barPlot.getValueAxisTickLabelFont(),
			barPlot.getValueAxisTickLabelColor(), barPlot.getValueAxisTickLabelMask(), barPlot.getValueAxisVerticalTickLabels(),
			barPlot.getOwnValueAxisLineColor(), true,
			(Comparable<?>)evaluateExpression(barPlot.getRangeAxisMinValueExpression()),
			(Comparable<?>)evaluateExpression(barPlot.getRangeAxisMaxValueExpression()));

		BarRenderer categoryRenderer = (BarRenderer)categoryPlot.getRenderer();
		categoryRenderer.setBaseItemLabelGenerator((CategoryItemLabelGenerator)getLabelGenerator());
		categoryRenderer.setBaseItemLabelsVisible(isShowLabels);
		categoryRenderer.setShadowVisible(false);

		return jfreeChart;
	}


	/**
	 * Converts a JasperReport data range into one understood by JFreeChart.
	 *
	 * @param dataRange the JasperReport version of the range
	 * @return the JFreeChart version of the range
	 * @throws JRException thrown when the low value of the range is greater than the
	 * 						high value
	 */
	protected Range convertRange(JRDataRange dataRange) throws JRException
	{
		if (dataRange == null)
			return null;

		Number low = (Number)evaluateExpression(dataRange.getLowExpression());
		Number high = (Number)evaluateExpression(dataRange.getHighExpression());
		return new Range( low != null ? low.doubleValue() : 0.0,
								 high != null ? high.doubleValue() : 100.0);
	}

	/**
	 * Converts a JasperReports meter interval to one that JFreeChart understands.
	 *
	 * @param interval the JasperReports definition of an interval
	 * @return the JFreeChart version of the same interval
	 * @throws JRException thrown when the interval contains an invalid range
	 */
	protected MeterInterval convertInterval(JRMeterInterval interval) throws JRException
	{
		String label = interval.getLabel();
		if (label == null)
			label = "";

		Range range = convertRange(interval.getDataRange());

		Color color = interval.getBackgroundColor() != null ? interval.getBackgroundColor() : (Color)ChartThemesConstants.TRANSPARENT_PAINT;
		float[] components = color.getRGBColorComponents(null);

		float alpha = (float)(interval.getAlphaDouble() == null ? JRMeterInterval.DEFAULT_TRANSPARENCY : interval.getAlphaDouble());
		Color alphaColor = new Color(components[0], components[1], components[2], alpha);

		return new MeterInterval(label, range, alphaColor, null, alphaColor);
	}

	/**
	 * Build and configure a meter chart.
	 */
	protected JFreeChart createMeterChart() throws JRException 
	{
		// Start by creating the plot that will hold the meter
		MeterPlot chartPlot = new MeterPlot((ValueDataset)getDataset());
		JRMeterPlot jrPlot = (JRMeterPlot)getPlot();

		// Set the shape
		MeterShapeEnum shape = jrPlot.getShapeValue() == null ? MeterShapeEnum.PIE : jrPlot.getShapeValue();
		
		switch(shape)
		{
			case CHORD:
				chartPlot.setDialShape(DialShape.CHORD);
				break;
			case CIRCLE:
				chartPlot.setDialShape(DialShape.CIRCLE);
				break;
			case DIAL:
				return createDialChart();
			case PIE:
			default:
				chartPlot.setDialShape(DialShape.PIE);
		}

		// Set the meter's range
		chartPlot.setRange(convertRange(jrPlot.getDataRange()));

		// Set the size of the meter
		int meterAngle = jrPlot.getMeterAngleInteger() == null ? 180 : jrPlot.getMeterAngleInteger();
		chartPlot.setMeterAngle(meterAngle);

		// Set the units - this is just a string that will be shown next to the
		// value
		String units = jrPlot.getUnits();
		if (units != null && units.length() > 0)
			chartPlot.setUnits(units);

		// Set the spacing between ticks.  I hate the name "tickSize" since to me it
		// implies I am changing the size of the tick, not the spacing between them.
		double tickInterval = jrPlot.getTickIntervalDouble() == null ? 10.0 : jrPlot.getTickIntervalDouble();
		chartPlot.setTickSize(tickInterval);

		// Set all the colors we support
		Color color = jrPlot.getMeterBackgroundColor();
		if (color != null)
			chartPlot.setDialBackgroundPaint(color);

		color = jrPlot.getNeedleColor();
		if (color != null)
			chartPlot.setNeedlePaint(color);

		JRFont tickLabelFont = jrPlot.getTickLabelFont();
		Integer defaultBaseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
		Font themeTickLabelFont = getFont((JRFont)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_TICK_LABEL_FONT), tickLabelFont, defaultBaseFontSize);
		chartPlot.setTickLabelFont(themeTickLabelFont);
		
		// localizing the default format, can be overridden by display.getMask()
		chartPlot.setTickLabelFormat(NumberFormat.getInstance(getLocale()));
		
		JRValueDisplay display = jrPlot.getValueDisplay();
		JRFont displayFont = display.getFont();
		Font themeDisplayFont = getFont((JRFont)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_DISPLAY_FONT), displayFont, defaultBaseFontSize);
		// Set how the value is displayed.
		if (display != null)
		{
			if (display.getColor() != null)
			{
				chartPlot.setValuePaint(display.getColor());
			}

			if (display.getMask() != null)
			{
				chartPlot.setTickLabelFormat(new DecimalFormat(display.getMask(),
						DecimalFormatSymbols.getInstance(getLocale())));
			}
			if (display.getFont() != null)
			{
				chartPlot.setValueFont(themeDisplayFont);
			}

		}

		color = jrPlot.getTickColor();
		if (color != null)
			chartPlot.setTickPaint(color);

		// Now define all of the intervals, setting their range and color
		List<JRMeterInterval> intervals = jrPlot.getIntervals();
		if (intervals != null)
		{
			Iterator<JRMeterInterval> iter = intervals.iterator();
			while (iter.hasNext())
			{
				JRMeterInterval interval = iter.next();
				if (interval != null)
					chartPlot.addInterval(convertInterval(interval));
			}
		}

		// Actually create the chart around the plot
		JFreeChart jfreeChart = 
			new JFreeChart(
				evaluateTextExpression(getChart().getTitleExpression()),
				null, 
				chartPlot, 
				isShowLegend()
				);

		// Set all the generic options
		configureChart(jfreeChart, getPlot());

		return jfreeChart;
	}

	/**
	 * Build and run a thermometer chart.  JFreeChart thermometer charts have some
	 * limitations.  They always have a maximum of three ranges, and the colors of those
	 * ranges seems to be fixed.
	 */
	protected JFreeChart createThermometerChart() throws JRException 
	{
		JRThermometerPlot jrPlot = (JRThermometerPlot)getPlot();

		// Create the plot that will hold the thermometer.
		ThermometerPlot chartPlot = new ThermometerPlot((ValueDataset)getDataset());
		
		ChartUtil chartUtil = ChartUtil.getInstance(getChartContext().getJasperReportsContext());
		// setting localized range axis formatters
		chartPlot.getRangeAxis().setStandardTickUnits(chartUtil.createIntegerTickUnits(getLocale()));

		Range range = convertRange(jrPlot.getDataRange());

		// Set the boundary of the thermomoter
		chartPlot.setLowerBound(range.getLowerBound());
		chartPlot.setUpperBound(range.getUpperBound());

		// Units can only be Fahrenheit, Celsius or none, so turn off for now.
		chartPlot.setUnits(ThermometerPlot.UNITS_NONE);

		// Set the color of the mercury.  Only used when the value is outside of
		// any defined ranges.
		Color color = jrPlot.getMercuryColor();
		if (color != null)
		{
			chartPlot.setMercuryPaint(color);
			chartPlot.setUseSubrangePaint(false);
		}
		
		// localizing the default format, can be overridden by display.getMask()
		chartPlot.setValueFormat(NumberFormat.getNumberInstance(getLocale()));

		// Set the formatting of the value display
		JRValueDisplay display = jrPlot.getValueDisplay();
		if (display != null)
		{
			if (display.getColor() != null)
			{
				chartPlot.setValuePaint(display.getColor());
			}
			if (display.getMask() != null)
			{
				chartPlot.setValueFormat(new DecimalFormat(display.getMask(),
						DecimalFormatSymbols.getInstance(getLocale())));
			}
			if (display.getFont() != null)
			{
//				chartPlot.setValueFont(getFontUtil().getAwtFont(display.getFont()));
			}
		}

		// Set the location of where the value is displayed
		ValueLocationEnum valueLocation = jrPlot.getValueLocationValue();
		switch (valueLocation)
		{
		  case NONE:
			 chartPlot.setValueLocation(ThermometerPlot.NONE);
			 break;
		  case LEFT:
			 chartPlot.setValueLocation(ThermometerPlot.LEFT);
			 break;
		  case RIGHT:
			 chartPlot.setValueLocation(ThermometerPlot.RIGHT);
			 break;
		  case BULB:
		  default:
			 chartPlot.setValueLocation(ThermometerPlot.BULB);
			 break;
		}

		// Define the three ranges
		range = convertRange(jrPlot.getLowRange());
		if (range != null)
		{
			chartPlot.setSubrangeInfo(2, range.getLowerBound(), range.getUpperBound());
		}

		range = convertRange(jrPlot.getMediumRange());
		if (range != null)
		{
			chartPlot.setSubrangeInfo(1, range.getLowerBound(), range.getUpperBound());
		}

		range = convertRange(jrPlot.getHighRange());
		if (range != null)
		{
			chartPlot.setSubrangeInfo(0, range.getLowerBound(), range.getUpperBound());
		}

		// Build a chart around this plot
		JFreeChart jfreeChart = 
				new JFreeChart(
					evaluateTextExpression(getChart().getTitleExpression()),
					null, 
					chartPlot, 
					isShowLegend()
					);

		// Set the generic options
		configureChart(jfreeChart, getPlot());
		
		return jfreeChart;
	}

	/**
	 *
	 */
	protected JFreeChart createDialChart() throws JRException
	{

		JRMeterPlot jrPlot = (JRMeterPlot)getPlot();

		// get data for diagrams
		DialPlot dialPlot = new DialPlot();
		dialPlot.setDataset((ValueDataset)getDataset());
		StandardDialFrame dialFrame = new StandardDialFrame();
		dialPlot.setDialFrame(dialFrame);

		DialBackground db = new DialBackground(jrPlot.getBackcolor());
		dialPlot.setBackground(db);
		Range range = convertRange(jrPlot.getDataRange());
		//double bound = Math.max(Math.abs(range.getUpperBound()), Math.abs(range.getLowerBound()));
		int tickCount = jrPlot.getTickCount() != null && jrPlot.getTickCount() > 1 ? jrPlot.getTickCount() : 7;
		StandardDialScale scale =
			new StandardDialScale(
				range.getLowerBound(),
				range.getUpperBound(),
				225,
				-270,
				(range.getUpperBound() - range.getLowerBound())/(tickCount-1),
				15
				);
		scale.setTickRadius(0.9);
		scale.setTickLabelOffset(0.16);
		JRFont tickLabelFont = jrPlot.getTickLabelFont();
		Integer defaultBaseFontSize = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BASEFONT_SIZE);
		Font themeTickLabelFont = getFont((JRFont)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_TICK_LABEL_FONT), tickLabelFont, defaultBaseFontSize);
		scale.setTickLabelFont(themeTickLabelFont);
		scale.setMajorTickStroke(new BasicStroke(1f));
		scale.setMinorTickStroke(new BasicStroke(0.3f));
		scale.setMajorTickPaint(jrPlot.getTickColor());
		scale.setMinorTickPaint(jrPlot.getTickColor());

		scale.setTickLabelsVisible(true);
		scale.setFirstTickLabelVisible(true);
		
		// localizing the default tick label formatter
		scale.setTickLabelFormatter(new DecimalFormat("0.0", DecimalFormatSymbols.getInstance(getLocale())));

		dialPlot.addScale(0, scale);
		List<JRMeterInterval> intervals = jrPlot.getIntervals();
		if (intervals != null && intervals.size() > 0)
		{
			int size = Math.min(3, intervals.size());
			int colorStep = 0;
			if (size > 0)
				colorStep = 255 / size;
			
			for (int i = 0; i < size; i++)
			{
				JRMeterInterval interval = intervals.get(i);
				Range intervalRange = convertRange(interval.getDataRange());

				Color color = new Color(255 - colorStep * i, 0 + colorStep * i, 0);
				
				StandardDialRange dialRange =
					new StandardDialRange(
						intervalRange.getLowerBound(),
						intervalRange.getUpperBound(),
						interval.getBackgroundColor() == null
							? color
							: interval.getBackgroundColor()
						);
				dialRange.setInnerRadius(0.41);
				dialRange.setOuterRadius(0.41);
				dialPlot.addLayer(dialRange);
			}
		}

		JRValueDisplay display = jrPlot.getValueDisplay();
		String displayVisibility = display != null && getChart().hasProperties() 
			? getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_DIAL_VALUE_DISPLAY_VISIBLE) : "false";

		if (Boolean.parseBoolean(displayVisibility))
		{
			DialValueIndicator dvi = new DialValueIndicator(0);
			dvi.setBackgroundPaint(ChartThemesConstants.TRANSPARENT_PAINT);
//			dvi.setFont(getFontUtil().getAwtFont(jrFont).deriveFont(10f).deriveFont(Font.BOLD));
			dvi.setOutlinePaint(ChartThemesConstants.TRANSPARENT_PAINT);
			dvi.setPaint(Color.WHITE);

			String pattern = display.getMask() != null ? display.getMask() : "#,##0.####";
			if (pattern != null)
				dvi.setNumberFormat( new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(getLocale())));
			dvi.setRadius(0.15);
			dvi.setValueAnchor(RectangleAnchor.CENTER);
			dvi.setTextAnchor(TextAnchor.CENTER);
			//dvi.setTemplateValue(Double.valueOf(getDialTickValue(dialPlot.getValue(0),dialUnitScale)));
			dialPlot.addLayer(dvi);
		}
		String label = getChart().hasProperties() ?
				getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_DIAL_LABEL) : null;
		
		if (label != null)
		{
			JRFont displayFont = jrPlot.getValueDisplay().getFont();
			Font themeDisplayFont = getFont((JRFont)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_DISPLAY_FONT), displayFont, defaultBaseFontSize);
			String[] textLines = label.split("\\n");
			for (int i = 0; i < textLines.length; i++)
			{
				DialTextAnnotation dialAnnotation = new DialTextAnnotation(textLines[i]);
				dialAnnotation.setFont(themeDisplayFont);
				dialAnnotation.setPaint(jrPlot.getValueDisplay().getColor());
				dialAnnotation.setRadius(Math.sin(Math.PI/4.0) + i/10.0);
				dialAnnotation.setAnchor(TextAnchor.CENTER);
				dialPlot.addLayer(dialAnnotation);
			}
		}

		DialPointer needle = new DialPointer.Pointer();

		needle.setVisible(true);
		needle.setRadius(0.91);
		dialPlot.addLayer(needle);

		DialCap cap = new DialCap();
		cap.setRadius(0.05);
		cap.setFillPaint(Color.DARK_GRAY);
		cap.setOutlinePaint(Color.GRAY);
		cap.setOutlineStroke(new BasicStroke(0.5f));
		dialPlot.setCap(cap);

		JFreeChart jfreeChart =
		new JFreeChart(
			evaluateTextExpression(getChart().getTitleExpression()),
			null,
			dialPlot,
			isShowLegend()
			);

		// Set all the generic options
		configureChart(jfreeChart, getPlot());

		return jfreeChart;

	}

	/**
	 * Specifies the axis location.
	 * It has to be overridden for child themes with another default axis location
	 */
	protected AxisLocation getChartAxisLocation(JRChartAxis chartAxis)
	{
		if (chartAxis.getPositionValue() != null)
		{
			switch (chartAxis.getPositionValue())
			{
				case RIGHT_OR_BOTTOM :
					return AxisLocation.BOTTOM_OR_RIGHT;
				default:
					return AxisLocation.TOP_OR_LEFT;
			}
		}
		else
		{
			return (AxisLocation)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LOCATION);
		}
	}

	/**
	 *
	 */
	private static RectangleEdge getEdge(EdgeEnum position, RectangleEdge defaultPosition)
	{
		RectangleEdge edge = defaultPosition;
		if (position != null)
		{
			switch (position)
			{
				case TOP :
				{
					edge = RectangleEdge.TOP;
					break;
				}
				case BOTTOM :
				{
					edge = RectangleEdge.BOTTOM;
					break;
				}
				case LEFT :
				{
					edge = RectangleEdge.LEFT;
					break;
				}
				case RIGHT :
				{
					edge = RectangleEdge.RIGHT;
					break;
				}
			}
		}
		return edge;
	}

	protected void populateSeriesColors(Paint[] colors, Paint[] colorSequence)
	{
		if (colors != null)
		{
			int size = colorSequence != null ? colorSequence.length : 0;
			System.arraycopy(colorSequence, 0, colors, 0, colorSequence.length);
			System.arraycopy(DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE, 0, colors, size, DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE.length);
		}
	}

	protected void setChartBackground(JFreeChart jfreeChart)
	{
		Paint defaultBackgroundPaint = (Paint)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BACKGROUND_PAINT);
		Image defaultBackgroundImage = (Image)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BACKGROUND_IMAGE);
		Integer defaultBackgroundImageAlignment = (Integer)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BACKGROUND_IMAGE_ALIGNMENT);
		Float defaultBackgroundImageAlpha = (Float)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.BACKGROUND_IMAGE_ALPHA);

		if (getChart().getOwnModeValue() != null)
		{
			if (getChart().getOwnModeValue() == ModeEnum.OPAQUE)
			{
				if (getChart().getOwnBackcolor() == null && defaultBackgroundPaint != null)
				{
					jfreeChart.setBackgroundPaint(defaultBackgroundPaint);
				}
				else
				{
					jfreeChart.setBackgroundPaint(getChart().getBackcolor());
				}
				
				setChartBackgroundImage(jfreeChart, 
						defaultBackgroundImage,
						defaultBackgroundImageAlignment,
						defaultBackgroundImageAlpha);
			}
			else
			{
				jfreeChart.setBackgroundPaint(ChartThemesConstants.TRANSPARENT_PAINT);
				setChartBackgroundImage(jfreeChart, 
						defaultBackgroundImage,
						defaultBackgroundImageAlignment,
						0f);
			}
		}
		else if (defaultBackgroundPaint != null)
		{
			jfreeChart.setBackgroundPaint(defaultBackgroundPaint);
		}
	}
	
	protected void setChartBackgroundImage(JFreeChart jfreeChart, 
			Image defaultBackgroundImage,
			Integer defaultBackgroundImageAlignment,
			Float defaultBackgroundImageAlpha)

	{
		
		if (defaultBackgroundImage != null)
		{
			jfreeChart.setBackgroundImage(defaultBackgroundImage);
			if (defaultBackgroundImageAlignment != null)
			{
				jfreeChart.setBackgroundImageAlignment(defaultBackgroundImageAlignment);
			}
			if (defaultBackgroundImageAlpha != null)
			{
				jfreeChart.setBackgroundImageAlpha(defaultBackgroundImageAlpha);
			}
		}
	}

	protected void setChartTitle(JFreeChart jfreeChart, Integer baseFontSize)
	{
		Boolean titleVisibility = (Boolean)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_VISIBLE);
		if (titleVisibility != null && titleVisibility)
		{
			TextTitle title = jfreeChart.getTitle();
			
			RectangleEdge titleEdge = null;
					
			if (title != null)
			{
				JRFont titleFont = getChart().getTitleFont();

				Font themeTitleFont = getFont((JRFont)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_FONT), titleFont, baseFontSize);
				title.setFont(themeTitleFont);
				
				HorizontalAlignment defaultTitleHAlignment = (HorizontalAlignment)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_HORIZONTAL_ALIGNMENT);
				if (defaultTitleHAlignment != null)
					title.setHorizontalAlignment(defaultTitleHAlignment);
				
				VerticalAlignment defaultTitleVAlignment = (VerticalAlignment)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_VERTICAL_ALIGNMENT);
				if (defaultTitleVAlignment != null)
					title.setVerticalAlignment(defaultTitleVAlignment);
				
				RectangleInsets defaultTitlePadding = (RectangleInsets)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_PADDING);
				RectangleInsets titlePadding = title.getPadding() != null ? title.getPadding() : defaultTitlePadding;
				if (titlePadding != null)
					title.setPadding(titlePadding);
				
				Color titleForecolor = getChart().getOwnTitleColor() != null ? 
						getChart().getOwnTitleColor() :
						(getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_FORECOLOR) != null ? 
								(Color)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_FORECOLOR) :
								getChart().getTitleColor());
				if (titleForecolor != null)
					title.setPaint(titleForecolor);
	
				Color titleBackcolor = (Color)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_BACKCOLOR);
				if (titleBackcolor != null)
					title.setBackgroundPaint(titleBackcolor);
				
				RectangleEdge defaultTitlePosition = (RectangleEdge)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.TITLE_POSITION);
				titleEdge = getEdge(getChart().getTitlePositionValue(), defaultTitlePosition);
				if (titleEdge != null)
					title.setPosition(titleEdge);
			}
		}
		else
		{
			TextTitle title = null;
			jfreeChart.setTitle(title);
		}
	}

	protected void setChartSubtitles(JFreeChart jfreeChart, Integer baseFontSize) throws JRException
	{			
		Boolean subtitleVisibility = (Boolean)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_VISIBLE);

		if (subtitleVisibility != null && subtitleVisibility)
		{
			String subtitleText = evaluateTextExpression(getChart().getSubtitleExpression());
			if (subtitleText != null)
			{
				TextTitle subtitle = new TextTitle(subtitleText);
				
				Font themeSubtitleFont = getFont((JRFont)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_FONT), getChart().getSubtitleFont(), baseFontSize);
				subtitle.setFont(themeSubtitleFont);
				
				HorizontalAlignment defaultSubtitleHAlignment = (HorizontalAlignment)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_HORIZONTAL_ALIGNMENT);
				if (defaultSubtitleHAlignment != null)
					subtitle.setHorizontalAlignment(defaultSubtitleHAlignment);

				VerticalAlignment defaultSubtitleVAlignment = (VerticalAlignment)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_VERTICAL_ALIGNMENT);
				if (defaultSubtitleVAlignment != null)
					subtitle.setVerticalAlignment(defaultSubtitleVAlignment);
				
				RectangleInsets defaultSubtitlePadding = (RectangleInsets)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_PADDING);
				RectangleInsets subtitlePadding = subtitle.getPadding() != null ? subtitle.getPadding() : defaultSubtitlePadding;
				if (subtitlePadding != null)
					subtitle.setPadding(subtitlePadding);

				Color subtitleForecolor = getChart().getOwnSubtitleColor() != null ? 
						getChart().getOwnSubtitleColor() :
						(getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_FORECOLOR) != null ? 
								(Color)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_FORECOLOR) :
								getChart().getSubtitleColor());
				if (subtitleForecolor != null)
					subtitle.setPaint(subtitleForecolor);
	
				Color subtitleBackcolor = getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_BACKCOLOR) != null ? 
						(Color)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_BACKCOLOR) :
						null;
				if (subtitleBackcolor != null)
					subtitle.setBackgroundPaint(subtitleBackcolor);
	
				RectangleEdge defaultSubtitlePosition = (RectangleEdge)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SUBTITLE_POSITION);
				//Subtitle has not its own position set, and by default this will be set the same as title position
				RectangleEdge subtitleEdge = null;
				if (defaultSubtitlePosition == null)
				{	
					subtitleEdge = jfreeChart.getTitle().getPosition();
				}
				else
				{
					subtitleEdge = defaultSubtitlePosition;
				}
				if (subtitleEdge != null)
					subtitle.setPosition(subtitleEdge);
				
				jfreeChart.addSubtitle(subtitle);
			}
		}
	}
	
	protected void setChartLegend(JFreeChart jfreeChart, Integer baseFontSize)
	{

		//The legend visibility is already taken into account in the jfreeChart object's constructor
		
		LegendTitle legend = jfreeChart.getLegend();
		if (legend != null)
		{
			Font themeLegendFont = getFont((JRFont)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_FONT), getChart().getLegendFont(), baseFontSize);
			legend.setItemFont(themeLegendFont);

			Color legendForecolor = getChart().getOwnLegendColor() != null ? 
					getChart().getOwnLegendColor() :
					(getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_FORECOLOR) != null ? 
							(Color)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_FORECOLOR) :
							getChart().getLegendColor());
			if (legendForecolor != null)
				legend.setItemPaint(legendForecolor);

			Color legendBackcolor = getChart().getOwnLegendBackgroundColor() != null ? 
					getChart().getOwnLegendBackgroundColor() :
					(getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_BACKCOLOR) != null ? 
							(Color)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_BACKCOLOR) :
							getChart().getLegendBackgroundColor());
			if (legendBackcolor != null)
				legend.setBackgroundPaint(legendBackcolor);
			
			BlockFrame frame = (BlockFrame)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_FRAME);
			if (frame != null)
				legend.setFrame(frame);
			
			HorizontalAlignment defaultLegendHAlignment = (HorizontalAlignment)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_HORIZONTAL_ALIGNMENT);
			if (defaultLegendHAlignment != null)
				legend.setHorizontalAlignment(defaultLegendHAlignment);
			
			VerticalAlignment defaultLegendVAlignment = (VerticalAlignment)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_VERTICAL_ALIGNMENT);
			if (defaultLegendVAlignment != null)
				legend.setVerticalAlignment(defaultLegendVAlignment);
			
			RectangleInsets defaultLegendPadding = (RectangleInsets)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_PADDING);
			RectangleInsets legendPadding = legend.getPadding() != null ? legend.getPadding() : defaultLegendPadding;
			if (legendPadding != null)
				legend.setPadding(legendPadding);

			RectangleEdge defaultLegendPosition = (RectangleEdge)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_POSITION);
			if (getEdge(getChart().getLegendPositionValue(), defaultLegendPosition) != null)
				legend.setPosition(getEdge(getChart().getLegendPositionValue(), defaultLegendPosition));
			
		}
	}
	
	protected void setChartBorder(JFreeChart jfreeChart)
	{
		JRLineBox lineBox = getChart().getLineBox();
		if (
			lineBox.getLeftPen().getLineWidth() == 0
			&& lineBox.getBottomPen().getLineWidth() == 0
			&& lineBox.getRightPen().getLineWidth() == 0
			&& lineBox.getTopPen().getLineWidth() == 0
			)
		{
			boolean isVisible = getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.CHART_BORDER_VISIBLE) == null ?
					false : 
					(Boolean)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.CHART_BORDER_VISIBLE);
			if (isVisible)
			{
				BasicStroke stroke = (BasicStroke)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.CHART_BORDER_STROKE);
				if (stroke != null)
					jfreeChart.setBorderStroke(stroke);
				Paint paint = (Paint)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.CHART_BORDER_PAINT);
				if (paint != null)
					jfreeChart.setBorderPaint(paint);
			}
				
			jfreeChart.setBorderVisible(isVisible);
		}
	}

	protected void setPlotBackground(Plot p, JRChartPlot jrPlot)
	{
		Paint defaultBackgroundPaint = (Paint)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_BACKGROUND_PAINT);
		Float defaultBackgroundAlpha = (Float)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_BACKGROUND_ALPHA);
		Float defaultForegroundAlpha = (Float)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_FOREGROUND_ALPHA);
		
		Image defaultBackgroundImage = (Image)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_BACKGROUND_IMAGE);
		Integer defaultBackgroundImageAlignment = (Integer)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_BACKGROUND_IMAGE_ALIGNMENT);
		Float defaultBackgroundImageAlpha = (Float)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_BACKGROUND_IMAGE_ALPHA);

		Paint backgroundPaint = jrPlot.getOwnBackcolor() != null ? jrPlot.getOwnBackcolor() : defaultBackgroundPaint;
		if (backgroundPaint != null)
		{
			p.setBackgroundPaint(backgroundPaint);
		}
		
		Float backgroundAlpha = jrPlot.getBackgroundAlphaFloat() != null ? 
				jrPlot.getBackgroundAlphaFloat() : 
				defaultBackgroundAlpha;
		if (backgroundAlpha != null)
			p.setBackgroundAlpha(backgroundAlpha);
		
		Float foregroundAlpha = jrPlot.getForegroundAlphaFloat() != null ? 
				jrPlot.getForegroundAlphaFloat() : 
				defaultForegroundAlpha;
		if (foregroundAlpha != null)
			p.setForegroundAlpha(foregroundAlpha);
		
		if (defaultBackgroundImage != null)
		{
			p.setBackgroundImage(defaultBackgroundImage);
			if (defaultBackgroundImageAlignment != null)
			{
				p.setBackgroundImageAlignment(defaultBackgroundImageAlignment);
			}
			if (defaultBackgroundImageAlpha != null)
			{
				p.setBackgroundImageAlpha(defaultBackgroundImageAlpha);
			}
		}
		
	}
	
	protected void handleCategoryPlotSettings(CategoryPlot p, JRChartPlot jrPlot)
	{
		Double defaultPlotLabelRotation = (Double)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_LABEL_ROTATION);
		PlotOrientation defaultPlotOrientation = (PlotOrientation)getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_ORIENTATION);
		// Handle rotation of the category labels.
		CategoryAxis axis = p.getDomainAxis();
		boolean hasRotation = jrPlot.getLabelRotationDouble() != null || defaultPlotLabelRotation != null;
		if(hasRotation)
		{
			double labelRotation = jrPlot.getLabelRotationDouble() != null ? 
					jrPlot.getLabelRotationDouble() :
					defaultPlotLabelRotation;
			
			if (labelRotation == 90)
			{
				axis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_90);
			}
			else if (labelRotation == -90) {
				axis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
			}
			else if (labelRotation < 0)
			{
				axis.setCategoryLabelPositions(
						CategoryLabelPositions.createUpRotationLabelPositions( (-labelRotation / 180.0) * Math.PI));
			}
			else if (labelRotation > 0)
			{
				axis.setCategoryLabelPositions(
						CategoryLabelPositions.createDownRotationLabelPositions((labelRotation / 180.0) * Math.PI));
			}
		}
		
		if (defaultPlotOrientation != null)
		{
			p.setOrientation(defaultPlotOrientation);
		}
	}

	protected void setPlotDrawingDefaults(Plot p, JRChartPlot jrPlot)
	{
		@SuppressWarnings("unchecked")
		List<Paint> defaultSeriesColors = (List<Paint>)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.SERIES_COLORS);
		Paint[] defaultPlotOutlinePaintSequence = 
			getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_PAINT_SEQUENCE) != null ?
			(Paint[])getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_PAINT_SEQUENCE) :
			DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE;
			
		Stroke[] defaultPlotStrokeSequence = 
			getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_STROKE_SEQUENCE) != null ?
			(Stroke[])getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_STROKE_SEQUENCE) :
			DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE;
			
		Stroke[] defaultPlotOutlineStrokeSequence = 
			getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_STROKE_SEQUENCE) != null ?
			(Stroke[])getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_OUTLINE_STROKE_SEQUENCE) :
			DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE;
			
		Shape[] defaultPlotShapeSequence = 
			getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_SHAPE_SEQUENCE) != null ?
			(Shape[])getDefaultValue(defaultPlotPropertiesMap, ChartThemesConstants.PLOT_SHAPE_SEQUENCE) :
			DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE;
		// Set color series
		Paint[] colors = null;
		SortedSet<JRSeriesColor> seriesColors = jrPlot.getSeriesColors();
		Paint[] colorSequence = null;
		if (seriesColors != null && seriesColors.size() > 0)
		{
			int seriesColorsSize = seriesColors.size();
			
			colors = new Paint[DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE.length + seriesColorsSize];

			JRSeriesColor[] jrColorSequence = new JRSeriesColor[seriesColorsSize];
			seriesColors.toArray(jrColorSequence);
			colorSequence = new Paint[seriesColorsSize];
			
			for (int i = 0; i < seriesColorsSize; i++)
			{
				colorSequence[i] = jrColorSequence[i].getColor();
			}
			populateSeriesColors(colors, colorSequence);
		}
		else if (defaultSeriesColors != null && defaultSeriesColors.size() > 0)
		{
			colors = new Paint[DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE.length + defaultSeriesColors.size()];
			colorSequence = new Paint[defaultSeriesColors.size()];
			defaultSeriesColors.toArray(colorSequence);
			populateSeriesColors(colors, colorSequence);
		}
		else
		{
			colors = DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE;
		}
		
		p.setDrawingSupplier(new DefaultDrawingSupplier(
				colors,
				defaultPlotOutlinePaintSequence,
				defaultPlotStrokeSequence,
				defaultPlotOutlineStrokeSequence,
				defaultPlotShapeSequence
				)
			);
		
	}
	
	protected void setAxisLine(Axis axis, Paint lineColor)
	{
		Boolean defaultAxisLineVisible = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LINE_VISIBLE);
		if (defaultAxisLineVisible != null && defaultAxisLineVisible)
		{
			Paint linePaint = lineColor != null ?
					lineColor :
					(Paint)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LINE_PAINT);
			
			if (linePaint != null)
			{
				axis.setAxisLinePaint(linePaint);
			}
			Stroke defaultAxisLineStroke = (Stroke)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LINE_STROKE);
			if (defaultAxisLineStroke != null)
				axis.setAxisLineStroke(defaultAxisLineStroke);
		}
	}
	
	protected void setAxisLabel(Axis axis, JRFont labelFont, Paint labelColor, Integer baseFontSize)
	{
		Boolean defaultAxisLabelVisible = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LABEL_VISIBLE);
		if (defaultAxisLabelVisible != null && defaultAxisLabelVisible)
		{
			if (axis.getLabel() == null)
				axis.setLabel((String)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LABEL));

			Double defaultLabelAngle = (Double)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LABEL_ANGLE);
			if (defaultLabelAngle != null)
				axis.setLabelAngle(defaultLabelAngle);
			Font themeLabelFont = getFont((JRFont)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LABEL_FONT), labelFont, baseFontSize);
			axis.setLabelFont(themeLabelFont);
			
			RectangleInsets defaultLabelInsets = (RectangleInsets)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LABEL_INSETS);
			if (defaultLabelInsets != null)
			{
				axis.setLabelInsets(defaultLabelInsets);
			}
			Paint labelPaint = labelColor != null ? 
					labelColor :
					(Paint)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_LABEL_PAINT);	
			if (labelPaint != null)
			{
				axis.setLabelPaint(labelPaint);
			}
		}
	}

	protected void setAxisTickLabels(Axis axis, JRFont tickLabelFont, Paint tickLabelColor, String tickLabelMask, Integer baseFontSize)
	{
		Boolean defaultAxisTickLabelsVisible = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_LABELS_VISIBLE);
		if (defaultAxisTickLabelsVisible != null && defaultAxisTickLabelsVisible)
		{
			Font themeTickLabelFont = getFont((JRFont)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_LABEL_FONT), tickLabelFont, baseFontSize);
			axis.setTickLabelFont(themeTickLabelFont);
			
			RectangleInsets defaultTickLabelInsets = (RectangleInsets)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_LABEL_INSETS);
			if (defaultTickLabelInsets != null)
			{
				axis.setTickLabelInsets(defaultTickLabelInsets);
			}
			Paint tickLabelPaint = tickLabelColor != null ? 
					tickLabelColor :
					(Paint)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_LABEL_PAINT);	
			if (tickLabelPaint != null)
			{
				axis.setTickLabelPaint(tickLabelPaint);
			}
			
			TimeZone timeZone = getChartContext().getTimeZone();
			if (axis instanceof DateAxis && timeZone != null)
			{
				// used when no mask is set
				((DateAxis) axis).setTimeZone(timeZone);
			}
			
			if (tickLabelMask != null)
			{
				if (axis instanceof NumberAxis)
				{
					NumberFormat fmt = NumberFormat.getInstance(getLocale());
					if (fmt instanceof DecimalFormat)
						((DecimalFormat) fmt).applyPattern(tickLabelMask);
					((NumberAxis)axis).setNumberFormatOverride(fmt);
				}
				else if (axis instanceof DateAxis)
				{
					DateFormat fmt;
					if (tickLabelMask.equals("SHORT") || tickLabelMask.equals("DateFormat.SHORT"))
						fmt = DateFormat.getDateInstance(DateFormat.SHORT, getLocale());
					else if (tickLabelMask.equals("MEDIUM") || tickLabelMask.equals("DateFormat.MEDIUM"))
						fmt = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
					else if (tickLabelMask.equals("LONG") || tickLabelMask.equals("DateFormat.LONG"))
						fmt = DateFormat.getDateInstance(DateFormat.LONG, getLocale());
					else if (tickLabelMask.equals("FULL") || tickLabelMask.equals("DateFormat.FULL"))
						fmt = DateFormat.getDateInstance(DateFormat.FULL, getLocale());
					else
						fmt = new SimpleDateFormat(tickLabelMask, getLocale());
					
					// FIXME fmt cannot be null
					if (fmt != null)
					{
						if (timeZone != null)
						{
							fmt.setTimeZone(timeZone);
						}
						
						((DateAxis)axis).setDateFormatOverride(fmt);
					}
					else
						((DateAxis)axis).setDateFormatOverride(DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()));
				}
				// ignore mask for other axis types.
			}
		}
	}
	
	protected void setAxisTickMarks(Axis axis, Paint lineColor)
	{
		Boolean defaultAxisTickMarksVisible = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_MARKS_VISIBLE);
		if (defaultAxisTickMarksVisible != null && defaultAxisTickMarksVisible)
		{
			Float defaultAxisTickMarksInsideLength = (Float)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_MARKS_INSIDE_LENGTH);
			if (defaultAxisTickMarksInsideLength != null)
				axis.setTickMarkInsideLength(defaultAxisTickMarksInsideLength);
			
			Float defaultAxisTickMarksOutsideLength = (Float)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_MARKS_OUTSIDE_LENGTH);
			if (defaultAxisTickMarksOutsideLength != null)
				axis.setTickMarkInsideLength(defaultAxisTickMarksOutsideLength);
			
			Paint tickMarkPaint = getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_MARKS_PAINT) != null ?
					(Paint)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_MARKS_PAINT) :
					lineColor;
			
			if (tickMarkPaint != null)
			{
				axis.setTickMarkPaint(tickMarkPaint);
			}
			Stroke defaultTickMarkStroke = (Stroke)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.AXIS_TICK_MARKS_STROKE);
			if (defaultTickMarkStroke != null)
				axis.setTickMarkStroke(defaultTickMarkStroke);
		}
	}
	
	protected void setAxisBounds(Axis axis, boolean isRangeAxis, String timePeriodUnit, Comparable<?> minValue, Comparable<?> maxValue) throws JRException
	{
		if (axis instanceof ValueAxis)
		{
			if (axis instanceof DateAxis)
			{
				if (minValue != null)
				{
					((DateAxis)axis).setMinimumDate((Date)minValue);
				}
				if (maxValue != null)
				{
					((DateAxis)axis).setMaximumDate((Date)maxValue);
				}
			}
			else
			{
				if (minValue != null)
				{
					((ValueAxis)axis).setLowerBound(((Number)minValue).doubleValue());
				}
				if (maxValue != null)
				{
					((ValueAxis)axis).setUpperBound(((Number)maxValue).doubleValue());
				}
			}

			calculateTickUnits(axis, isRangeAxis, timePeriodUnit);
		}
	}

	/**
	 * For a given axis, adjust the tick unit size, in order to 
	 * have a customizable number of ticks on that axis
	 */
	protected void calculateTickUnits(Axis axis, boolean isRangeAxis, String timePeriodUnit)
	{
		Integer tickCount = null;
		Number tickInterval = null;
		boolean axisIntegerUnit = false;
		
		if (getChart().hasProperties())
		{
			String tickCountProperty = null;
			String tickIntervalProperty = null;
			String axisIntegerUnitProperty = null;
			
			if (isRangeAxis)
			{
				tickCountProperty = getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_RANGE_AXIS_TICK_COUNT);
				tickIntervalProperty = getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_RANGE_AXIS_TICK_INTERVAL);
				axisIntegerUnitProperty = getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_RANGE_AXIS_INTEGER_UNIT);
			}
			else
			{
				tickCountProperty = getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_DOMAIN_AXIS_TICK_COUNT);
				tickIntervalProperty = getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_DOMAIN_AXIS_TICK_INTERVAL);
				axisIntegerUnitProperty = getChart().getPropertiesMap().getProperty(DefaultChartTheme.PROPERTY_DOMAIN_AXIS_INTEGER_UNIT);
			}
			if (tickCountProperty != null && tickCountProperty.trim().length() > 0)
			{
				tickCount = Integer.valueOf(tickCountProperty);
			}
			if (tickIntervalProperty != null && tickIntervalProperty.trim().length() > 0)
			{
				tickInterval = Double.valueOf(tickIntervalProperty);
			}
			if (axisIntegerUnitProperty != null && axisIntegerUnitProperty.trim().length() > 0)
			{
				axisIntegerUnit = Boolean.valueOf(axisIntegerUnitProperty);
			}
		}
		else
		{
			if (isRangeAxis)
			{
				tickCount = (Integer)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.RANGE_AXIS_TICK_COUNT);
				tickInterval = (Number)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.RANGE_AXIS_TICK_INTERVAL);
				if (getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.RANGE_AXIS_INTEGER_UNIT) != null)
				{
					axisIntegerUnit = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.RANGE_AXIS_INTEGER_UNIT);
				}
			}
			else
			{
				tickCount = (Integer)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.DOMAIN_AXIS_TICK_COUNT);
				tickInterval = (Number)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.DOMAIN_AXIS_TICK_INTERVAL);
				if (getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.DOMAIN_AXIS_INTEGER_UNIT) != null)
				{
					axisIntegerUnit = (Boolean)getDefaultValue(defaultAxisPropertiesMap, ChartThemesConstants.DOMAIN_AXIS_INTEGER_UNIT);
				}
			}
		}
		
//		if (axis instanceof NumberAxis)
//		{
//			NumberAxis numberAxis = (NumberAxis)axis;
//			int axisRange = (int)numberAxis.getRange().getLength();
//			if (numberAxis.getNumberFormatOverride() != null)
//			{
//				if (tickInterval != null && tickInterval.length() > 0)
//					numberAxis.setTickUnit(new NumberTickUnit(Double.valueOf(tickInterval), numberAxis.getNumberFormatOverride()));
//				else
//					numberAxis.setTickUnit(new NumberTickUnit( axisRange/tickCount, numberAxis.getNumberFormatOverride()));
//			}
//			else
//			{
//				if (tickInterval != null && tickInterval.length() > 0)
//					numberAxis.setTickUnit(new NumberTickUnit(Double.valueOf(tickInterval)));
//				else
//					numberAxis.setTickUnit(new NumberTickUnit(axisRange/tickCount));
//			}
//		}
		if (axis instanceof NumberAxis)
		{
			NumberAxis numberAxis = (NumberAxis)axis;
			int axisRange = (int)numberAxis.getRange().getLength();
			
			if (axisIntegerUnit)
			{
				ChartUtil chartUtil = ChartUtil.getInstance(getChartContext().getJasperReportsContext());
				numberAxis.setStandardTickUnits(chartUtil.createIntegerTickUnits(getLocale()));
				chartUtil.setAutoTickUnit(numberAxis);
			}
			else if (axisRange > 0)
			{
				if (tickInterval != null)
				{
					if (numberAxis.getNumberFormatOverride() != null)
					{
						numberAxis.setTickUnit(new NumberTickUnit(tickInterval.doubleValue(), numberAxis.getNumberFormatOverride()));
					}
					else
					{
						numberAxis.setTickUnit(new NumberTickUnit(tickInterval.doubleValue(), NumberFormat.getNumberInstance(getLocale())));
					}
				}
				else if (tickCount != null)
				{
					int newTickUnitSize = axisRange / tickCount;
					if (newTickUnitSize > numberAxis.getTickUnit().getSize())
					{
						int tickUnitSize = newTickUnitSize;
			
						//preferably multiple of 5 values should be used as tick units lengths:
						int i = 1;
						while(tickUnitSize > 9)
						{
							tickUnitSize /= 10;
							i *= 10;
						}
						tickUnitSize *= i;
						newTickUnitSize = tickUnitSize + i/2;
			
						if (newTickUnitSize > 0 && axisRange / newTickUnitSize > tickCount)
						{
							newTickUnitSize += i / 2;
						}
						if (numberAxis.getNumberFormatOverride() != null)
						{
							numberAxis.setTickUnit(new NumberTickUnit(newTickUnitSize, numberAxis.getNumberFormatOverride()));
						}
						else
						{
							numberAxis.setTickUnit(new NumberTickUnit(newTickUnitSize, NumberFormat.getNumberInstance(getLocale())));
						}
					}
				}
				else
				{
					ChartUtil chartUtil = ChartUtil.getInstance(getChartContext().getJasperReportsContext());
					numberAxis.setStandardTickUnits(chartUtil.createStandardTickUnits(getLocale()));
					chartUtil.setAutoTickUnit(numberAxis);
				}
			}
		}
//		else if (axis instanceof DateAxis)
//		{
//			DateAxis dateAxis = (DateAxis)axis;
//			int axisRange = (int)dateAxis.getRange().getLength();
//			int timeUnit = getTimePeriodUnit(timePeriodUnit);
//			
//			if (dateAxis.getDateFormatOverride() != null)
//			{
//				if (tickInterval != null && tickInterval.length() > 0)
//					dateAxis.setTickUnit(new DateTickUnit(timeUnit, Integer.valueOf(tickInterval), dateAxis.getDateFormatOverride()));
//				else
//					dateAxis.setTickUnit(new DateTickUnit(timeUnit, axisRange/tickCount, dateAxis.getDateFormatOverride()));
//			}
//			else
//			{
//				if (tickInterval != null && tickInterval.length() > 0)
//					dateAxis.setTickUnit(new DateTickUnit(timeUnit, Integer.valueOf(tickInterval)));
//				else
//					dateAxis.setTickUnit(new DateTickUnit(timeUnit, axisRange/tickCount));
//			}
//		}
	}
	
	/**
	 * Specifies whether a chart legend should be visible or no by default.
	 */
	protected boolean isShowLegend()
	{
		Boolean legendVisibility = 
			getChart().getShowLegend() == null 
				?(Boolean)getDefaultValue(defaultChartPropertiesMap, ChartThemesConstants.LEGEND_VISIBLE)
				: getChart().getShowLegend();

		return legendVisibility == null ? false : legendVisibility;
	}

	/**
	 * Returns the specific org.jfree.chart.axis.DateTickUnit time unit constant
	 * related to the String value passed as argument
	 * 
	 * @param timePeriodUnit - a String represented by one of the following
	 * accepted values: ["Year", "Month", "Day", "Hour", "Minute", "Second", "Millisecond"]
	 * @return the specific org.jfree.chart.axis.DateTickUnit time unit constant
	 */
	protected DateTickUnitType getTimePeriodUnit(String timePeriodUnit)
	{
		if (timePeriodUnit == null)
			return DateTickUnitType.DAY;
		return timePeriodUnit.equals("Year")
			? DateTickUnitType.YEAR
			: timePeriodUnit.equals("Month")
			? DateTickUnitType.MONTH
			: timePeriodUnit.equals("Hour")
			? DateTickUnitType.HOUR
			: timePeriodUnit.equals("Minute")
			? DateTickUnitType.MINUTE
			: timePeriodUnit.equals("Second")
			? DateTickUnitType.SECOND
			: timePeriodUnit.equals("Millisecond")
			? DateTickUnitType.MILLISECOND
			: DateTickUnitType.DAY;
	}

	protected Object getDefaultValue(Map<String, ?> map, Object key)
	{
		return map == null ? null : map.get(key);
	}


	protected Font getFont(JRFont themeFont, JRFont ownFont, Integer baseFontSize)
	{
		JRBaseFont font = new JRBaseFont();
		if (themeFont != null && themeFont.getFontsize() <= 0 && baseFontSize != null && baseFontSize > 0)
		{
			themeFont.setFontSize((float)baseFontSize);
		}
		FontUtil.copyNonNullOwnProperties(themeFont, font);
		FontUtil.copyNonNullOwnProperties(ownFont, font);
		font = new JRBaseFont(getChart(), font);
		return getFontUtil().getAwtFont(font, getLocale());
	}
	
	
	/**
	 *
	 */
	protected JRFont getFont(JRFont font)
	{
		if (font == null)
		{
			return new JRBaseFont(getChart());
		}
		return font;
	}

	
	/**
	 * @return the defaultChartPropertiesMap
	 */
	public Map<String, ?> getDefaultChartPropertiesMap()
	{
		return defaultChartPropertiesMap;
	}


	/**
	 * @param defaultChartPropertiesMap the defaultChartPropertiesMap to set
	 */
	public void setDefaultChartPropertiesMap(Map<String, ?> defaultChartPropertiesMap)
	{
		this.defaultChartPropertiesMap = defaultChartPropertiesMap;
	}


	/**
	 * @return the defaultPlotPropertiesMap
	 */
	public Map<String, ?> getDefaultPlotPropertiesMap()
	{
		return defaultPlotPropertiesMap;
	}


	/**
	 * @param defaultPlotPropertiesMap the defaultPlotPropertiesMap to set
	 */
	public void setDefaultPlotPropertiesMap(Map<String, ?> defaultPlotPropertiesMap)
	{
		this.defaultPlotPropertiesMap = defaultPlotPropertiesMap;
	}


	/**
	 * @return the defaultAxisPropertiesMap
	 */
	public Map<String, ?> getDefaultAxisPropertiesMap()
	{
		return defaultAxisPropertiesMap;
	}


	/**
	 * @param defaultAxisPropertiesMap the defaultAxisPropertiesMap to set
	 */
	public void setDefaultAxisPropertiesMap(Map<String, ?> defaultAxisPropertiesMap)
	{
		this.defaultAxisPropertiesMap = defaultAxisPropertiesMap;
	}


	/**
	 * @return the defaultChartTypePropertiesMap
	 */
	public Map<String, ?> getDefaultChartTypePropertiesMap()
	{
		return defaultChartTypePropertiesMap;
	}


	/**
	 * @param defaultChartTypePropertiesMap the defaultChartTypePropertiesMap to set
	 */
	public void setDefaultChartTypePropertiesMap(Map<String, ?> defaultChartTypePropertiesMap)
	{
		this.defaultChartTypePropertiesMap = defaultChartTypePropertiesMap;
	}
		
}
