/*
 * Created on 09/05/2004
 *
 */
package it.businesslogic.ireport.chart;

import java.awt.Image;
import java.util.HashMap;
import java.util.Hashtable;

import dori.jasper.engine.JRDataSource;
import dori.jasper.engine.JRField;
import dori.jasper.engine.data.JRMapArrayDataSource;

/**
 * Base class for any chart factory suported by iReport.
 * 
 * @author Egon Rosa Pereira
 *
 */
public abstract class IReportAbstractChartFactory {
	
	public static final int XY_AXIS_CHART_DATASET_TYPE		= 1;
	public static final int X_AXIS_CHART_DATASET_TYPE 		= 2;
	public static final int Y_AXIS_CHART_DATASET_TYPE 		= 3;

	
	private static Hashtable CHART_FACTORY_COLLECTION;
	
	static{
		CHART_FACTORY_COLLECTION = new Hashtable();
	}

	/**
	 * Protected constructor.
	 */
	protected IReportAbstractChartFactory() {
		super();
	}

	protected abstract Image engineGenerateChartImage(IReportChartProperties chartProperties, Hashtable datasources) throws Exception;
	protected abstract int engineGetChartTypeCount();
	protected abstract boolean allowMultipleChart();


	/**
	 * Generate the chart image from a XML file or XML PCData encoded text.
	 * Throws RuntimeException if fail. 
	 *  
	 * @param xmlFile  Chart properties XML file.
	 * @param isFilename If true the xmlFile parameter contains a filename and false contains a XML PCData encoded.
	 * @param dataSource Data source to fill chart.
	 * @return The image data.
	 */
	public static Image generateChartImage(String xmlFile, boolean isFilename, JRDataSource dataSource) {
		
		Hashtable datasources = new Hashtable();
		datasources.put("datasource", dataSource);
		
		return generateChartImage(xmlFile, isFilename, datasources);	
	}



	/**
	 * Generate the chart image using the specified chart factory in the chartProperties.
	 * Throws RuntimeException if fail. 
	 *  
	 * @param chartProperties  Properties for build chart.
	 * @param dataSource Datasource to fill chart.
	 * @return The image data.
	 */
	public static Image generateChartImage(IReportChartProperties chartProperties, JRDataSource dataSource) {

		Hashtable datasources = new Hashtable();
		datasources.put("datasource", dataSource);
		
		return generateChartImage(chartProperties, datasources);
	}

	/**
	 * Generate the chart image from a XML file or XML PCData encoded text.
	 * Throws RuntimeException if fail. 
	 *  
	 * @param xmlFile  Chart properties XML file.
	 * @param isFilename If true the xmlFile parameter contains a filename and false contains a XML file encoded inside a PCData.
	 * @param dataSources Data sources to fill chart.
	 * @return The image data.
	 */
	public static Image generateChartImage(String xmlFile, boolean isFilename, Hashtable dataSources) {
	
		if(isFilename){	
			return generateChartImage(IReportChartProperties.getInstanceFromXMLFile(xmlFile), dataSources);
		}else{
			return generateChartImage(IReportChartProperties.getInstanceFromXMLPCData(xmlFile), dataSources);
		}
	}

	/**
	 * Generate the chart image using the specified chart factory in the chartProperties.
	 * Throws RuntimeException if fail. 
	 *  
	 * @param chartProperties  Properties for build chart.
	 * @param dataSources Datasources to fill chart.
	 * @return The image data.
	 */
	public static Image generateChartImage(IReportChartProperties chartProperties, Hashtable dataSources) {
		
		try{

			//keep a instance for all kind of chart factory
			String className = chartProperties.getFactory(); 

			//get a instance of chart factory
			IReportAbstractChartFactory chartFactoryInstance = getChartFactoryInstance(className);
			
			return chartFactoryInstance.engineGenerateChartImage(chartProperties, dataSources);
			
		}catch(Exception e){
			throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage());
		}
	}
	


	/**
	 * @param className
	 * @return
	 */
	private static IReportAbstractChartFactory getChartFactoryInstance(String className){
		
		//keep a instance for all kind of chart factory
		IReportAbstractChartFactory chartFactoryInstance;
		if(CHART_FACTORY_COLLECTION.containsKey(className)){
			chartFactoryInstance = (IReportAbstractChartFactory) CHART_FACTORY_COLLECTION.get(className);
		}else{
			try{
				chartFactoryInstance = (IReportAbstractChartFactory) Class.forName(className).newInstance();
			}catch(Exception e){
				throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage());
			}
			CHART_FACTORY_COLLECTION.put(className, chartFactoryInstance);
		}
		
		return chartFactoryInstance;
	}

	/**
	 * Get how many chart types can be used with the selected chart factory.  
	 * For use with a chart wizard.  
	 * 
	 * @param chartFactory  Fully qualified class name. Example: it.businesslogic.ireport.chart.IReportJFreeChartFactory
	 * @return Chart types count.
	 */
	public static int getChartTypeCount(String chartFactory) {

		//get a instance of chart factory
		return getChartFactoryInstance(chartFactory).engineGetChartTypeCount();
	}


	/**
	 * Get a sample JRDataSource of selected dataset type.
	 * The types are:
	 * IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE - a dataset with many data rows and data columns. In this case 6x6. 
	 * IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE  - a dataset with one data row and many data columns. In this case 2x6. 
	 * IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE  - a dataset with many data rows and one data column. In this case 6x2.
	 * 
	 * For retrieve the data source values use the method getSampleDataSourceFields().
	 *  
	 * For use with a chart wizard.  
	 * 
	 * @param dataSetType IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE, IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE or IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE. 
	 * @return Returns a sample JRDataSource of selected dataset type.
	 */
	public static JRDataSource getSampleDataSource(int dataSetType) {
	
		HashMap array[] = null;
		JRField fields[] = getSampleDataSourceFields(dataSetType);
		
		switch (dataSetType) {
			case IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE :

			array = new HashMap[6];
			array[0] = new HashMap(); 
			array[1] = new HashMap(); 
			array[2] = new HashMap(); 
			array[3] = new HashMap(); 
			array[4] = new HashMap(); 
			array[5] = new HashMap(); 

			array[0].put(fields[0].getName(), "Apple");   
			array[1].put(fields[0].getName(), "Cereal");   
			array[2].put(fields[0].getName(), "Milk");   
			array[3].put(fields[0].getName(), "Rice");   
			array[4].put(fields[0].getName(), "Cookies");   
			array[5].put(fields[0].getName(), "Sugar");   

			array[0].put(fields[1].getName(), new Double(5.1));   
			array[0].put(fields[2].getName(), new Double(4.6));   
			array[0].put(fields[3].getName(), new Double(7.2));   
			array[0].put(fields[4].getName(), new Double(8.1));   
			array[0].put(fields[5].getName(), new Double(4.8));   

			array[1].put(fields[1].getName(), new Double(6.2));   
			array[1].put(fields[2].getName(), new Double(4.5));   
			array[1].put(fields[3].getName(), new Double(6.4));   
			array[1].put(fields[4].getName(), new Double(7));   
			array[1].put(fields[5].getName(), new Double(5.7));   

			array[2].put(fields[1].getName(), new Double(6));   
			array[2].put(fields[2].getName(), new Double(4.7));   
			array[2].put(fields[3].getName(), new Double(8.2));   
			array[2].put(fields[4].getName(), new Double(5.8));   
			array[2].put(fields[5].getName(), new Double(6.3));   

			array[3].put(fields[1].getName(), new Double(6.7));   
			array[3].put(fields[2].getName(), new Double(4.8));   
			array[3].put(fields[3].getName(), new Double(4.6));   
			array[3].put(fields[4].getName(), new Double(8.2));   
			array[3].put(fields[5].getName(), new Double(7.8));   

			array[4].put(fields[1].getName(), new Double(5.2));   
			array[4].put(fields[2].getName(), new Double(4.8));   
			array[4].put(fields[3].getName(), new Double(6.2));   
			array[4].put(fields[4].getName(), new Double(9.5));   
			array[4].put(fields[5].getName(), new Double(8.1));
			   
			array[5].put(fields[1].getName(), new Double(2.5));   
			array[5].put(fields[2].getName(), new Double(9.3));   
			array[5].put(fields[3].getName(), new Double(10));   
			array[5].put(fields[4].getName(), new Double(4.9));   
			array[5].put(fields[5].getName(), new Double(1.8));

			break;
				
			case IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE :
			
			array = new HashMap[1]; 
			array[0] = new HashMap(); 

			array[0].put(fields[0].getName(), new Double(45.1));   
			array[0].put(fields[1].getName(), new Double(25.1));   
			array[0].put(fields[2].getName(), new Double(10.6));   
			array[0].put(fields[3].getName(), new Double(7.2));   
			array[0].put(fields[4].getName(), new Double(4.1));   
			array[0].put(fields[5].getName(), new Double(1.8));   

			break;
			
			case IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE :

			array = new HashMap[6];
			array[0] = new HashMap(); 
			array[1] = new HashMap(); 
			array[2] = new HashMap(); 
			array[3] = new HashMap(); 
			array[4] = new HashMap(); 
			array[5] = new HashMap(); 

			array[0].put(fields[0].getName(), new Double(0.25));   
			array[1].put(fields[0].getName(), new Double(0.12));   
			array[2].put(fields[0].getName(), new Double(0.22));   
			array[3].put(fields[0].getName(), new Double(0.08));   
			array[4].put(fields[0].getName(), new Double(0.16));   
			array[5].put(fields[0].getName(), new Double(0.17));   
				
			break;
		}
		
		return new JRMapArrayDataSource(array);		
	}

	/**
	 * Get a sample JRDataSource of selected dataset type.
	 * The types are:
	 * IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE - a dataset with many data rows and data columns. 
	 * IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE  - a dataset with one data row and many data columns. 
	 * IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE  - a dataset with many data rows and one data column.
	 * 
	 * For retrieve the data source values use the method
	 * IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE - six fields. 
	 * IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE  - six fields.
	 * IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE  - two fields.
	 *  
	 * For use with a chart wizard.  
	 * 
	 * @param dataSetType IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE, IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE or IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE. 
	 * @return Returns the fields for the samples JRDataSources.
	 */
	public static JRField[] getSampleDataSourceFields(int dataSetType) {
		
		JRField[] fields = null;
		
		switch (dataSetType) {
			case IReportAbstractChartFactory.XY_AXIS_CHART_DATASET_TYPE :
			fields = new JRField[6];
			fields[0] = new JRDefaultField("Product", String.class);
			fields[1] = new JRDefaultField("Jan", Double.class);
			fields[2] = new JRDefaultField("Feb", Double.class);
			fields[3] = new JRDefaultField("Mar", Double.class);
			fields[4] = new JRDefaultField("May", Double.class);
			fields[5] = new JRDefaultField("Jul", Double.class);
			break;
				
			case IReportAbstractChartFactory.X_AXIS_CHART_DATASET_TYPE :
			fields = new JRField[6];
			fields[0] = new JRDefaultField("AT 486", Double.class);
			fields[1] = new JRDefaultField("Pentium", Double.class);
			fields[2] = new JRDefaultField("Pentium II", Double.class);
			fields[3] = new JRDefaultField("Pentium III", Double.class);
			fields[4] = new JRDefaultField("Pentium IV", Double.class);
			fields[5] = new JRDefaultField("Pentium V", Double.class);

			break;

			case IReportAbstractChartFactory.Y_AXIS_CHART_DATASET_TYPE :
			fields = new JRField[1];
			fields[0] = new JRDefaultField("Percent", Double.class);
				
			break;
		}
		
		return fields;
	}

}
