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

import org.eclipse.birt.report.engine.data.IResultSet;
import org.eclipse.birt.report.engine.ir.ReportItemDesign;

/**
 * the listing element is executing as:
 * <ul>
 * <li>for empty resutl set:</li>
 * <ul>
 * <li>execute the header</li>
 * <li>execute the footer</li>
 * </ul>
 * <li> for none empty result set:</li>
 * <ul>
 * <li>execute the header</li>
 * <li>execute the first group</li>
 * <li>while (!end of listing)</li>
 * <ul>
 * <li> skip to next row</li>
 * <li>execute the first group</li>
 * </ul>
 * <li>execute the footer.</li>
 * </ul>
 * </ul>
 * 
 * so we can organize the execution into three steps:
 * <ul>
 * <li> execute the header </li>
 * <li> execute the inner groups </li>
 * <li> execute the footer </li>
 * </ul>
 * and label those steps as:
 * <ul>
 * <li>EXECUTE_HEADER</li>
 * <li>EXECUTE_DETAIL</li>
 * <li>EXECUTE_FOOTER</li>
 * </ul>
 */
class ListingElementExecutorUtil
{

	private final static int EXECUTE_FROM_CURRENT_ROW = 0;
	private final static int EXECUTE_FROM_NEXT_ROW = 1;
	private final static int EXECUTE_END = 3;

	int group;
	ReportItemDesign header;
	ReportItemDesign child;
	ReportItemDesign footer;
	IResultSet rset;
	int executeState;
	boolean includeHeader;

	ListingElementExecutorUtil( int group, ReportItemDesign header,
			ReportItemDesign footer, ReportItemDesign child, IResultSet rset )
	{
		this( group, header, footer, child, rset, true );
	}

	ListingElementExecutorUtil( int group, ReportItemDesign header,
			ReportItemDesign footer, ReportItemDesign child, IResultSet rset,
			boolean fromBegin )
	{
		this.group = group;
		this.header = header;
		this.footer = footer;
		this.child = child;
		this.rset = rset;
		this.executeState = EXECUTE_FROM_CURRENT_ROW;
		this.includeHeader = fromBegin;
	}

	public void startFromCurrentRow( )
	{
		if ( executeState != EXECUTE_END )
		{
			executeState = EXECUTE_FROM_CURRENT_ROW;
		}
	}

	int collectExecutableElements( ReportItemDesign[] executableElements )
	{
		while ( executeState != EXECUTE_END )
		{
			int totalElements = doCollectExecutableElements( executableElements );
			if ( totalElements != 0 )
			{
				return totalElements;
			}
		}
		return 0;
	}

	private int doCollectExecutableElements(
			ReportItemDesign[] executableElements )
	{
		int totalElements = 0;

		switch ( executeState )
		{
			case EXECUTE_FROM_CURRENT_ROW :
				if ( includeHeader && header != null )
				{
					includeHeader = false;
					executableElements[totalElements++] = header;
				}
				if ( child != null )
				{
					executableElements[totalElements++] = child;
				}
				executeState = EXECUTE_FROM_NEXT_ROW;
				if ( isGroupEnd( ) )
				{
					if ( footer != null )
					{
						executableElements[totalElements++] = footer;
					}
					executeState = EXECUTE_END;
				}
				break;
			case EXECUTE_FROM_NEXT_ROW :
				if ( isGroupEnd( ) )
				{
					if ( footer != null )
					{
						executableElements[totalElements++] = footer;
					}
					executeState = EXECUTE_END;
					return totalElements;
				}
				if ( rset.next( ) )
				{
					if ( child != null )
					{
						executableElements[totalElements++] = child;
					}
					if ( isGroupEnd( ) )
					{
						if ( footer != null )
						{
							executableElements[totalElements++] = footer;
						}
						executeState = EXECUTE_END;
					}
					return totalElements;
				}
				break;
		}
		return totalElements;
	}

	boolean isGroupEnd( )
	{
		int groupLevel = rset.getEndingGroupLevel( );
		if ( groupLevel <= group )
		{
			return true;
		}
		return false;
	}
}
