/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.engine.internal.document.v4;

import org.eclipse.birt.report.engine.api.DataID;
import org.eclipse.birt.report.engine.api.InstanceID;
import org.eclipse.birt.report.engine.executor.SuppressDuplicateUtil;
import org.eclipse.birt.report.engine.ir.BandDesign;
import org.eclipse.birt.report.engine.ir.ListingDesign;
import org.eclipse.birt.report.engine.ir.ReportItemDesign;

/**
 * An abstract class that defines execution logic for a Listing element, which
 * is the base element for table and list items.
 */
public abstract class ListingElementExecutor extends ContainerExecutor
{

	protected ListingElementExecutor( ExecutorManager manager, int type )
	{
		super( manager, type );
		executableElements = null;
		totalElements = 0;
		currentElement = 0;
		executorUtil = null;
	}

	public void close( )
	{
		// clear the duplicate flag in the listing
		SuppressDuplicateUtil.clearDuplicateFlags( design );
		executableElements = null;
		totalElements = 0;
		currentElement = 0;
		executorUtil = null;
		super.close( );
	}

	protected ReportItemExecutor doCreateExecutor( long offset )
			throws Exception
	{
		if ( currentElement >= totalElements )
		{
			// we need get the next executable elements.
			collectExecutables( );
		}

		if ( currentElement < totalElements )
		{
			ReportItemDesign childDesign = executableElements[currentElement];
			currentElement++;
			ReportItemExecutor childExecutor = manager.createExecutor( this,
					childDesign, offset );
			if ( childExecutor instanceof GroupExecutor )
			{
				GroupExecutor groupExecutor = (GroupExecutor) childExecutor;
				groupExecutor.setLisingExecutor( this );
			}
			return childExecutor;
		}
		return null;
	}

	protected void doSkipToExecutor( InstanceID iid, long offset )
			throws Exception
	{
		long uid = iid.getUniqueID( );
		DataID dataId = iid.getDataID( );
		long rowId = dataId.getRowID( );
		long rsetPosition = rset.getCurrentPosition( );
		if ( rsetPosition == rowId )
		{
			if ( currentElement >= totalElements )
			{
				collectExecutables( uid == 0, true );
			}
		}
		else
		{
			rset.skipTo( rowId );
			collectExecutables( uid == 0, true );
		}
		for ( int i = 0; i < totalElements; i++ )
		{
			if ( executableElements[i].getID( ) == iid.getComponentID( ) )
			{
				currentElement = i;
				return;
			}
		}
		currentElement = totalElements;
	}

	// bands to be execute in current row.
	private ReportItemDesign[] executableElements;
	// total bands in the executabelBands
	private int totalElements;
	// band to be executed
	private int currentElement;

	private ListingElementExecutorUtil executorUtil;

	protected void collectExecutables( )
	{
		collectExecutables( true, false );
	}

	protected void collectExecutables( boolean includeHeader,
			boolean useCurrentRow )
	{
		currentElement = 0;
		totalElements = 0;
		if ( executableElements == null )
		{
			ListingDesign listing = (ListingDesign) getDesign( );
			// prepare the bands to be executed.
			executableElements = new ReportItemDesign[3];
			if ( rset == null || rsetEmpty )
			{
				BandDesign header = listing.getHeader( );
				if ( header != null )
				{
					executableElements[totalElements++] = header;
				}
				BandDesign footer = listing.getFooter( );
				if ( footer != null )
				{
					executableElements[totalElements++] = footer;
				}
			}
			else
			{
				executorUtil = new ListingElementExecutorUtil( 0, listing
						.getHeader( ), listing.getFooter( ),
						listing.getGroupCount( ) == 0
								? (ReportItemDesign) listing.getDetail( )
								: (ReportItemDesign) listing.getGroup( 0 ),
						rset, includeHeader );
			}
		}
		if ( executorUtil != null )
		{
			if ( useCurrentRow )
			{
				executorUtil.startFromCurrentRow( );
			}
			totalElements = executorUtil
					.collectExecutableElements( executableElements );
		}
	}
}
