
package org.eclipse.birt.report.engine.emitter.excel.chart;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.birt.chart.model.Chart;
import org.eclipse.birt.chart.model.ChartWithAxes;
import org.eclipse.birt.chart.model.ChartWithoutAxes;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.reportitem.ChartReportItemImpl;
import org.eclipse.birt.report.engine.emitter.excel.Data;
import org.eclipse.birt.report.engine.emitter.excel.ExcelEmitter;
import org.eclipse.birt.report.engine.emitter.excel.ExcelWriter;
import org.eclipse.birt.report.engine.emitter.excel.StyleEngine;
import org.eclipse.birt.report.engine.ir.ExtendedItemDesign;
import org.eclipse.birt.report.model.api.ExtendedItemHandle;
import org.eclipse.birt.report.model.api.extension.ExtendedElementException;
import org.eclipse.birt.report.model.api.extension.IReportItem;

/**
 * <code>ChartConverter</code> is for use of extracting chart data
 * 
 */

public class ChartConverter
{
	protected  Logger logger = Logger.getLogger( ExcelEmitter.class
			.getName( ) );
	
	private int ID = 1;
	
	public final int MAX_STORE = 255;
	
	public File convert(ExtendedItemDesign design, ExtendedItemHandle handle)
	{
		if(ID >= MAX_STORE)
		{
			return null;
		}	
		
		IReportItem item = null;
		
		try
		{
			item = handle.getReportItem( );
		}
		catch ( ExtendedElementException e )
		{
			
		}

		if ( item == null )
		{
			try
			{
				handle.loadExtendedElement( );
				item = handle.getReportItem( );
			}
			catch ( ExtendedElementException e )
			{
				logger.log( Level.WARNING, e.getMessage( ), e );
			}
			
			if ( item == null )
			{
				return null;
			}
		}

		Chart chart = (Chart) ( (ChartReportItemImpl) item )
				.getProperty( "chart.instance" );
		
		TableDataIterator iter = convert(chart);
		
		try
		{
			File tempFile = File.createTempFile( "Chart" + 
					System.currentTimeMillis( ), ID + "" );
			ExcelWriter writer = new ExcelWriter(new FileOutputStream(tempFile));
			
			writer.startSheet( "Chart" + ID++ );
			writer.startTable( null );
			
			while ( iter.hasNext( ) )
			{
				writer.startRow( );
				Data[] row = iter.nextRow( );

				for ( int i = 0; i < row.length; i++ )
				{
					if ( row[i] == null )
					{						
						writer.writeDefaultCell( AbstractDataHelper.createData( "", Data.STRING) );
					}
					else
					{
						if(row[i].getDatatype( ) == Data.DATE) {
							row[i].setStyleId( StyleEngine.DEFAULT_DATE_STYLE );
						}
						
						writer.writeDefaultCell( row[i]);
					}
				}
				writer.endRow( );
			}	
			
			writer.endTable(  );
			writer.closeSheet( );
			
			writer.close( false );
			
			return tempFile;
		}
		catch(IOException e)
		{
			logger.log( Level.WARNING, e.getMessage( ), e);
			return null;
		}	
	}

	/**
	 * This method selects a proper runtime to handle given chart based on chart
	 * type.
	 * 
	 * @param chart
	 * @return An iterator, by which user can walk on the chart data
	 */
	public TableDataIterator convert( Chart chart )
	{
		TableGen table = null;

		if ( chart instanceof ChartWithAxes )
		{
			table = convertChartWithAxes( (ChartWithAxes) chart );
		}
		else
		{
			table = covertChart( (ChartWithoutAxes) chart );
		}

		return table.iterator( );
	}
	
	private TableGen covertChart( ChartWithoutAxes chart )
	{
		TableGen table = new TableGen( );

		for ( int i = 0; i < chart.getSeriesDefinitions( ).size( ); i++ )
		{
			SeriesDefinition def = (SeriesDefinition) chart
					.getSeriesDefinitions( ).get( i );
			// Handle the base series definition
			table.addSeriesDefinition( def, null );

			walkOnSeriesDefinition( def, table );
		}

		return table;
	}

	private void walkOnSeriesDefinition( SeriesDefinition def,
			TableGen table )
	{
		for ( int i = 0; i < def.getSeriesDefinitions( ).size( ); i++ )
		{
			SeriesDefinition cdef = (SeriesDefinition) def
					.getSeriesDefinitions( ).get( i );
			table.addSeriesDefinition( cdef, null );

			walkOnSeriesDefinition( cdef, table );
		}
	}

	private TableGen convertChartWithAxes( ChartWithAxes chart )
	{
		TableGen table = null;

		// Handle the base axes
		if ( chart.getBaseAxes( ) != null )
		{
			table = new TableGen( );

			Axis baseAxis = chart.getBaseAxes( )[0];
			table.addSeriesDefinition( ( (SeriesDefinition) baseAxis
					.getSeriesDefinitions( ).get( 0 ) ),
					getAxisTitle( baseAxis ) );

			for ( int i = 0; i < baseAxis.getAssociatedAxes( ).size( ); i++ )
			{
				Axis assAxis = (Axis) baseAxis.getAssociatedAxes( ).get( i );

				for ( int j = 0; j < assAxis.getSeriesDefinitions( ).size( ); j++ )
				{
					table.addSeriesDefinition( ( (SeriesDefinition) assAxis
							.getSeriesDefinitions( ).get( j ) ),
							getAxisTitle( assAxis ) );
				}
			}
		}

		return table;
	}

	private String getAxisTitle( Axis axis )
	{
		String title = axis.getTitle( ).getCaption( ).getValue( );
		return title.indexOf( '=' ) == 0 ? title.substring( 1 ) : title;
	}
}
