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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.birt.report.engine.ir.DataItemDesign;
import org.eclipse.birt.report.model.api.elements.structures.ComputedColumn;

public class TableBinding
{

	private ComputedColumn[] computedColumns = new ComputedColumn[0];
	private DataItemDesign[] dataItemDesigns = new DataItemDesign[0];
	private String[] columnExpressions = new String[0];
	private Map dataItemDesign2DataList = new HashMap( );
	
	private static Logger log = Logger.getLogger( TableBinding.class.getName( ) );

	public TableBinding( List cols )
	{
		if ( cols == null )
		{
			return;
		}
		
		computedColumns = new ComputedColumn[cols.size( )];
		
		for ( int i = 0; i < computedColumns.length; i++ )
		{
			computedColumns[i] = (ComputedColumn) cols.get( i );
			
			if ( computedColumns[i].getAggregateOn( ) == null )
			{
				computedColumns[i].setAggregateOn( "Table" );
			}
		}

		dataItemDesigns = new DataItemDesign[computedColumns.length];
	}

	public void dump( Map unsolvedDatas )
	{
		for ( Iterator it = dataItemDesign2DataList.entrySet( ).iterator( ); it
				.hasNext( ); )
		{
			List x = ( (List) ( (Map.Entry) it.next( ) ).getValue( ) );
			for ( int i = 0; i < x.size( ); i++ )
			{
				unsolvedDatas.put( x.get( i ), x.get( i ) );
			}
		}
		// case the table used repeatedly
		dataItemDesign2DataList.clear( );
	}	

	public void add2DataList( Object design, Data data )
	{
		Data d = (Data) data.clone( );
		// free the memory
		d.style = null;
		d.span = null;

		List x = (List) dataItemDesign2DataList.get( design );
		if ( x == null )
		{
			x = new ArrayList( );
			x.add( d );
			dataItemDesign2DataList.put( design, x );
		}
		else
		{
			x.add( d );
		}
	}

//	public Object getDataList( Object design )
//	{
//		return dataItemDesign2DataList.get( design );
//	}

	public boolean isAggregateData( Object data )
	{
		for ( int i = 0; i < dataItemDesigns.length; i++ )
		{
			if ( dataItemDesigns[i] == data )
			{
				return computedColumns[i].getExpression( ).startsWith( "Total" );

			}
		}
		
		return false;
	}

	public String[] getColumnExpression( )
	{
		if ( columnExpressions.length == 0 )
		{
			columnExpressions = new String[computedColumns.length];
			for ( int i = 0; i < columnExpressions.length; i++ )
			{
				columnExpressions[i] = computedColumns[i].getExpression( );
			}
		}
		return columnExpressions;
	}

	public int getDataItemDesignIndex( Object data )
	{
		for ( int i = 0; i < dataItemDesigns.length; i++ )
		{
			if ( dataItemDesigns[i] == data )
			{
				return i;
			}
		}
		return -1;
	}

	public void compute( GroupInfo root )
	{
		for ( int i = 0; i < dataItemDesigns.length; i++ )
		{
			Object o = dataItemDesign2DataList.get( dataItemDesigns[i] );
			if ( o != null )
			{
				List groupDatas = (List) o;
				String expression = computedColumns[i].getExpression( );
				if ( !ExcelUtil.isValidExp( expression, columnExpressions ) )
				{
					continue;
				}
				for ( int j = 0; j < groupDatas.size( ); j++ )
				{
					Data d = (Data) groupDatas.get( j );

					// dont replace txt if error occurs
					try
					{
						List ps = root.getByGroup( computedColumns[i]
								.getAggregateOn( ), ExcelUtil
								.getColumnOfExp( expression ), j );
						d.txt = ExcelUtil.createFormula( d.txt.toString( ), expression, ps );
						d.setNotTxtData( );
					}
					catch ( Throwable e )
					{
						log.log( Level.WARNING, "compute " + expression );
//						e.printStackTrace( );
					}
				}
			}
		}

	}

	public boolean tryBind( DataItemDesign data )
	{
		String columnName = (String) data.getHandle( ).getElement( )
				.getProperty( null, "resultSetColumn" );

		// dataItem doesnt bind any computedColumn
		if ( columnName == null )
		{
			return false;
		}
		for ( int i = 0; i < computedColumns.length; i++ )
		{
			if ( computedColumns[i].getName( ).equals( columnName ) )
			{
				dataItemDesigns[i] = data;
				return true;
			}
		}
		return false;
	}
}
