/*******************************************************************************
 * 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.data.engine.impl.rd;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.birt.core.data.DataType;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.script.JavascriptEvalUtil;
import org.eclipse.birt.data.engine.api.DataEngine;
import org.eclipse.birt.data.engine.api.DataEngineContext;
import org.eclipse.birt.data.engine.api.IBaseExpression;
import org.eclipse.birt.data.engine.api.IJoinCondition;
import org.eclipse.birt.data.engine.api.IQueryResults;
import org.eclipse.birt.data.engine.api.IResultIterator;
import org.eclipse.birt.data.engine.api.ISortDefinition;
import org.eclipse.birt.data.engine.api.querydefn.BaseDataSetDesign;
import org.eclipse.birt.data.engine.api.querydefn.BaseQueryDefinition;
import org.eclipse.birt.data.engine.api.querydefn.ComputedColumn;
import org.eclipse.birt.data.engine.api.querydefn.GroupDefinition;
import org.eclipse.birt.data.engine.api.querydefn.JoinCondition;
import org.eclipse.birt.data.engine.api.querydefn.JointDataSetDesign;
import org.eclipse.birt.data.engine.api.querydefn.OdaDataSetDesign;
import org.eclipse.birt.data.engine.api.querydefn.QueryDefinition;
import org.eclipse.birt.data.engine.api.querydefn.ScriptExpression;
import org.eclipse.birt.data.engine.api.querydefn.SortDefinition;
import org.eclipse.birt.data.engine.api.querydefn.SubqueryDefinition;
import org.eclipse.birt.data.engine.core.DataException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.IdScriptableObject;
import org.mozilla.javascript.ScriptableObject;

import testutil.ConfigText;
import testutil.JDBCOdaDataSource;

/**
 * Test the feature of report document. A life cycle of report document can be
 * divided into two parts, one is generation and the other is presentation. Once
 * a report can be generated once, it can be presented many times. In generation
 * time, query results ID and expression id needs to be stored. These ID are
 * automatically generated by DtE implemenation. In presentation time, query
 * results ID is first used to retrieve the query result, and then expression ID
 * can be used to retrieve the detailed data.
 */
public class ReportDocumentTest extends RDTestCase
{
	private ScriptableObject subScope;
	private ScriptableObject subOfSubScope;

	// id to store
	private String queryResultID;
	private String[] rowExprName;
	private String[] totalExprName;

	// name of sub query
	private String subQueryName = "test";

	// name of sub query of sub query
	private String subOfSubQueryName = "test2";

	// value to compare
	private List expectedValue;
	private List expectedStartingGroupLevelValueList;
	private List expectedEndingGroupLevelValueList;
	
	/*
	 * @see org.eclipse.birt.data.engine.api.APITestCase#getDataSourceInfo()
	 */
	protected DataSourceInfo getDataSourceInfo( )
	{
		return new DataSourceInfo( ConfigText.getString( "Api.TestData.TableName" ),
				ConfigText.getString( "Api.TestData.TableSQL" ),
				ConfigText.getString( "Api.TestData.TestDataFileName" ) );
	}
	
	/*
	 * @see junit.framework.TestCase#setUp()
	 */
	public void setUp( ) throws Exception
	{
		super.setUp( );
		
		expectedValue = new ArrayList( );
		expectedStartingGroupLevelValueList = new ArrayList( );
		expectedEndingGroupLevelValueList = new ArrayList( );
		
		Context context = Context.enter( );
		
		subScope = context.initStandardObjects( );
		subScope.setPrototype( scope );

		subOfSubScope = context.initStandardObjects( );
		subOfSubScope.setPrototype( subScope );
		
		Context.exit( );
	}
	
	/**
	 * Basic report document test without sub query, but it has aggregation.
	 * 
	 * @throws BirtException
	 */
	public void testBasic( ) throws BirtException
	{
		this.genBasic( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preBasic( );
		this.closeArchiveReader( );
	}

	/**
	 * Basic report document test without sub query, but it has aggregation.
	 * @throws Exception 
	 */
	public void testJointDataSet( ) throws Exception
	{
		
		OdaDataSetDesign dset1 = new OdaDataSetDesign( "dset1" );
		dset1.setDataSource( this.dataSource.getName( ) );
		dset1.setQueryText( "Select * FROM "
				+ this.getTestTableName( ) );
		dset1.setExtensionID( JDBCOdaDataSource.DATA_SET_TYPE );
		
		OdaDataSetDesign dset2 = new OdaDataSetDesign( "dset2" );
		dset2.setDataSource( this.dataSource.getName( ) );
		dset2.setQueryText( "Select * FROM "
				+ this.getTestTableName( ) );
		dset2.setExtensionID( JDBCOdaDataSource.DATA_SET_TYPE );
		
		List a = new ArrayList();
		a.add( new JoinCondition(new ScriptExpression("dataSetRow.CITY"),new ScriptExpression("dataSetRow.CITY"),IJoinCondition.OP_EQ) );
	
		JointDataSetDesign dset3 = new JointDataSetDesign( "dset3", dset1.getName( ), dset2.getName( ), 0, a );
		myGenDataEngine.defineDataSet( dset1 );
		myGenDataEngine.defineDataSet( dset2 );
		myGenDataEngine.defineDataSet( dset3 );
	
		QueryDefinition query = this.newReportQuery( dset3 );
		
		// prepare
		IBaseExpression[] rowBeArray = new IBaseExpression[6];
		
		rowBeArray[0] = new ScriptExpression("dataSetRow[\"dset1::CITY\"]");
		rowBeArray[1] = new ScriptExpression("dataSetRow[\"dset2::CITY\"]");
		rowBeArray[2] = new ScriptExpression("dataSetRow[\"dset1::COUNTRY\"]");
		rowBeArray[3] = new ScriptExpression("dataSetRow[\"dset2::COUNTRY\"]");
		rowBeArray[4] = new ScriptExpression("dataSetRow[\"dset1::AMOUNT\"]");
		rowBeArray[5] = new ScriptExpression("dataSetRow[\"dset2::AMOUNT\"]");
						
		//		 prepare
		rowExprName = new String[]{"CITY1","CITY2","COUNTRY1","COUNTRY2","AMOUNT1","AMOUNT2"};
		
		prepareExprNameAndQuery( rowExprName, rowBeArray, new String[0], new IBaseExpression[0], query );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( query ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, new IBaseExpression[0] );
		
		IResultIterator ri = qr.getResultIterator( );		
		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );
		}

		ri.close( );
	
		qr.close( );
	
		myGenDataEngine.shutdown( );
		
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preBasic( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genBasic( ) throws BirtException
	{
		QueryDefinition qd = newReportQuery( );
		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName,rowBeArray, totalExprName, totalBeArray, qd );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri.getValue( totalExprName[i] ) );
		}

		ri.close( );
		ri.close( );
		qr.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasic( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult1( ri );

		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	public void testBasicSkip( ) throws BirtException
	{
		this.genBasicSkip( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		final int skipCount = 3;
		this.preBasicSkip( skipCount );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genBasicSkip( ) throws BirtException
	{
		genBasic( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasicSkip( int skipCount ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult3( ri, skipCount );
		
		ri.close( );
		myPreDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	public void testBasicMove( ) throws BirtException
	{
		this.genBasicMove( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		int[] destIndex = new int[]{
				1, 3, 4, 6, 7
		}; 
		this.preBasicMove( destIndex );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genBasicMove( ) throws BirtException
	{
		genBasic( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasicMove( int[] destIndex ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult4( ri, destIndex, true );
		
		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * Without use next 
	 * 
	 * @throws BirtException
	 */
	public void testBasicMove2( ) throws BirtException
	{
		this.genBasicMove2( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		int[] destIndex = new int[]{
				1, 3, 4, 6, 7
		}; 
		this.preBasicMove2( destIndex );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genBasicMove2( ) throws BirtException
	{
		genBasic( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasicMove2( int[] destIndex ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult4( ri, destIndex, false );
		
		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	public void testBasicDiskCache( ) throws BirtException
	{
		System.setProperty( "birt.data.engine.test.memcachesize", "5" );
		this.testBasic( );
	}
	
	/**
	 * Test the expression on the group header
	 * @throws BirtException
	 */
	public void testGroupBeforeExpr( ) throws BirtException
	{
		this.genGroupBeforeExpr( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preGroupBeforeExpr( );
		this.closeArchiveReader( );
	}
	
	private String beforeExprID;
	
	/**
	 *
	 */
	private void genGroupBeforeExpr( ) throws BirtException
	{
		QueryDefinition qd = newReportQuery( );

		GroupDefinition groupDefn = new GroupDefinition( "G1");
		groupDefn.setKeyColumn( "COUNTRY" );
		qd.addGroup( groupDefn );
		qd.addResultSetExpression("COUNTRY", new ScriptExpression( "dataSetRow.COUNTRY" ));
		IBaseExpression rowExpr = new ScriptExpression( "dataSetRow.COUNTRY" );
		rowExpr.setGroupName("G1");
		beforeExprID = "BEFOREEXPRID";
		qd.addResultSetExpression(beforeExprID, rowExpr);
		//groupDefn.addExpression( rowExpr, BaseTransform.BEFORE_FIRST_ROW );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );

		queryResultID = qr.getID( );
		
						
		IResultIterator ri = qr.getResultIterator( );
		while ( ri.next( ) )
		{
			if ( ri.getStartingGroupLevel( ) <= 1 )
			{
				expectedValue.add( ri.getValue( beforeExprID ) );
				System.out.println( ri.getValue( beforeExprID ) );
			}
		}

		ri.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	private void preGroupBeforeExpr( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );

		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );

		Iterator it = this.expectedValue.iterator( );

		while ( ri.next( ) )
		{
			if ( ri.getStartingGroupLevel( ) <= 0 )
			{
				String str = "";
				Object ob1 = it.next( );
				Object ob2 = ri.getValue( beforeExprID );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
				System.out.println( "row result set: " + str );
			}
		}

		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * Basic report document test without sub query, but it has aggregation.
	 * 
	 * @throws BirtException
	 */
	public void testBasicGroupLevel( ) throws BirtException
	{
		this.genBasicGroupLevel( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preBasicGroupLevel( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException 
	 */
	private void genBasicGroupLevel( ) throws BirtException
	{
		QueryDefinition qd = newReportQuery( );

		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName,rowBeArray, totalExprName,totalBeArray, qd );
		
		GroupDefinition groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "COUNTRY" );
		qd.addGroup( groupDefn );
		
		groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "CITY" );
		qd.addGroup( groupDefn );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri.getValue( totalExprName[i] ) );
			
			this.expectedStartingGroupLevelValueList.add( new Integer( ri.getStartingGroupLevel( ) ) );
			this.expectedEndingGroupLevelValueList.add( new Integer( ri.getEndingGroupLevel( ) ) );
		}

		ri.close( );
		ri.close( );
		qr.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasicGroupLevel( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult2( ri );

		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	public void testBasicMoveWithGroup( ) throws BirtException
	{
		this.genBasicMoveWithGroup( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		final int destIndex = 6;
		this.preBasicMoveWithGroup( destIndex );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genBasicMoveWithGroup( ) throws BirtException
	{
		genBasicGroupLevel( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasicMoveWithGroup( int destIndex ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult2( ri, destIndex );
		
		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	public void testBasicSkipToEnd( ) throws BirtException
	{
		this.genBasicSkipToEnd( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preBasicSkipToEnd( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException 
	 */
	private void genBasicSkipToEnd( ) throws BirtException
	{
		QueryDefinition qd = newReportQuery( );

		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		
		prepareExprNameAndQuery( rowExprName,rowBeArray, totalExprName,totalBeArray, qd );
		
		GroupDefinition groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "COUNTRY" );
		qd.addGroup( groupDefn );
		
		groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "CITY" );
		qd.addGroup( groupDefn );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );
		ri.next( );
		ri.skipToEnd( 1 );
		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri.getValue( totalExprName[i] ) );

			this.expectedStartingGroupLevelValueList.add( new Integer( ri.getStartingGroupLevel( ) ) );
			this.expectedEndingGroupLevelValueList.add( new Integer( ri.getEndingGroupLevel( ) ) );
		} 

		ri.close( );
		ri.close( );
		qr.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preBasicSkipToEnd( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		ri.next( );
		ri.skipToEnd( 1 );
		checkResult2( ri );

		ri.close( );
		myPreDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	public void testBasicFooter( ) throws BirtException
	{
		int countOfRow = 8;
		List genValue = null;
		{
			QueryDefinition qd = newReportQuery( );
			// prepare
			IBaseExpression[] rowBeArray = getRowExpr( );
			IBaseExpression[] totalBeArray = getAggrExpr( );
			rowExprName = getRowExprName( );
			totalExprName = getAggrExprName( );
			prepareExprNameAndQuery( rowExprName,
					rowBeArray,
					totalExprName,
					totalBeArray,
					qd );

			// generation
			IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );

			// important step
			saveForPresentation( qr, rowBeArray, totalBeArray );

			IResultIterator ri = qr.getResultIterator( );

			int currRow = -1;
			while ( ri.next( ) )
			{
				currRow++;
				if ( currRow == countOfRow - 1 )
				{
					genValue = new ArrayList( );
					for ( int i = 0; i < rowBeArray.length; i++ )
						genValue.add( ri.getValue( rowExprName[i] ) );

					for ( int i = 0; i < totalBeArray.length; i++ )
						genValue.add( ri.getValue( totalExprName[i] ) );
				}
			}
			ri.close( );
			ri.close( );
			qr.close( );
			qr.close( );
			myGenDataEngine.shutdown( );
		}

		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		List preValue = null;
		{
			IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
			IResultIterator ri = qr.getResultIterator( );
			ri.moveTo( countOfRow - 1 );
			
			preValue = new ArrayList( );
			if ( rowExprName != null )
			{
				for ( int i = 0; i < rowExprName.length; i++ )
				{
					Object ob2 = ri.getValue( rowExprName[i] );
					preValue.add( ob2 );
				}
			}
			if ( totalExprName != null )
			{
				for ( int i = 0; i < totalExprName.length; i++ )
				{
					Object ob2 = ri.getValue( totalExprName[i] );
					preValue.add( ob2 );
				}
			}

			ri.close( );
			myPreDataEngine.shutdown( );
			this.closeArchiveReader( );
		}
		
		Iterator it1 = genValue.iterator( );
		Iterator it2 = preValue.iterator( );
		String str = "";
		while ( it1.hasNext( ) )
		{
			Object ob2 = it2.next( );
			assertTrue( it1.next( ).equals( ob2 ) );
			str += ob2.toString( ) + " ";
		}
		System.out.println( "row result set: " + str );
	}
	
	/**
	 * Basic report document test without sub query, but its use details
	 * property is false;
	 * 
	 * @throws BirtException
	 */
	public void testBasicGroupLevel2( ) throws BirtException
	{
		this.genBasicGroupLevel2( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preBasicGroupLevel2( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException 
	 */
	private void genBasicGroupLevel2( ) throws BirtException
	{
		QueryDefinition qd = newReportQuery( );
		qd.setUsesDetails( false );

		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName,rowBeArray, totalExprName,totalBeArray, qd );
		
		GroupDefinition groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "COUNTRY" );
		qd.addGroup( groupDefn );
		
		groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "CITY" );
		qd.addGroup( groupDefn );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri.getValue( totalExprName[i] ) );
			
			this.expectedStartingGroupLevelValueList.add( new Integer( ri.getStartingGroupLevel( ) ) );
			this.expectedEndingGroupLevelValueList.add( new Integer( ri.getEndingGroupLevel( ) ) );
		}

		ri.close( );
		ri.close( );
		qr.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preBasicGroupLevel2( ) throws BirtException
	{
		// ---next test
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult2( ri );

		ri.close( );
		
		System.out.println("--------move to test1--------");
		
		// ---moveTo test
		qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult2( ri, 0 );

		ri.close( );
		
		System.out.println("--------move to test2--------");
		
		// ---moveTo test
		qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );
		
		ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );
		
		checkResult2( ri, 2 );
		
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * Basic sub query test for report document.
	 * 
	 * @throws BirtException
	 */
	public void testSubQuery( ) throws BirtException
	{
		this.genSubQuery( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
				
		this.preSubQuery( );
		this.closeArchiveReader( );
	}

	/**
	 * @throws BirtException
	 */
	private void genSubQuery( ) throws BirtException
	{
		QueryDefinition queryDefn = newReportQuery( );

		// add sub query
		GroupDefinition groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "COUNTRY" );
		queryDefn.addGroup( groupDefn );
		//		 prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		
		prepareExprNameAndQuery( rowExprName, rowBeArray, totalExprName, totalBeArray,queryDefn );
		
		SubqueryDefinition subQueryDefn = new SubqueryDefinition( subQueryName );
		groupDefn.addSubquery( subQueryDefn );

		// sort on sub query
		SortDefinition sortDefn = new SortDefinition( );
		sortDefn.setColumn( "AMOUNT" );
		sortDefn.setSortDirection( ISortDefinition.SORT_DESC );
		subQueryDefn.addSort( sortDefn );
		
		
		prepareExprNameAndQuery( rowExprName, rowBeArray, totalExprName, totalBeArray, subQueryDefn );

		// generation
		IQueryResults qr = myGenDataEngine.prepare( queryDefn ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		
		int loopCount = 5;
		for ( int i = 0; i < loopCount; i++ )
			ri.next( );

		IResultIterator ri2 = ri.getSecondaryIterator( subQueryName, subScope );

		while ( ri2.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri2.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri2.getValue( totalExprName[i] ) );
		}

		ri2.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preSubQuery( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		IResultIterator ri = qr.getResultIterator( );

		int loopCount = 5;
		for ( int i = 0; i < loopCount; i++ )
			ri.next( );

		IResultIterator ri2 = ri.getSecondaryIterator( subQueryName, subScope );

		checkResult1( ri2 );

		ri2.close( );
		qr.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * Sub query test2 for report document. This query has two features:
	 * 1: sub query is added on the query, not on group
	 * 2: the point of the parent query moves to the end
	 * 
	 * @throws BirtException
	 */
	public void testSubQuery2( ) throws BirtException
	{
		this.genSubQuery2( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
				
		this.preSubQuery2( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genSubQuery2( ) throws BirtException
	{
		QueryDefinition queryDefn = newReportQuery( );

		SubqueryDefinition subQueryDefn = new SubqueryDefinition( subQueryName );
		queryDefn.addSubquery( subQueryDefn );
		
		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName, rowBeArray, totalExprName, totalBeArray, subQueryDefn );

		// generation
		IQueryResults qr = myGenDataEngine.prepare( queryDefn ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		
		while ( ri.next( ) );

		IResultIterator ri2 = ri.getSecondaryIterator( subQueryName, subScope );

		while ( ri2.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri2.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri2.getValue( totalExprName[i] ) );
		}

		ri2.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preSubQuery2( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		IResultIterator ri = qr.getResultIterator( );

		while ( ri.next( ) );

		IResultIterator ri2 = ri.getSecondaryIterator( subQueryName, subScope );

		checkResult1( ri2 );

		ri2.close( );
		qr.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	public void testSubQuery3( ) throws BirtException
	{
		this.genSubQuery3( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
				
		this.preSubQuery3( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genSubQuery3( ) throws BirtException
	{
		QueryDefinition queryDefn = newReportQuery( );
		
		SubqueryDefinition subQueryDefn = new SubqueryDefinition( subQueryName );
		subQueryDefn.setApplyOnGroupFlag( false );
		queryDefn.addSubquery( subQueryDefn );
		
		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName, rowBeArray, totalExprName, totalBeArray, subQueryDefn );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( queryDefn ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		
		while ( ri.next( ) )
		{
			IResultIterator ri2 = ri.getSecondaryIterator( subQueryName,
					subScope );
			
			while ( ri2.next( ) )
			{
				for ( int i = 0; i < rowBeArray.length; i++ )
					expectedValue.add( ri2.getValue( rowExprName[i] ) );
				
				for ( int i = 0; i < totalBeArray.length; i++ )
					expectedValue.add( ri2.getValue( totalExprName[i] ) );
			}
			ri2.close( );
		}
		
		qr.close( );
		myGenDataEngine.shutdown( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void preSubQuery3( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		IResultIterator ri = qr.getResultIterator( );
		Iterator it = expectedValue.iterator( );
		
		while ( ri.next( ) )
		{
			IResultIterator ri2 = ri.getSecondaryIterator( subQueryName,
					subScope );
			
			checkResult1( it, ri2 );
			ri2.close( );
		}
		
		qr.close( );
		myPreDataEngine.shutdown( );
	}

	/**
	 * Advanced sub query test. A sub query is retrieved from another sub query.
	 * 
	 * @throws BirtException
	 */
	public void testSubOfSubQuery( ) throws BirtException
	{
		this.genSubOfSubQuery( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preSubOfSubQuery( );
		this.closeArchiveReader( );
	}

	/**
	 * @throws BirtException
	 */
	private void genSubOfSubQuery( ) throws BirtException
	{
		QueryDefinition queryDefn = newReportQuery( );

		// add sub query
		GroupDefinition groupDefn = new GroupDefinition( );
		groupDefn.setKeyColumn( "COUNTRY" );
		queryDefn.addGroup( groupDefn );
		queryDefn.addResultSetExpression("COUNTRY", new ScriptExpression("dataSetRow.COUNTRY"));
		SubqueryDefinition subQueryDefn = new SubqueryDefinition( subQueryName );
		groupDefn.addSubquery( subQueryDefn );

		// add sub query of sub query
		GroupDefinition subGroupDefn = new GroupDefinition( );
		subGroupDefn.setKeyColumn( "CITY" );
		subQueryDefn.addGroup( subGroupDefn );
		subQueryDefn.addResultSetExpression("CITY", new ScriptExpression("dataSetRow.CITY"));
		SubqueryDefinition subOfSubQueryDefn = new SubqueryDefinition( subOfSubQueryName );
		subGroupDefn.addSubquery( subOfSubQueryDefn );

		// prepare
		IBaseExpression[] rowBeArray = getRowExpr( );
		IBaseExpression[] totalBeArray = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName, rowBeArray, totalExprName, totalBeArray, subOfSubQueryDefn );

		// generation
		IQueryResults qr = myGenDataEngine.prepare( queryDefn ).execute( subScope );
				
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );

		ri.next( );
		IResultIterator ri2 = ri.getSecondaryIterator( subQueryName, scope );
		ri2.next( );

		IResultIterator ri3 = ri2.getSecondaryIterator( subOfSubQueryName, subOfSubScope );
		while ( ri3.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri3.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri3.getValue( totalExprName[i] ) );
		}

		ri3.close( );		
		ri2.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preSubOfSubQuery( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		IResultIterator ri = qr.getResultIterator( );

		ri.next( );
		IResultIterator ri2 = ri.getSecondaryIterator( subQueryName, subScope );
		ri2.next( );		

		IResultIterator ri3 = ri2.getSecondaryIterator( subOfSubQueryName, subOfSubScope );

		checkResult1( ri3 );

		ri3.close( );
		qr.close( );
		myPreDataEngine.shutdown( );
	}

	/**
	 * Basic report document test with nested query
	 * 
	 * @throws BirtException
	 */
	public void testNestedQuery( ) throws BirtException
	{
		this.genNestedQuery( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preNestedQuery( );
		this.closeArchiveReader( );
	}

	/**
	 * @throws BirtException
	 */
	private void genNestedQuery( ) throws BirtException
	{
		QueryDefinition qd = newReportQuery( );

		// prepare
		IBaseExpression[] rowBeArray1 = getRowExpr( );
		IBaseExpression[] totalBeArray1 = getAggrExpr( );
		rowExprName = getRowExprName();
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName, rowBeArray1, totalExprName, totalBeArray1, qd );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );
		qr.getResultIterator( ).next( );

		Context cx = Context.enter( );
		ScriptableObject nestedScope = cx.initStandardObjects( );
		nestedScope.setPrototype( this.scope );
		Context.exit( );

		QueryDefinition nestedQD = newReportQuery( );
		IBaseExpression[] tempArray2 = getRowExpr( );
		int length = tempArray2.length;
		IBaseExpression[] rowBeArray2 = new IBaseExpression[length + 1];
		System.arraycopy( tempArray2, 0, rowBeArray2, 0, length );
		rowBeArray2[length] = new ScriptExpression( "rows[0].AMOUNT" );
		rowExprName = new String[rowBeArray2.length];
		for( int i = 0; i < rowExprName.length; i++)
		{
			rowExprName[i] = "NAME_"+i;
		}
		IBaseExpression[] totalBeArray2 = getAggrExpr( );
		
		totalExprName = getAggrExprName();
		
		prepareExprNameAndQuery( rowExprName, rowBeArray2, totalExprName,totalBeArray2, nestedQD );

		IQueryResults qr2 = myGenDataEngine.prepare( nestedQD ).execute( qr,
				nestedScope );
		IResultIterator ri = qr2.getResultIterator( );

		// important step
		saveForPresentation( qr2, rowBeArray2, totalBeArray2 );

		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray2.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray2.length; i++ )
				expectedValue.add( ri.getValue( totalExprName[i] ) );
		}

		ri.close( );
		qr2.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preNestedQuery( ) throws BirtException
	{
		this.preBasic( );
	}
	
	/**
	 * Basic report document test with computed column
	 * 
	 * @throws BirtException
	 */
	public void testComputedColumn( ) throws BirtException
	{
		this.genComputedColumn( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preComputedColumn( );
		this.closeArchiveReader( );
	}

	/**
	 * @throws BirtException
	 */
	private void genComputedColumn( ) throws BirtException
	{
		String[] ccName = new String[]{
				"cc1", "cc2"
		};
		String[] ccExpr = new String[]{
				"row.COUNTRY", "row.AMOUNT*100"
		};
		int[] dataTypes = new int[]{
				DataType.STRING_TYPE, DataType.INTEGER_TYPE
		};
		for ( int i = 0; i < 2; i++ )
		{
			ComputedColumn computedColumn = new ComputedColumn( ccName[i],
					ccExpr[i],
					dataTypes[i] );
			( (BaseDataSetDesign) this.dataSet ).addComputedColumn( computedColumn );
		}
		
		QueryDefinition qd = newReportQuery( );

		// prepare
		IBaseExpression[] tempArray = getRowExpr( );
		int length = tempArray.length;
		IBaseExpression[] rowBeArray = new IBaseExpression[length + 2];
		System.arraycopy( tempArray, 0, rowBeArray, 0, length );
		for ( int i = 0; i < ccName.length; i++ )
			rowBeArray[length + i] = new ScriptExpression( "dataSetRow." + ccName[i] );
		
		rowExprName = new String[rowBeArray.length];
		for( int i = 0; i < rowExprName.length; i++)
		{
			rowExprName[i] = "NAME_"+i;
		}
		
		IBaseExpression[] totalBeArray = getAggrExpr( );
		totalExprName = getAggrExprName();
		prepareExprNameAndQuery( rowExprName, rowBeArray, totalExprName, totalBeArray, qd );
		
		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );
		
		// important step
		saveForPresentation( qr, rowBeArray, totalBeArray );
		
		IResultIterator ri = qr.getResultIterator( );		
		while ( ri.next( ) )
		{
			for ( int i = 0; i < rowBeArray.length; i++ )
				expectedValue.add( ri.getValue( rowExprName[i] ) );

			for ( int i = 0; i < totalBeArray.length; i++ )
				expectedValue.add( ri.getValue( totalExprName[i] ) );
		}

		ri.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preComputedColumn( ) throws BirtException
	{
		this.preBasic( );
	}
	
	/**
	 * @return row expression array
	 */
	private IBaseExpression[] getRowExpr( )
	{
		// row test
		int num = 4;
		IBaseExpression[] rowBeArray = new IBaseExpression[num];
		rowBeArray[0] = new ScriptExpression( "dataSetRow.COUNTRY" );
		rowBeArray[1] = new ScriptExpression( "dataSetRow.CITY" );
		rowBeArray[2] = new ScriptExpression( "dataSetRow.SALE_DATE" );
		rowBeArray[3] = new ScriptExpression( "dataSetRow.AMOUNT" );

		return rowBeArray;
	}

	/**
	 * @return row expression array
	 */
	private String[] getRowExprName( )
	{
		// row test
		int num = 4;
		String[] rowBeArray = new String[num];
		rowBeArray[0] = "COUNTRY";
		rowBeArray[1] = "CITY";
		rowBeArray[2] = "SALE_DATE";
		rowBeArray[3] = "AMOUNT";

		return rowBeArray;
	}
	/**
	 * @return aggregation expression array
	 */
	private IBaseExpression[] getAggrExpr( )
	{
		int num2 = 2;
		IBaseExpression[] totalBeArray = new IBaseExpression[num2];
		totalBeArray[0] = new ScriptExpression( "Total.Count( )" );
		totalBeArray[1] = new ScriptExpression( "Total.Sum( dataSetRow.AMOUNT )" );

		return totalBeArray;
	}

	/**
	 * @return aggregation expression array
	 */
	private String[] getAggrExprName( )
	{
		int num2 = 2;
		String[] totalBeArray = new String[num2];
		totalBeArray[0] = "Total.Count( )";
		totalBeArray[1] = "Total.Sum( dataSetRow.AMOUNT )";

		return totalBeArray;
	}
	/**
	 * Add expression on the row of group
	 * @param rowBeArray
	 * @param totalBeArray
	 * @param qd
	 */
	private void prepareExprNameAndQuery( String[] rowBeName, IBaseExpression[] rowBeArray,
			String[] totalBeName, IBaseExpression[] totalBeArray, BaseQueryDefinition qd )
	{
		for ( int i = 0; i < rowBeName.length; i++ )
			qd.addResultSetExpression( rowBeName[i], rowBeArray[i]);

		for ( int i = 0; i < totalBeName.length; i++ )
			qd.addResultSetExpression( totalBeName[i], totalBeArray[i]);
	}
	
	/**
	 * @param rowBeArray
	 * @param totalBeArray
	 */
	private void saveForPresentation( IQueryResults queryResuls,
			IBaseExpression[] rowBeArray, IBaseExpression[] totalBeArray )
	{
		queryResultID = queryResuls.getID( );
	}

	/**
	 * Only check the result of the expectedValue of the result set
	 * 
	 * @param it
	 * @param ri
	 * @throws DataException
	 * @throws BirtException
	 */
	private void checkResult1( IResultIterator ri )
			throws BirtException
	{
		Iterator it = this.expectedValue.iterator( );
		checkResult1( it, ri );
	}
	
	/**
	 * @param it
	 * @param ri
	 * @throws BirtException
	 */
	private void checkResult1(Iterator it, IResultIterator ri)
			throws BirtException 
	{
		while (ri.next()) 
		{
			String str = "";
			if (rowExprName != null) 
			{
				for (int i = 0; i < rowExprName.length; i++) 
				{
					Object ob1 = it.next();
					Object ob2 = ri.getValue(rowExprName[i]);
					assertEquals(ob1, ob2);
					str += " " + ob2.toString();
				}
			}
			if (totalExprName != null) 
			{
				for (int i = 0; i < totalExprName.length; i++) 
				{
					Object ob1 = it.next();
					Object ob2 = ri.getValue(totalExprName[i]);
					assertEquals(ob1, ob2);
					str += " " + ob2.toString();
				}
			}
			System.out.println("row result set: " + str);
		}
	}

	/**
	 * Check the result of the row result set and the starting and ending group
	 * level
	 * 
	 * @param ri
	 * @throws BirtException
	 */
	private void checkResult2( IResultIterator ri ) throws BirtException
	{
		Iterator it = this.expectedValue.iterator( );
		Iterator it1 = this.expectedStartingGroupLevelValueList.iterator( );
		Iterator it2 = this.expectedEndingGroupLevelValueList.iterator( );

		while ( ri.next( ) )
		{
			String str = "";
			for ( int i = 0; i < rowExprName.length; i++ )
			{
				Object ob1 = it.next( );
				Object ob2 = ri.getValue(rowExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
			}

			for ( int i = 0; i < totalExprName.length; i++ )
			{
				Object ob1 = it.next( );
				Object ob2 = ri.getValue( totalExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
			}

			System.out.println( "row result set: " + str );

			str = "";
			Integer value1 = (Integer) it1.next( );
			int value2 = ri.getStartingGroupLevel( );
			assertEquals( value1.intValue( ), value2 );
			str += " staring: " + value1;

			Integer value3 = (Integer) it2.next( );
			int value4 = ri.getEndingGroupLevel( );
			assertEquals( value3.intValue( ), value4 );
			str += " ending " + value3;

			System.out.println( "row group level value: " + str );
		}
	}

	/**
	 * Check the result of the row result set and the starting and ending group level  
	 * 
	 * @param ri
	 * @throws BirtException
	 */
	private void checkResult2( IResultIterator ri, int destIndex ) throws BirtException
	{
		Iterator it = this.expectedValue.iterator( );
		Iterator it1 = this.expectedStartingGroupLevelValueList.iterator( );
		Iterator it2 = this.expectedEndingGroupLevelValueList.iterator( );

		for ( int k = 0; k < destIndex; k++ )
		{
			for ( int i = 0; i < rowExprName.length; i++ )
				it.next( );
			for ( int i = 0; i < totalExprName.length; i++ )
				it.next( );
			it1.next( ); // for starting group level
			it2.next( ); // for ending group level
		}
		
		if ( destIndex >= 1 )
			ri.moveTo( destIndex - 1 );
		
		while ( ri.next( ) )
		{
			String str = "";
			for ( int i = 0; i < rowExprName.length; i++ )
			{
				Object ob1 = it.next( );
				Object ob2 = ri.getValue( rowExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
			}

			for ( int i = 0; i < totalExprName.length; i++ )
			{
				Object ob1 = it.next( );
				Object ob2 = ri.getValue( totalExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
			}

			System.out.println( "row result set: " + str );

			str = "";
			Integer value1 = (Integer) it1.next( );
			int value2 = ri.getStartingGroupLevel( );
			assertEquals( value1.intValue( ), value2 );
			str += " staring: " + value1;

			Integer value3 = (Integer) it2.next( );
			int value4 = ri.getEndingGroupLevel( );
			assertEquals( value3.intValue( ), value4 );
			str += " ending " + value3;

			System.out.println( "row group level value: " + str );
		}
	}
	
	/**
	 * Skip specified skipCount at the begining.
	 * 
	 * @param ri
	 * @param skipCount
	 * @throws BirtException
	 */
	private void checkResult3( IResultIterator ri, int skipCount )
			throws BirtException
	{
		Iterator it = this.expectedValue.iterator( );

		for ( int k = 0; k < skipCount; k++ )
		{
			for ( int i = 0; i < rowExprName.length; i++ )
				it.next( );
			for ( int i = 0; i < totalExprName.length; i++ )
				it.next( );
			ri.next( );
		}
		
		while ( ri.next( ) )
		{
			String str = "";
			for ( int i = 0; i < rowExprName.length; i++ )
			{
				Object ob1 = it.next( );
				Object ob2 = ri.getValue( rowExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
			}

			for ( int i = 0; i < totalExprName.length; i++ )
			{
				Object ob1 = it.next( );
				Object ob2 = ri.getValue( totalExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob2.toString( );
			}

			System.out.println( "row result set: " + str );
		}
	}
	
	/**
	 * Skip specified skipCount at the begining.
	 * 
	 * @param ri
	 * @param skipCount
	 * @throws BirtException
	 */
	private void checkResult4( IResultIterator ri, int destIndex[], boolean doNextFirst )
			throws BirtException
	{
		if ( doNextFirst )
			ri.next( );
		
		int offset = rowExprName.length + totalExprName.length;
		
		for ( int j = 0; j < destIndex.length; j++ )
		{
			int index = destIndex[j];
			
			ri.moveTo( index );
			
			String str = "";
			for ( int i = 0; i < rowExprName.length; i++ )
			{
				Object ob1 = expectedValue.get( index * offset + i );
				Object ob2 = ri.getValue( rowExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob1.toString( );
			}

			for ( int i = 0; i < totalExprName.length; i++ )
			{
				Object ob1 = expectedValue.get( index
						* offset + rowExprName.length + i );
				Object ob2 = ri.getValue( totalExprName[i] );
				assertEquals( ob1, ob2 );
				str += " " + ob1.toString( );
			}

			System.out.println( "row result set: " + str );
		}
	}
	
	// for dummy data set
	private String dummyRowExprName;
	
	/**
	 * Basic report document without data set
	 * 
	 * @throws BirtException
	 */
	public void testBasicDummy( ) throws BirtException
	{
		this.genBasicDummy( );
		this.closeArchiveWriter( );
		
		DataEngineContext deContext2 = newContext( DataEngineContext.MODE_PRESENTATION,
				fileName );
		myPreDataEngine = DataEngine.newDataEngine( deContext2 );
		
		this.preBasicDummy( );
		this.closeArchiveReader( );
	}
	
	/**
	 * @throws BirtException
	 */
	private void genBasicDummy( ) throws BirtException
	{
		QueryDefinition qd = new QueryDefinition( );
		qd.setDataSetName( null );

		// prepare
		IBaseExpression rowExpr = new ScriptExpression( "new Date()" );
		dummyRowExprName = "Date";
		qd.addResultSetExpression( dummyRowExprName, rowExpr );

		// generation
		IQueryResults qr = myGenDataEngine.prepare( qd ).execute( scope );

		// important step
		queryResultID = qr.getID( );

		IResultIterator ri = qr.getResultIterator( );
		while ( ri.next( ) )
		{
			expectedValue.add( ri.getValue( dummyRowExprName ) );
		}
		
		assertTrue( ri.getResultMetaData( ) != null );
		ri.close( );
		qr.close( );
		myGenDataEngine.shutdown( );
	}

	/**
	 * @throws BirtException
	 */
	private void preBasicDummy( ) throws BirtException
	{
		IQueryResults qr = myPreDataEngine.getQueryResults( queryResultID );
		assert ( qr.getResultMetaData( ) != null );

		IResultIterator ri = qr.getResultIterator( );
		assert ( ri.getResultMetaData( ) != null );

		Iterator it = this.expectedValue.iterator( );

		while ( ri.next( ) )
		{
			String str = "";
			Object ob1 = it.next( );
			Object ob2 = ri.getValue( dummyRowExprName );
			
			if ( ob1 instanceof IdScriptableObject )
			{
				ob1 = JavascriptEvalUtil.convertJavascriptValue( ob1 );
				ob2 = JavascriptEvalUtil.convertJavascriptValue( ob2 );
			}
			
			assertEquals( ob1, ob2 );
			str += " " + ob2.toString( );
			System.out.println( "row result set: " + str );
		}

		assertTrue( ri.getResultMetaData( ) != null );
		ri.close( );
		myPreDataEngine.shutdown( );
	}
	
	/**
	 * @throws DataException
	 */
	private void closeArchiveWriter( ) throws DataException
	{
		if ( archiveWriter != null )
			try
			{
				archiveWriter.finish( );
			}
			catch ( IOException e )
			{
				throw new DataException( "error", e );
			}
	}
	
	/**
	 * @throws DataException
	 */
	private void closeArchiveReader( ) throws DataException
	{
		if ( archiveReader != null )
			try
			{
				archiveReader.close( );
			}
			catch ( IOException e )
			{
				throw new DataException( "error", e );
			}
	}
	
}
