/*******************************************************************************
 * Copyright (c) 2004, 2005 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.tests.data.engine.smoke;

import java.util.Collection;
import java.util.Iterator;

import org.eclipse.birt.core.data.DataType;
import org.eclipse.birt.data.engine.api.IBaseExpression;
import org.eclipse.birt.data.engine.api.IParameterMetaData;
import org.eclipse.birt.data.engine.api.IPreparedQuery;
import org.eclipse.birt.data.engine.api.IQueryResults;
import org.eclipse.birt.data.engine.api.IResultIterator;
import org.eclipse.birt.data.engine.api.IResultMetaData;
import org.eclipse.birt.data.engine.api.querydefn.FilterDefinition;
import org.eclipse.birt.data.engine.api.querydefn.GroupDefinition;
import org.eclipse.birt.data.engine.api.querydefn.OdaDataSetDesign;
import org.eclipse.birt.data.engine.api.querydefn.ParameterDefinition;
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 testutil.APITestCase;
import testutil.ConfigText;
import testutil.APITestCase.DataSourceInfo;

/**
 * DtE features test.
 */
public class DsParameterTest extends APITestCase
{

	/*
	 * @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" ) );
	}

	/**
	 * Test feature of GetParameterMetaData1
	 * 
	 * @throws Exception
	 */
	public void test_StringParameter( ) throws Exception
	{
		String sql = "select COUNTRY, CITY from " + getTestTableName( )
				+ " where city = ?";
		( (OdaDataSetDesign) this.dataSet ).setQueryText( sql );

		// add an input parameter hint
		ParameterDefinition inputParamDefn = new ParameterDefinition( "param1",
				DataType.DECIMAL_TYPE, true, false );
		inputParamDefn.setPosition( 1 );
		inputParamDefn.setDefaultInputValue( "0" );
		( (OdaDataSetDesign) this.dataSet ).addParameter( inputParamDefn );

		IBaseExpression[] expressions = new IBaseExpression[]{
				new ScriptExpression( "row.COUNTRY", 0 ),
				new ScriptExpression( "row.CITY", 0 )};

		QueryDefinition queryDefn = createQueryDefn( expressions, null, null,
				null );

		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		Collection parameterMetaData = preparedQuery.getParameterMetaData( );
		assertTrue( parameterMetaData != null && parameterMetaData.size( ) == 1 );

		Iterator iter = parameterMetaData.iterator( );
		while ( iter.hasNext( ) )
		{
			IParameterMetaData paramMd = (IParameterMetaData) iter.next( );
			assertEquals( 1, paramMd.getPosition( ) );
			assertEquals( DataType.STRING_TYPE, paramMd.getDataType( ) );
			assertEquals( "param1", paramMd.getName( ) );
			assertEquals( "VARCHAR", paramMd.getNativeTypeName( ) );
			assertEquals( 0, paramMd.getScale( ) );
			assertEquals( 10, paramMd.getPrecision( ) );
		}
	}

	/**
	 * Test feature of GetParameterMetaData
	 * 
	 * @throws Exception
	 */
	public void test_BasicGetParameterMetaData( ) throws Exception
	{
		String sql = "select COUNTRY, CITY from " + getTestTableName( )
				+ " where city = ?";
		( (OdaDataSetDesign) this.dataSet ).setQueryText( sql );
		IBaseExpression[] expressions = new IBaseExpression[]{
				new ScriptExpression( "row.COUNTRY", 0 ),
				new ScriptExpression( "row.CITY", 0 )};

		// add an input parameter hint
		ParameterDefinition inputParamDefn = new ParameterDefinition( "param1",
				DataType.STRING_TYPE );
		inputParamDefn.setInputMode( true );
		inputParamDefn.setDefaultInputValue( "Beijing" );
		inputParamDefn.setPosition( 1 );

		( (OdaDataSetDesign) this.dataSet ).addParameter( inputParamDefn );
		QueryDefinition queryDefn = createQueryDefn( expressions, null, null,
				null );

		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		Collection parameterMetaData = preparedQuery.getParameterMetaData( );
		assertTrue( parameterMetaData != null && parameterMetaData.size( ) == 1 );

		Iterator iter = parameterMetaData.iterator( );
		while ( iter.hasNext( ) )
		{
			IParameterMetaData paramMd = (IParameterMetaData) iter.next( );
			assertEquals( 1, paramMd.getPosition( ) );
			assertEquals( DataType.STRING_TYPE, paramMd.getDataType( ) );
			assertEquals( "param1", paramMd.getName( ) );
			assertEquals( "VARCHAR", paramMd.getNativeTypeName( ) );
			assertEquals( 0, paramMd.getScale( ) );
			assertEquals( 10, paramMd.getPrecision( ) );
		}

		IQueryResults queryResults = preparedQuery.execute( null );
		IResultIterator resultIt = queryResults.getResultIterator( );
		assertTrue( resultIt.next( ) );

		resultIt.getValue( expressions[0].toString( ) );
		resultIt.getValue( expressions[1].toString( ) );
		while ( resultIt.next( ) )
		{
			assertEquals( "Beijing", resultIt.getValue( expressions[1]
					.toString( ) ) );
		};
	}

	/**
	 * Test feature of GetParameterMetaData This case contains two parameters
	 * 
	 * @throws Exception
	 */
	public void test_GetParameterMetaData( ) throws Exception
	{
		String sql = "select AMOUNT, CITY from " + getTestTableName( )
				+ " where city = ? and COUNTRY > ?";
		( (OdaDataSetDesign) this.dataSet ).setQueryText( sql );
		IBaseExpression[] expressions = new IBaseExpression[]{
				new ScriptExpression( "row.AMOUNT", 2 ),
				new ScriptExpression( "row.CITY", 0 )};

		// add an input parameter hint
		ParameterDefinition inputParamDefn = new ParameterDefinition( "param1",
				DataType.STRING_TYPE );
		inputParamDefn.setInputMode( true );
		inputParamDefn.setDefaultInputValue( "Beijing" );
		inputParamDefn.setPosition( 1 );

		( (OdaDataSetDesign) this.dataSet ).addParameter( inputParamDefn );

		// add an input parameter hint
		ParameterDefinition inputParamDefn1 = new ParameterDefinition(
				"param2", DataType.STRING_TYPE );
		inputParamDefn1.setInputMode( true );
		inputParamDefn1.setDefaultInputValue( "CHINA" );
		inputParamDefn1.setPosition( 2 );

		( (OdaDataSetDesign) this.dataSet ).addParameter( inputParamDefn1 );

		QueryDefinition queryDefn = createQueryDefn( expressions, null, null,
				null );

		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		Collection parameterMetaData = preparedQuery.getParameterMetaData( );
		assertTrue( parameterMetaData != null && parameterMetaData.size( ) == 2 );
		Iterator iter = parameterMetaData.iterator( );
		while ( iter.hasNext( ) )
		{
			IParameterMetaData paramMd = (IParameterMetaData) iter.next( );
			assertEquals( DataType.STRING_TYPE, paramMd.getDataType( ) );
			assertEquals( "VARCHAR", paramMd.getNativeTypeName( ) );
			assertEquals( 0, paramMd.getScale( ) );
			assertEquals( 10, paramMd.getPrecision( ) );
		}
	}

	/**
	 * Test feature of GetParameterMetaData1
	 * 
	 * @throws Exception
	 */
	public void testBasicGetParameterMetaData1( ) throws Exception
	{
		String sql = "select COUNTRY, CITY from " + getTestTableName( )
				+ " where city = ?";
		( (OdaDataSetDesign) this.dataSet ).setQueryText( sql );

		// add an input parameter hint
		ParameterDefinition inputParamDefn = new ParameterDefinition( "param1",
				DataType.DECIMAL_TYPE, true, false );
		inputParamDefn.setPosition( 1 );
		inputParamDefn.setDefaultInputValue( "0" );
		( (OdaDataSetDesign) this.dataSet ).addParameter( inputParamDefn );

		IBaseExpression[] expressions = new IBaseExpression[]{
				new ScriptExpression( "row.COUNTRY", 0 ),
				new ScriptExpression( "row.CITY", 0 )};

		QueryDefinition queryDefn = createQueryDefn( expressions, null, null,
				null );

		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		Collection parameterMetaData = preparedQuery.getParameterMetaData( );
		assertTrue( parameterMetaData != null && parameterMetaData.size( ) == 1 );

		Iterator iter = parameterMetaData.iterator( );
		while ( iter.hasNext( ) )
		{
			IParameterMetaData paramMd = (IParameterMetaData) iter.next( );
			assertEquals( 1, paramMd.getPosition( ) );
			assertEquals( DataType.STRING_TYPE, paramMd.getDataType( ) );
			assertEquals( "param1", paramMd.getName( ) );
			assertEquals( "VARCHAR", paramMd.getNativeTypeName( ) );
			assertEquals( 0, paramMd.getScale( ) );
			assertEquals( 10, paramMd.getPrecision( ) );
		}
	}

	/**
	 * Test feature of GetParameterMetaDataDefaultValue
	 * 
	 * @throws Exception
	 */
	public void testBasicGetParameterMetaDataDefaultValue( ) throws Exception
	{
		String sql = "select COUNTRY, CITY from " + getTestTableName( )
				+ " where city = ?";
		( (OdaDataSetDesign) this.dataSet ).setQueryText( sql );

		// add an input parameter hint
		ParameterDefinition inputParamDefn = new ParameterDefinition( "param1",
				DataType.DECIMAL_TYPE );
		inputParamDefn.setInputMode( true );
		inputParamDefn.setDefaultInputValue( "123" );
		inputParamDefn.setPosition( 1 );

		( (OdaDataSetDesign) this.dataSet ).addParameter( inputParamDefn );

		IBaseExpression[] expressions = new IBaseExpression[]{
				new ScriptExpression( "row.COUNTRY", 0 ),
				new ScriptExpression( "row.CITY", 0 )};

		QueryDefinition queryDefn = createQueryDefn( expressions, null, null,
				null );

		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		Collection parameterMetaData = preparedQuery.getParameterMetaData( );
		assertTrue( parameterMetaData != null && parameterMetaData.size( ) == 1 );

		Iterator iter = parameterMetaData.iterator( );
		while ( iter.hasNext( ) )
		{
			IParameterMetaData paramMd = (IParameterMetaData) iter.next( );
			assertEquals( 1, paramMd.getPosition( ) );
			assertEquals( DataType.STRING_TYPE, paramMd.getDataType( ) );
			assertEquals( "param1", paramMd.getName( ) );
			assertEquals( "VARCHAR", paramMd.getNativeTypeName( ) );
			assertEquals( 0, paramMd.getScale( ) );
			assertEquals( 10, paramMd.getPrecision( ) );
			assertEquals( "123", paramMd.getDefaultInputValue( ) );
		}
	}

	/**
	 * Test feature of NativeColumnTypeName
	 * 
	 * @throws Exception
	 */
	public void testNativeColumnTypeName( ) throws Exception
	{
		String testSQL = "select COUNTRY, CITY from " + getTestTableName( );
		( (OdaDataSetDesign) this.dataSet ).setQueryText( testSQL );

		IBaseExpression[] expressions = new IBaseExpression[]{
				new ScriptExpression( "row.COUNTRY", 0 ),
				new ScriptExpression( "row.CITY", 0 )};

		QueryDefinition queryDefn = createQueryDefn( expressions, null, null,
				null );

		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		IQueryResults queryResults = preparedQuery.execute( null );
		IResultMetaData metadata = queryResults.getResultMetaData( );

		assertEquals( "VARCHAR", metadata.getColumnNativeTypeName( 1 ) );
		assertEquals( "VARCHAR", metadata.getColumnNativeTypeName( 2 ) );
	}

	/**
	 * Create query definition from passed parameteres and then run it.
	 * 
	 * @param expressions
	 * @param groupDefn
	 * @param sortDefn
	 * @param filters
	 * @throws Exception
	 */
	private void createAndRunQuery( IBaseExpression[] expressions,
			GroupDefinition[] groupDefn, SortDefinition[] sortDefn,
			FilterDefinition[] filters ) throws Exception
	{
		QueryDefinition queryDefn = createQueryDefn( expressions, groupDefn,
				sortDefn, filters );
		IPreparedQuery preparedQuery = dataEngine.prepare( queryDefn );
		IQueryResults queryResults = preparedQuery.execute( jsScope );
		IResultIterator resultIt = queryResults.getResultIterator( );
		outputQueryResult( resultIt, new String[]{"COL_COUNTRY", "COL_CITY",
				"COL_SALE_DATE", "COL_AMOUNT"} );
	}

	/**
	 * Create query definition from passed parameters
	 * 
	 * @param expressions
	 *            row expression
	 * @param groupDefn
	 * @param sortDefn
	 * @param filters
	 * @return QueryDefinition
	 */
	private QueryDefinition createQueryDefn( IBaseExpression[] expressions,
			GroupDefinition[] groupDefn, SortDefinition[] sortDefn,
			FilterDefinition[] filters )
	{
		// define a query design
		QueryDefinition queryDefn = newReportQuery( );

		if ( groupDefn != null )
			for ( int i = 0; i < groupDefn.length; i++ )
				queryDefn.addGroup( groupDefn[i] );
		if ( sortDefn != null )
			for ( int i = 0; i < sortDefn.length; i++ )
				queryDefn.addSort( sortDefn[i] );
		if ( expressions != null )
			for ( int i = 0; i < expressions.length; i++ )
				queryDefn.addResultSetExpression( expressions[i].toString( ),
						expressions[i] );
		if ( filters != null )
			for ( int i = 0; i < filters.length; i++ )
				queryDefn.addFilter( filters[i] );

		return queryDefn;
	}

}