/*******************************************************************************
 * Copyright (c) 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.report.designer.data.ui.dataset;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.eclipse.birt.core.data.DataType;
import org.eclipse.birt.data.engine.api.IParameterMetaData;
import org.eclipse.birt.report.designer.data.ui.property.AbstractDescriptionPropertyPage;
import org.eclipse.birt.report.designer.data.ui.util.ControlProvider;
import org.eclipse.birt.report.designer.data.ui.util.DataSetProvider;
import org.eclipse.birt.report.designer.data.ui.util.Utility;
import org.eclipse.birt.report.designer.internal.ui.processor.ElementProcessorFactory;
import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.internal.ui.views.attributes.widget.ExpressionCellEditor;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.dialogs.ExpressionBuilder;
import org.eclipse.birt.report.designer.ui.dialogs.ParameterDialog;
import org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPageContainer;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.adapter.oda.ReportParameterAdapter;
import org.eclipse.birt.report.model.api.DataSetHandle;
import org.eclipse.birt.report.model.api.DataSetParameterHandle;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.JointDataSetHandle;
import org.eclipse.birt.report.model.api.OdaDataSetHandle;
import org.eclipse.birt.report.model.api.OdaDataSetParameterHandle;
import org.eclipse.birt.report.model.api.ParameterHandle;
import org.eclipse.birt.report.model.api.PropertyHandle;
import org.eclipse.birt.report.model.api.ReportElementHandle;
import org.eclipse.birt.report.model.api.ScalarParameterHandle;
import org.eclipse.birt.report.model.api.SlotHandle;
import org.eclipse.birt.report.model.api.activity.NotificationEvent;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.command.ContentException;
import org.eclipse.birt.report.model.api.command.NameException;
import org.eclipse.birt.report.model.api.core.Listener;
import org.eclipse.birt.report.model.api.elements.DesignChoiceConstants;
import org.eclipse.birt.report.model.api.elements.structures.DataSetParameter;
import org.eclipse.birt.report.model.api.elements.structures.OdaDataSetParameter;
import org.eclipse.birt.report.model.api.metadata.IChoice;
import org.eclipse.birt.report.model.api.metadata.PropertyValueException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.datatools.connectivity.oda.OdaException;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;

/**
 * Property page to define dataset parameters. If they could be retrieved from
 * DataSetParameter metadata, they will be displayed automatically. Five
 * properties will be shown in this page, which is name, data type, mode,
 * default value, and linked <code>ScalarParameter</code> parameter. User
 * could edit those properties to construct data set parameter for query.
 */
public class DataSetParametersPage extends AbstractDescriptionPropertyPage
		implements
			Listener
{

	private boolean modelChanged = true;
	private PropertyHandle parameters;
	private PropertyHandleTableViewer viewer;
	private DataSetParameter originalStructure = null;

	private DataSetParameter newParameter = null;
	private boolean isDirectionSet = false;
	private boolean isDataTypeSet = false;
	private String parameterName;
	private boolean isOdaParameterStructure = true;
	private boolean isJointDataSet = false;

	private static IChoice[] dataTypes = DEUtil.getMetaDataDictionary( )
			.getStructure( DataSetParameter.STRUCT_NAME )
			.getMember( DataSetParameter.DATA_TYPE_MEMBER )
			.getAllowedChoices( )
			.getChoices( );

	private static String[] directions = new String[]{
			Messages.getString( "label.input" ), //$NON-NLS-1$
			Messages.getString( "label.output" ), //$NON-NLS-1$
			Messages.getString( "label.inputOutput" ) //$NON-NLS-1$
	};

	private static String NAME = DataSetParameter.NAME_MEMBER; //$NON-NLS-1$
	private static String DATA_TYPE = "parameterDataType"; //$NON-NLS-1$
	private static String INPUT = "input"; //$NON-NLS-1$
	private static String OUTPUT = "output"; //$NON-NLS-1$
	private static String DEFAULT_VALUE = DataSetParameter.DEFAULT_VALUE_MEMBER; //$NON-NLS-1$
	private static String PARAM_NAME = OdaDataSetParameter.PARAM_NAME_MEMBER;
	private static String NULLABLE = DataSetParameter.ALLOW_NULL_MEMBER; //$NON-NLS-1$
	private static String OPTIONAL = DataSetParameter.IS_OPTIONAL_MEMBER; //$NON-NLS-1$

	private static String DIRECTION = "direction"; //$NON-NLS-1$

	private static String DEFAULT_MESSAGE = Messages.getString( "dataset.editor.parameters" ); //$NON-NLS-1$
	private static String ERROR_DLG_TITLE = Messages.getString( "DataSetParametersPage.ErrorTitle.InvalidInput" );
	private static String ERROR_MSG_EMPTY_COLUMN_NAME = Messages.getString( "DataSetParametersPage.ErrorMessage.CanootBeNull" );
	private static String NONE_DEFAULT_VALUE = Messages.getString( "DataSetParametersPage.default.None" );
	private static String UNLINKED_REPORT_PARAM = Messages.getString( "DataSetParametersPage.reportParam.None" );

	private static String[] cellLabels = new String[]{
			Messages.getString( "dataset.editor.title.name" ),
			Messages.getString( "dataset.editor.title.dataType" ),
			Messages.getString( "dataset.editor.title.direction" ),
			Messages.getString( "dataset.editor.title.defaultValue" ),
			Messages.getString( "DataSetParameterPage.cell.linkToSalarParameter" )
	};

	private static String[] cellProperties = new String[]{
			DataSetParameter.NAME_MEMBER,
			DataSetParameter.DATA_TYPE_MEMBER,
			DIRECTION, //$NON-NLS-1$
			DataSetParameter.DEFAULT_VALUE_MEMBER,
			OdaDataSetParameter.PARAM_NAME_MEMBER
	};
	
	/**
	 * constructor
	 */
	public DataSetParametersPage( )
	{
		super( );
	}

	public void setContainer( IPropertyPageContainer container )
	{
		super.setContainer( container );
		parameters = ( (DataSetHandle) getContainer( ).getModel( ) ).getPropertyHandle( DataSetHandle.PARAMETERS_PROP );

		Iterator it = parameters.iterator( );
		if( it != null )
		{
			
			while( it.hasNext( ))
			{
				DataSetParameterHandle parameter = (DataSetParameterHandle) it.next( );
				if ( parameter.getPosition( ) == null
						|| parameter.getPosition( ).intValue( ) <= 0
						|| parameter.getPosition( ).intValue( ) > parameters.getListValue( )
								.size( ) )
				{
					MessageDialog.openWarning( null,
							Messages.getString( "dataset.editor.error.title" ),
							Messages.getFormattedString( "dataset.editor.warning.correctParameter",
									new Object[]{
										"aa"
									} ) );
					
				}
			}
		}
		this.refreshPositions( );
	}
	/*
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.AbstractDescriptionPropertyPage#createContents(org.eclipse.swt.widgets.Composite)
	 */
	public Control createContents( Composite parent )
	{
		
		if ( (DataSetHandle) getContainer( ).getModel( ) instanceof JointDataSetHandle )
		{
			isJointDataSet = true;
		}
		else
		{
			isJointDataSet = false;
		}
		
		if ( (DataSetHandle) getContainer( ).getModel( ) instanceof OdaDataSetHandle )
		{
			this.isOdaParameterStructure = true;
		}
		else
		{
			this.isOdaParameterStructure = false;
		}
		return createParameterPageControl( parent );
	}

	/**
	 * Create parameter page control, if the datasetHandle is ODA, add the
	 * "linked with report parameter" cell.
	 * 
	 * @param parent
	 * @return
	 */
	private Control createParameterPageControl( Composite parent )
	{
		viewer = new PropertyHandleTableViewer( parent, true, true, true ) {

			void doRemove( )
			{
				super.doRemove( );
				refreshMessage( );
			}

		};

		TableColumn column = new TableColumn( viewer.getViewer( ).getTable( ),
				SWT.LEFT );
		column.setText( " " ); //$NON-NLS-1$
		column.setResizable( false );
		column.setWidth( 19 );

		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( Messages.getString( "dataset.editor.title.name" ) ); //$NON-NLS-1$
		column.setWidth( 100 );

		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( Messages.getString( "dataset.editor.title.dataType" ) ); //$NON-NLS-1$
		column.setWidth( 100 );

		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( Messages.getString( "dataset.editor.title.direction" ) ); //$NON-NLS-1$
		column.setWidth( 100 );

		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( Messages.getString( "dataset.editor.title.defaultValue" ) ); //$NON-NLS-1$
		column.setWidth( 100 );

		// if the parameter is ODA, support it link with report parameter
		if ( this.isOdaParameterStructure )
		{
			column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
			column.setText( Messages.getString( "DataSetParameterPage.cell.linkToSalarParameter" ) ); //$NON-NLS-1$
			column.setWidth( 180 );
		}

		viewer.getViewer( )
				.setContentProvider( new ParameterViewContentProvider( ) );

		viewer.getViewer( )
				.setLabelProvider( new ParameterViewLableProvider( this.isOdaParameterStructure ) );

		viewer.getViewer( ).setInput( parameters );
//		setupEditors( );
		addRefreshMenu( );
		addListeners( );
		setToolTips( );
		( (DataSetHandle) getContainer( ).getModel( ) ).addListener( this );
		return viewer.getControl( );
	}

	/**
	 * Add refresh menu to refresh the parameter.If the parameter metadata could
	 * get from database, list the parameter
	 * 
	 */
	private void addRefreshMenu( )
	{
		MenuItem itmRefresh = new MenuItem( viewer.getMenu( ), SWT.NONE, 0 );
		new MenuItem( viewer.getMenu( ), SWT.SEPARATOR, 1 );
		itmRefresh.setText( Messages.getString( "parameters.menuItem.refresh" ) ); //$NON-NLS-1$
		itmRefresh.addSelectionListener( new SelectionAdapter( ) {

			public void widgetSelected( SelectionEvent e )
			{
				PropertyHandle handle = (PropertyHandle) viewer.getViewer( )
						.getInput( );
				try
				{
					handle.clearValue( );
				}
				catch ( SemanticException e1 )
				{
				}
				refreshParameters( );
				viewer.getViewer( ).refresh( );
			}
		} );
	}

	/**
	 * Setup cell editor
	 *
	 */
	protected final void setupEditors( )
	{
		String[] dataTypeDisplayNames = new String[dataTypes.length];
		for ( int i = 0; i < dataTypes.length; i++ )
		{
			dataTypeDisplayNames[i] = dataTypes[i].getDisplayName( );
		}
		CellEditor[] editors = new CellEditor[6];
		editors[1] = new TextCellEditor( viewer.getViewer( ).getTable( ),
				SWT.NONE );
		editors[2] = new ComboBoxCellEditor( viewer.getViewer( ).getTable( ),
				dataTypeDisplayNames,
				SWT.READ_ONLY );
		editors[3] = new ComboBoxCellEditor( viewer.getViewer( ).getTable( ),
				getDirections( ),
				SWT.READ_ONLY );

		ExpressionCellEditor editor = new ExpressionCellEditor( viewer.getViewer( )
				.getTable( ),
				SWT.NONE );
		editors[4] = editor;

		List parameterList = Utility.getAllParameters( );
		List nameList = new ArrayList( );
		nameList.add( UNLINKED_REPORT_PARAM );
		for ( int i = 0; i < parameterList.size( ); i++ )
		{
			ReportElementHandle handle = (ReportElementHandle) parameterList.get( i );
			if ( handle instanceof ScalarParameterHandle )
			{
				nameList.add( handle.getQualifiedName( ) );
			}
		}
		String[] paramName = new String[nameList.size( )];
		for ( int i = 0; i < nameList.size( ); i++ )
		{
			paramName[i] = nameList.get( i ).toString( );
		}

		final ParameterComboCellEditor editor2 = new ParameterComboCellEditor( viewer.getViewer( )
				.getTable( ),
				paramName,
				SWT.READ_ONLY );
		editor2.addScalarParmeterLister( new ScalarParameterListener( ) );
		editors[5] = editor2;

		viewer.getViewer( ).setColumnProperties( new String[]{
				"", //$NON-NLS-1$
				NAME,
				DATA_TYPE,
				DIRECTION,
				DEFAULT_VALUE,
				PARAM_NAME
		} );

		viewer.getViewer( ).setCellEditors( editors );
		viewer.getViewer( ).setCellModifier( new ICellModifier( ) {

			/*
			 * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object,
			 *      java.lang.String)
			 */
			public boolean canModify( Object element, String property )
			{
				if(isJointDataSet)
					return false;
				getContainer( ).setMessage( DEFAULT_MESSAGE,
						IMessageProvider.NONE );
				if ( property.equals( DEFAULT_VALUE )
						|| property.equals( PARAM_NAME )
						|| property.equals( NULLABLE )
						|| property.equals( OPTIONAL ) )
				{
					Boolean isInput = null;
					try
					{
						if ( property.equals( DEFAULT_VALUE ) )
						{
							if ( Utility.getProperty( element, PARAM_NAME ) != null )
								return false;
						}
						else if ( property.equals( PARAM_NAME ) )
						{
							( (ParameterComboCellEditor) editor2 ).setInput( element );
						}
						isInput = (Boolean) Utility.getProperty( element, INPUT );
					}
					catch ( Exception ex )
					{
						ExceptionHandler.handle( ex );
					}
					if ( isInput == null || !isInput.booleanValue( ) )
					{
						return false;
					}
				}

				if ( element == newParameter && !property.equals( NAME ) )
					return false;
				return true;
			}

			public Object getValue( Object element, String property )
			{
				Object value = null;
				try
				{
					if ( property.equals( DIRECTION ) )
					{
						value = new Integer( getDirectionIndex( (Boolean) Utility.getProperty( element,
								INPUT ),
								(Boolean) Utility.getProperty( element, OUTPUT ) ) );
					}
					else if ( property.equals( NULLABLE ) )
					{
						value = new Boolean( true );
					}
					else
					{
						value = Utility.getProperty( element, property );
					}
				}
				catch ( Exception e )
				{
					ExceptionHandler.handle( e );
				}

				if ( property.equals( OPTIONAL ) )
				{
					if ( value == null )
					{
						value = new Boolean( false );
					}
					value = ( (Boolean) value ).booleanValue( )
							? new Integer( 0 ) : new Integer( 1 );
				}
				else if ( property.equals( NULLABLE ) )
				{
					if ( value == null )
					{
						value = new Boolean( true );
					}
					value = ( (Boolean) value ).booleanValue( )
							? new Integer( 0 ) : new Integer( 1 );
				}
				else if ( property.equals( DATA_TYPE ) )
				{
					value = new Integer( getTypeIndex( (String) value ) );
				}

				if ( value == null )
				{
					value = ""; //$NON-NLS-1$
				}

				return value;
			}

			public void modify( Object element, String property, Object value )
			{
				Object actualElement = ( (TableItem) element ).getData( );
				Object finalValue = value;
				String finalProperty = property;
				if ( property.equals( DIRECTION ) )
				{
					int selection = ( (Integer) finalValue ).intValue( );
					char ch = Character.toUpperCase( INPUT.charAt( 0 ) );
					StringBuffer sbFinalProperty = new StringBuffer( );
					sbFinalProperty.append( "is" ).append( ch ).append( INPUT.substring( 1 ) ); //$NON-NLS-1$
					try
					{
						Utility.setProperty( actualElement,
								sbFinalProperty.toString( ),
								( selection == 0 || selection == 2 )
										? new Boolean( true )
										: new Boolean( false ) );
					}
					catch ( Exception e )
					{
					}
					ch = Character.toUpperCase( OUTPUT.charAt( 0 ) );
					sbFinalProperty.setLength( 0 );
					sbFinalProperty.append( "is" ).append( ch ).append( OUTPUT.substring( 1 ) ); //$NON-NLS-1$
					finalProperty = sbFinalProperty.toString( );
					finalValue = ( selection == 1 || selection == 2 )
							? new Boolean( true ) : new Boolean( false );

					if ( selection == 1 )
					{
						try
						{
							Utility.setProperty( actualElement,
									PARAM_NAME,
									null );
							Utility.setProperty( actualElement,
									DEFAULT_VALUE,
									null );
						}
						catch ( Exception e )
						{
						}
					}

					if ( actualElement == newParameter )
					{
						isDirectionSet = true;
					}
				}
				/*
				 * The property OPTIONAL&NULLABLE is not used now. comments them
				 * out. Maybe future impl, we will added them
				 * 
				 * else if ( property.equals( OPTIONAL ) || property.equals(
				 * NULLABLE ) ) { char ch = Character.toUpperCase(
				 * property.charAt( 0 ) ); StringBuffer sbFinalProperty = new
				 * StringBuffer( ); sbFinalProperty.append( "is" ).append( ch
				 * ).append( property.substring( 1 ) ); //$NON-NLS-1$ if ( (
				 * (Integer) value ).intValue( ) == 0 ) { finalValue = new
				 * Boolean( true ); } else { finalValue = new Boolean( false ); }
				 * finalProperty = sbFinalProperty.toString( ); if (
				 * actualElement == newParameter ) { if ( property.equals(
				 * OPTIONAL ) ) { isOptionalSet = true; } else if (
				 * property.equals( NULLABLE ) ) { isNullableSet = true; } } }
				 */
				else if ( property.equals( DATA_TYPE ) )
				{
					int selectedType = ( (Integer) value ).intValue( );
					if ( selectedType > 0 )
					{
						finalValue = dataTypes[selectedType].getName( );
					}
					else
					{
						finalValue = null;
					}
				}
				else if ( property.equals( NAME ) )
				{
					if ( actualElement != newParameter
							&& ( finalValue == null || ( (String) finalValue ).trim( )
									.length( ) == 0 ) )
					{
						ExceptionHandler.openMessageBox( ERROR_DLG_TITLE,
								ERROR_MSG_EMPTY_COLUMN_NAME,
								SWT.ICON_INFORMATION );
						viewer.getViewer( ).update( actualElement, null );
						return;
					}

					if ( !isUniqueName( actualElement, (String) finalValue ) )
					{
						viewer.getViewer( ).update( actualElement, null );
						return;
					}
				}
				else if ( property.equals( PARAM_NAME ) )
				{
					if ( UNLINKED_REPORT_PARAM.equals( finalValue.toString( ) ) )
					{
						finalValue = null;
					}
				}
				try
				{
					Utility.setProperty( actualElement,
							finalProperty,
							finalValue );
					viewer.getViewer( ).update( actualElement, null );
					if ( actualElement == newParameter )
					{
						isDataTypeSet = true;
						if ( newParameter.getName( ) != null
								&& newParameter.getName( ).trim( ).length( ) > 0 )
						{
							parameters.addItem( newParameter );
							clearNewParameter( );
							viewer.getViewer( ).refresh( );
						}
					}
					getContainer( ).setMessage( DEFAULT_MESSAGE,
							IMessageProvider.NONE );
				}
				catch ( Exception ex )
				{
					ExceptionHandler.handle( ex );
				}
			}
		} );
	}

	/**
	 * get the right direction for different dataset type
	 * 
	 * @return
	 */
	private String[] getDirections( )
	{
		String[] directions;
		boolean supportInput = ( (DataSetEditor) this.getContainer( ) ).supportsInParameters( );
		boolean supportOutput = ( (DataSetEditor) this.getContainer( ) ).supportsOutputParameters( );
		if ( supportInput && supportOutput )
		{
			directions = new String[]{
					Messages.getString( "label.input" ), //$NON-NLS-1$
					Messages.getString( "label.output" ), //$NON-NLS-1$
					Messages.getString( "label.inputOutput" ) //$NON-NLS-1$
			};
		}
		else if ( supportInput )
		{
			directions = new String[]{
				Messages.getString( "label.input" )
			};
		}
		else if ( supportOutput )
		{
			directions = new String[]{
				Messages.getString( "label.output" )
			};
		}
		else
		{
			directions = new String[]{
					Messages.getString( "label.input" ), //$NON-NLS-1$
					Messages.getString( "label.output" ), //$NON-NLS-1$
					Messages.getString( "label.inputOutput" ) //$NON-NLS-1$
			};
		}
		return directions;
	}

	/**
	 * 
	 *
	 */
	private void addListeners( )
	{
    	viewer.getNewButton( ).addSelectionListener( new SelectionAdapter( ) {

			public void widgetSelected( SelectionEvent e )
			{
				doNew( );
			}
		} );

		viewer.getEditButton( ).addSelectionListener( new SelectionAdapter( ) {

			public void widgetSelected( SelectionEvent e )
			{
				doEdit( );
			}
		} );

		viewer.getViewer( ).getTable( ).addMouseListener( new MouseAdapter( ) {

			public void mouseDoubleClick( MouseEvent e )
			{
				doEdit( );
			}
		} );

		viewer.getViewer( ).getTable( ).addKeyListener( new KeyListener( ) {

			public void keyPressed( KeyEvent e )
			{
			}

			public void keyReleased( KeyEvent e )
			{
				if ( e.keyCode == SWT.DEL )
				{
					removeSelectedItem( );
					setPageProperties( );
				}
			}

		} );

		viewer.getRemoveButton( )
				.addSelectionListener( new SelectionListener( ) {

					public void widgetSelected( SelectionEvent e )
					{
						removeSelectedItem( );
						setPageProperties( );
					}

					public void widgetDefaultSelected( SelectionEvent e )
					{
					}

				} );

		viewer.getRemoveMenuItem( )
				.addSelectionListener( new SelectionListener( ) {

					public void widgetSelected( SelectionEvent e )
					{
						removeSelectedItem( );
						setPageProperties( );
					}

					public void widgetDefaultSelected( SelectionEvent e )
					{
					}

				} );

		viewer.getRemoveAllMenuItem( )
				.addSelectionListener( new SelectionListener( ) {

					public void widgetSelected( SelectionEvent e )
					{
						removeAllItem( );
						setPageProperties( );
					}

					public void widgetDefaultSelected( SelectionEvent e )
					{
						widgetSelected( e );
					}
				} );

		viewer.getViewer( )
				.addSelectionChangedListener( new ViewerSelectionListener( ) );
	}
	
	private void doNew( )
	{
		DataSetParameter newParam = null;
		if ( isOdaParameterStructure )
			newParam = new OdaDataSetParameter( );
		else
			newParam = new DataSetParameter( );

		int position = viewer.getViewer( ).getTable( ).getItemCount( );
		newParam.setName( getUniqueName( ) );
		newParam.setPosition( new Integer( position + 1 ) );
		doEdit( newParam );
	}

	private void doEdit( )
	{
		int index = viewer.getViewer( ).getTable( ).getSelectionIndex( );
		if ( index == -1 )
			return;

		DataSetParameterHandle handle = (DataSetParameterHandle) viewer.getViewer( )
				.getTable( )
				.getItem( index )
				.getData( );
		originalStructure = (DataSetParameter) handle.getStructure( ).copy( );

		doEdit( handle );
	}

	private void doEdit( Object structureOrHandle )
	{
		ParameterInputDialog dlg = new ParameterInputDialog( structureOrHandle );

		if ( dlg.open( ) == Window.OK )
		{
			update( dlg.structureHandle );
		}
	}
	
	private void update( DataSetParameterHandle dataSetParameterHandle )
	{
		viewer.getViewer( ).update( dataSetParameterHandle, null );
		viewer.getViewer( ).refresh( );
		
		refreshMessage( );
	}
	
	private void refreshMessage( )
	{
		getContainer( ).setMessage( DEFAULT_MESSAGE, IMessageProvider.NONE );
		if ( !doSaveEmptyParameter( parameters ) )
		{
			getContainer( ).setMessage( Messages.getFormattedString( "dataset.editor.error.noInputParameterDefaultValue", new Object[]{this.getNoneValuedParameterName( )} ), IMessageProvider.ERROR ); //$NON-NLS-1$
		}
	}
	
	private DataSetParameter getStructure( Object structureOrHandle )
	{
		DataSetParameter structure = null;
		if ( structureOrHandle instanceof DataSetParameter )
		{
			structure = (DataSetParameter) structureOrHandle;
		}
		else
		{
			structure = (DataSetParameter) ( (DataSetParameterHandle) structureOrHandle ).getStructure( );
		}

		return structure;
	}
	
    private void setToolTips( )
	{
		viewer.getNewButton( )
				.setToolTipText( Messages.getString( "DataSetParameterPage.toolTipText.New" ) );//$NON-NLS-1$
		viewer.getEditButton( )
				.setToolTipText( Messages.getString( "DataSetParameterPage.toolTipText.Edit" ) );//$NON-NLS-1$
		viewer.getRemoveButton( )
				.setToolTipText( Messages.getString( "DataSetParameterPage.toolTipText.Remove" ) );//$NON-NLS-1$
		viewer.getUpButton( )
				.setToolTipText( Messages.getString( "DataSetParameterPage.toolTipText.Up" ) );//$NON-NLS-1$
		viewer.getDownButton( )
				.setToolTipText( Messages.getString( "DataSetParameterPage.toolTipText.Down" ) );//$NON-NLS-1$
	}

	/**
	 * 
	 * @param isInput
	 * @param isOutput
	 * @return
	 */
	protected final int getDirectionIndex( Boolean isInput, Boolean isOutput )
	{
		boolean input = ( isInput == null ) ? false : isInput.booleanValue( );
		boolean output = ( isOutput == null ) ? false : isOutput.booleanValue( );

		if ( input && output )
		{
			return 2;
		}
		else if ( output )
		{
			return 1;
		}
		return 0;
	}

	/**
	 * 
	 * @param isInput
	 * @param isOutput
	 * @return
	 */
	protected final String getDirectionDisplayName( boolean isInput,
			boolean isOutput )
	{
		if ( isInput && isOutput )
		{
			return directions[2];
		}
		else if ( isOutput )
		{
			return directions[1];
		}
		return directions[0];
	}

	/**
	 * 
	 * @param dataTypeName
	 * @return
	 */
	private final int getTypeIndex( String dataTypeName )
	{
		for ( int n = 0; n < dataTypes.length; n++ )
		{
			if ( dataTypes[n].getName( ).equals( dataTypeName ) )
			{
				return n;
			}
		}
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#pageActivated()
	 */
	public void pageActivated( )
	{
		getContainer( ).setMessage( DEFAULT_MESSAGE, IMessageProvider.NONE );
		if ( !doSaveEmptyParameter( parameters ) )
		{
			getContainer( ).setMessage( Messages.getFormattedString( "dataset.editor.error.noInputParameterDefaultValue", new Object[]{this.getNoneValuedParameterName( )} ), IMessageProvider.ERROR ); //$NON-NLS-1$
		}
		if ( viewer != null )
			viewer.getViewer( ).refresh( );
		// The proeprties of the various controls on the page
		// will be set depending on the parameters
		setPageProperties( );
		viewer.getViewer( ).getTable( ).select( 0 );
	}

	/**
	 * Refreshes the parameter list adds any new parameter retrieved. This
	 * method doesn't clear unused parameters. It is the users responsibility to
	 * delete individual parameters through the UI.
	 */
	private void refreshParameters( )
	{
		try
		{
			DataSetHandle ds = ( (DataSetHandle) getContainer( ).getModel( ) );
			Collection paramsFromDataSet = null;

			paramsFromDataSet = DataSetProvider.getCurrentInstance( )
					.getParametersFromDataSet( ds );

			// iterate through the list of parameters and find the parameter
			// with
			// the same position in the data set
			if ( paramsFromDataSet != null )
			{
				Iterator iter = paramsFromDataSet.iterator( );
				while ( iter.hasNext( ) )
				{
					IParameterMetaData paramFromDataSet = (IParameterMetaData) iter.next( );

					DataSetParameter parameter = null;
					if ( paramFromDataSet.getPosition( ) > 0 )
					{
						parameter = findParameterByPosition( paramFromDataSet.getPosition( ) );
					}
					else
					{
						parameter = findParameterByName( paramFromDataSet.getName( ) );
					}
					if ( parameter != null )
					{
						DataSetParameter newParameter = newParameter( paramFromDataSet );
						// if the parameter is unsame with new parameter,replace
						// the old one with the new one.or keep the old
						// parameter
						if ( !isSameParameters( parameter, newParameter ) )
						{
							parameters.replaceItem( parameter, newParameter );
						}
					}
					else
					{
						parameters.addItem( newParameter( paramFromDataSet ) );
					}
				}
				// if the paremeters has more value, remove these extra value
				if ( parameters.getListValue( ) != null
						&& paramsFromDataSet.size( ) < parameters.getListValue( )
								.size( ) )
				{
					int size = parameters.getListValue( ).size( );
					while ( size > paramsFromDataSet.size( ) )
					{
						parameters.removeItem( size - 1 );
						size = parameters.getListValue( ).size( );
					}
				}
			}
			else
			{
				if ( viewer != null )
				{
					PropertyHandle handle = (PropertyHandle) viewer.getViewer( )
							.getInput( );
					handle.clearValue( );
				}
			}
			refreshPositions( );
			setPageProperties( );
		}
		catch ( Exception e )
		{
		}
	}

	/**
	 * create a parameter according to the parameter's metadata
	 * 
	 * @param paramFromDataSet
	 * @return
	 */
	private DataSetParameter newParameter( IParameterMetaData paramFromDataSet )
	{
		DataSetParameter parameter = null;
		if ( this.isOdaParameterStructure )
			parameter = new OdaDataSetParameter( );
		else
			parameter = new DataSetParameter( );
		try
		{
			parameter.setParameterDataType( toModelDataType( paramFromDataSet.getDataTypeName( ) ) );
		}
		catch ( Exception e )
		{
		}
		parameter.setDefaultValue( paramFromDataSet.getDefaultInputValue( ) );
		if ( paramFromDataSet.isOptional( ) != null )
		{
			parameter.setIsOptional( paramFromDataSet.isOptional( )
					.booleanValue( ) );
		}
		if ( paramFromDataSet.isNullable( ) != null )
		{
			parameter.setAllowNull( paramFromDataSet.isNullable( )
					.booleanValue( ) );
		}

		if ( paramFromDataSet.isInputMode( ) != null )
		{
			parameter.setIsInput( paramFromDataSet.isInputMode( )
					.booleanValue( ) );
		}
		if ( paramFromDataSet.isOutputMode( ) != null )
		{
			parameter.setIsOutput( paramFromDataSet.isOutputMode( )
					.booleanValue( ) );
		}
		if ( ( paramFromDataSet.isInputMode( ) == null && paramFromDataSet.isOutputMode( ) == null )
				|| ( parameter.isInput( ) == false && parameter.isOutput( ) == false ) )
		{
			parameter.setIsInput( true );
		}

		parameter.setName( paramFromDataSet.getName( ) );
		if ( parameter.getName( ) == null )
		{
			parameter.setName( getUniqueName( ) );
		}
		return parameter;
	}

	/**
	 * whether the param1 is same with param2
	 * 
	 * @param param1
	 * @param param2
	 * @return
	 */
	private boolean isSameParameters( DataSetParameter param1,
			DataSetParameter param2 )
	{
		boolean isSame = false;
		if ( param1 == param2 )
			isSame = true;
		else if ( param1 == null || param2 == null )
			isSame = false;
		else if ( param1.getParameterDataType( ).equals( param2.getParameterDataType( ) )
				&& ( param1.isInput( ) == param2.isInput( ) )
				&& ( param1.isOutput( ) == param2.isOutput( ) ) )
			isSame = true;
		return isSame;
	}

	/**
	 * Convert data type of DtE to corresponding type of Model
	 * 
	 * @param dteDTName
	 * @return modelDataType
	 */
	private static String toModelDataType( String dteDTName )
	{
		if ( dteDTName == null )
			return null;

		String modelDataType = dteDTName;

		if ( dteDTName.equals( DataType.INTEGER_TYPE_NAME ) )
			modelDataType = DesignChoiceConstants.PARAM_TYPE_INTEGER;
		else if ( dteDTName.equals( DataType.DOUBLE_TYPE_NAME ) )
			modelDataType = DesignChoiceConstants.PARAM_TYPE_FLOAT;
		else if ( dteDTName.equals( DataType.DECIMAL_TYPE_NAME ) )
			modelDataType = DesignChoiceConstants.PARAM_TYPE_DECIMAL;
		else if ( dteDTName.equals( DataType.STRING_TYPE_NAME ) )
			modelDataType = DesignChoiceConstants.PARAM_TYPE_STRING;
		else if ( dteDTName.equals( DataType.DATE_TYPE_NAME ) )
			modelDataType = DesignChoiceConstants.PARAM_TYPE_DATETIME;
		else if ( dteDTName.equals( DataType.BOOLEAN_TYPE_NAME ) )
			modelDataType = DesignChoiceConstants.PARAM_TYPE_BOOLEAN;
		return modelDataType;
	}

	/*
	 * @see org.eclipse.birt.report.model.core.Listener#elementChanged(org.eclipse.birt.report.model.api.DesignElementHandle,
	 *      org.eclipse.birt.report.model.activity.NotificationEvent)
	 */
	public void elementChanged( DesignElementHandle focus, NotificationEvent ev )
	{
		modelChanged = true;
	}

	protected final DataSetParameter findParameterByPosition( int position )
	{
		if ( parameters != null )
		{
			Iterator iter = parameters.iterator( );
			if ( iter != null )
			{
				while ( iter.hasNext( ) )
				{
					DataSetParameterHandle parameter = (DataSetParameterHandle) iter.next( );
					if ( parameter.getPosition( ) != null
							&& parameter.getPosition( ).intValue( ) == position )
					{
						return (DataSetParameter) parameter.getStructure( );
					}
				}
			}
		}
		return null;
	}

	protected final DataSetParameter findParameterByName( String name )
	{
		if ( parameters != null )
		{
			Iterator iter = parameters.iterator( );
			if ( iter != null )
			{
				while ( iter.hasNext( ) )
				{
					DataSetParameterHandle parameter = (DataSetParameterHandle) iter.next( );
					if ( name != null && name.equals( parameter.getName( ) ) )
					{
						return (DataSetParameter) parameter.getStructure( );
					}
				}
			}
		}
		return null;
	}

	/**
	 * Re-indexes the parameters starting at 1 from the 1st in the list.
	 */
	protected final void refreshPositions( )
	{
		if ( parameters != null )
		{
			int position = 1;
			Iterator iter = parameters.iterator( );
			
			if ( iter != null )
			{
				while ( iter.hasNext( ) )
				{
					DataSetParameterHandle parameter = (DataSetParameterHandle) iter.next( );
					parameter.setPosition( new Integer( position++ ) );
				}
			}
		}
	}

	/**
	 * 
	 * @return
	 */
	protected final String getUniqueName( )
	{
		int n = 1;
		String prefix = "param"; //$NON-NLS-1$
		StringBuffer buf = new StringBuffer( );
		while ( buf.length( ) == 0 )
		{
			buf.append( prefix ).append( n++ );
			if ( parameters != null )
			{
				Iterator iter = parameters.iterator( );
				if ( iter != null )
				{
					while ( iter.hasNext( ) && buf.length( ) > 0 )
					{
						DataSetParameterHandle parameter = (DataSetParameterHandle) iter.next( );
						if ( buf.toString( )
								.equalsIgnoreCase( parameter.getName( ) ) )
						{
							buf.setLength( 0 );
						}
					}
				}
			}
		}
		return buf.toString( );
	}

	/* (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.AbstractPropertyPage#performCancel()
	 */
	public boolean performCancel( )
	{
		//   selectorImage.dispose();
		( (DataSetHandle) getContainer( ).getModel( ) ).removeListener( this );
		return super.performCancel( );
	}

	/* (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.AbstractPropertyPage#performOk()
	 */
	public boolean performOk( )
	{
		if ( doSaveEmptyParameter( parameters ) )
		{
			// selectorImage.dispose();
			refreshPositions( );
			if ( this.modelChanged
					&& this.getContainer( ) != null
					&& this.getContainer( ) instanceof DataSetEditor )
			{
				this.modelChanged = false;
				( (DataSetHandle) getContainer( ).getModel( ) ).removeListener( this );
				( (DataSetEditor) getContainer( ) ).updateDataSetDesign( DataSetHandle.PARAMETERS_PROP );
			}
			return super.performOk( );
		}
		else
		{
			String name = getNoneValuedParameterName( );
			boolean confirm = MessageDialog.openConfirm( null,
					Messages.getString( "dataset.editor.error.title" ),
					Messages.getFormattedString( "dataset.editor.error.validationParameter",
							new Object[]{
								name
							} ) );
			if ( confirm )
				( (DataSetEditor) getContainer( ) ).updateDataSetDesign( DataSetHandle.PARAMETERS_PROP );
			return confirm;
		}
	}

	/**
	 * whether to save empty parameter
	 * @param parameters
	 * @return
	 */
	private boolean doSaveEmptyParameter( PropertyHandle parameters )
	{
		if ( parameters == null )
		{
			parameters = ( (DataSetHandle) getContainer( ).getModel( ) ).getPropertyHandle( DataSetHandle.PARAMETERS_PROP );
			if ( (DataSetHandle) getContainer( ).getModel( ) instanceof OdaDataSetHandle )
				this.isOdaParameterStructure = true;
			else
				this.isOdaParameterStructure = false;
		}
		if ( parameters != null )
		{
			Iterator iter = parameters.iterator( );
			String paramName = null;
			if ( iter != null )
			{
				while ( iter.hasNext( ) )
				{
					DataSetParameterHandle parameter = (DataSetParameterHandle) iter.next( );
					if ( this.isOdaParameterStructure )
						paramName = ( (OdaDataSetParameterHandle) parameter ).getParamName( );
					if ( parameter.isInput( )
							&& paramName == null
							&& ( parameter.getDefaultValue( ) == null
									|| parameter.getDefaultValue( )
											.trim( )
											.length( ) == 0 || parameter.getDefaultValue( )
									.trim( )
									.equalsIgnoreCase( "null" ) ) ) //$NON-NLS-1$
					{
						setNoneValuedParameterName( parameter.getName( ) );
						return false;
					}
				}
			}
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.AbstractPropertyPage#canLeave()
	 */
	public boolean canLeave( )
	{
		refreshPositions( );
		if ( this.modelChanged
				&& this.getContainer( ) != null
				&& this.getContainer( ) instanceof DataSetEditor )
		{
			this.modelChanged = false;
			( (DataSetEditor) getContainer( ) ).updateDataSetDesign( DataSetHandle.PARAMETERS_PROP );
		}
		return true;
	}

	/**
	 * whether the page can be finished and closed.
	 */
	public boolean canFinish( )
	{
		refreshPositions( );
		return doSaveEmptyParameter( parameters );
	}

	private void clearNewParameter( )
	{
		newParameter = null;
		isDirectionSet = false;
		isDataTypeSet = false;
		viewer.getViewer( ).refresh( );
	}

	private void removeSelectedItem( )
	{
		//Get the current selection and delete that row
		int index = viewer.getViewer( ).getTable( ).getSelectionIndex( );
		int count = ( parameters.getListValue( ) == null ) ? 0
				: parameters.getListValue( ).size( );
		//Do not allow deletion of the last item.
		if ( index == count )
		{
			clearNewParameter( );
			viewer.getViewer( ).refresh( );
		}
	}

	private void removeAllItem( )
	{
		clearNewParameter( );
		viewer.getViewer( ).refresh( );
	}

	private boolean isUniqueName( Object dataSetParameter, String name )
	{
		DataSetParameter parameter = null;
		if ( dataSetParameter instanceof DataSetParameterHandle )
		{
			parameter = (DataSetParameter) ( (DataSetParameterHandle) dataSetParameter ).getStructure( );
		}
		else
		{
			parameter = (DataSetParameter) dataSetParameter;
		}
		Iterator iter = parameters.iterator( );
		if ( iter != null )
		{
			while ( iter.hasNext( ) )
			{
				DataSetParameterHandle handle = (DataSetParameterHandle) iter.next( );
				if ( parameter != handle.getStructure( )
						&& handle.getName( ).equals( name ) )
				{
					getContainer( ).setMessage( Messages.getString( "dataset.editor.error.duplicateParameterName" ), IMessageProvider.ERROR ); //$NON-NLS-1$
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 
	 *
	 */
	private class ViewerSelectionListener implements ISelectionChangedListener
	{

		/*
		 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
		 */
		public void selectionChanged( SelectionChangedEvent event )
		{
			setPageProperties( );
		}
	}

	/**
	 * Depending on the value of the parameters the properties of various controls
	 * on this page are set
	 */
	private void setPageProperties( )
	{
		boolean parametersExist = false;

		parametersExist = ( parameters != null
				&& parameters.getListValue( ) != null && parameters.getListValue( )
				.size( ) > 0 );
		if ( viewer != null )
		{
			viewer.getDownButton( ).setEnabled( parametersExist
					&& parameters.getListValue( ).size( ) > 1 );
			viewer.getUpButton( ).setEnabled( parametersExist
					&& parameters.getListValue( ).size( ) > 1 );
			viewer.getEditButton( ).setEnabled( parametersExist );
			viewer.getRemoveButton( ).setEnabled( parametersExist&&!isJointDataSet );
			viewer.getRemoveMenuItem( ).setEnabled( parametersExist&&!isJointDataSet );
			viewer.getRemoveAllMenuItem( ).setEnabled( parametersExist&&!isJointDataSet );

		}
		if ( parametersExist == false )
			getContainer( ).setMessage( DEFAULT_MESSAGE, IMessageProvider.NONE ); //$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#getToolTip()
	 */
	public String getToolTip( )
	{
		return Messages.getString( "DataSetParametersPage.Filter.Tooltip" ); //$NON-NLS-1$
	}

	/**
	 */
	public String getNoneValuedParameterName( )
	{
		return parameterName;
	}

	/**
	 * 
	 * @param name
	 */
	private void setNoneValuedParameterName( String name )
	{
		this.parameterName = name;
	}

	/**
	 * Since the weak link between the dataset parameter and report parameter, we had to 
	 * 
	 */
	private void enableModelChanged( )
	{
		( (DataSetEditor) this.getContainer( ) ).enableLinkedParamChanged( );
	}

	/**
	 * 
	 * @param typeName
	 * @return
	 */
	private String getTypeDisplayName( String typeName )
	{
		String displayName = dataTypes[1].getDisplayName( );
		for ( int i = 0; i < dataTypes.length; i++ )
		{
			if ( dataTypes[i].getName( ).equals( typeName ) )
				return dataTypes[i].getDisplayName( );
		}
		return displayName;
	}
	
	private String getTypeName( String typeDisplayName )
	{
		String name = dataTypes[1].getName( );
		for ( int i = 0; i < dataTypes.length; i++ )
		{
			if ( dataTypes[i].getDisplayName( ).equals( typeDisplayName ) )
				return dataTypes[i].getName( );
		}
		return name;
	}
	
	/**
	 * The listener on scalar parameter
	 * 
	 */
	private class ScalarParameterListener implements Listener
	{

		/**
		 * 
		 */
		public void elementChanged( DesignElementHandle focus,
				NotificationEvent ev )
		{
			modelChanged = true;
			enableModelChanged( );
		}
	}

	private class ParameterViewContentProvider
			implements
				IStructuredContentProvider
	{

		/*
		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
		 */
		public Object[] getElements( Object inputElement )
		{
			if ( inputElement == null
					|| !( inputElement instanceof PropertyHandle ) )
				return new Object[0];
			Iterator iter = ( (PropertyHandle) inputElement ).iterator( );
			ArrayList params = new ArrayList( 10 );
			if ( iter != null )
			{
				while ( iter.hasNext( ) )
				{
					params.add( iter.next( ) );
				}
			}

			refreshPositions( );
			return params.toArray( );
		}

		/*
		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
		 */
		public void dispose( )
		{
		}

		/*
		 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
		 */
		public void inputChanged( Viewer viewer, Object oldInput,
				Object newInput )
		{
		}
	}

	private class ParameterViewLableProvider implements ITableLabelProvider
	{

		boolean isOdaUsed = true;

		public ParameterViewLableProvider( boolean isOdaUsed )
		{
			this.isOdaUsed = isOdaUsed;
		}

		/*
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object,
		 *      int)
		 */
		public Image getColumnImage( Object element, int columnIndex )
		{
			return null;
		}

		/*
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object,
		 *      int)
		 */
		public String getColumnText( Object element, int columnIndex )
		{
			String value = null;
			DataSetParameter metaData = null;
			if ( element instanceof DataSetParameter )
			{
				metaData = (DataSetParameter) element;
			}
			else
			{
				metaData = (DataSetParameter) ( (DataSetParameterHandle) element ).getStructure( );
			}
			if ( metaData != newParameter )
			{
				if ( isOdaUsed )
					value = getOdaParametersValue( (OdaDataSetParameter) metaData,
							columnIndex );
				else
					value = getParametersValue( metaData, columnIndex );
			}
			else
			{
				if ( columnIndex == 1 )
				{
					value = Messages.getString( "DataSetParametersPage.Prompt.new" );
				}
			}

			if ( value == null )
			{
				value = ""; //$NON-NLS-1$
			}
			return value;
		}

		/*
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
		 */
		public void addListener( ILabelProviderListener listener )
		{
		}

		/*
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
		 */
		public void dispose( )
		{
		}

		/*
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
		 */
		public boolean isLabelProperty( Object element, String property )
		{
			return false;
		}

		/*
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
		 */
		public void removeListener( ILabelProviderListener listener )
		{
		}

		/**
		 * 
		 * @param parameter
		 * @param columnIndex
		 * @return
		 */
		private String getParametersValue( DataSetParameter parameter,
				int columnIndex )
		{
			String value = null;
			switch ( columnIndex )
			{
				case 0 :
				{
					if ( parameter.getPosition( ) != null )
					{
						value = parameter.getPosition( ).toString( );
					}
					break;
				}
				case 1 :
				{
					value = parameter.getName( );
					break;
				}
				case 2 :
				{
					if ( parameter != newParameter || isDataTypeSet )
					{
						value = getTypeDisplayName( parameter.getParameterDataType( ) );
					}
					break;
				}
				case 3 :
				{
					if ( parameter != newParameter || isDirectionSet )
					{
						value = getDirectionDisplayName( parameter.isInput( ),
								parameter.isOutput( ) );
					}
					break;
				}
				case 4 :
				{
					value = parameter.getDefaultValue( );
					break;
				}
			}
			return value;
		}

		/**
		 * 
		 * @param parameter
		 * @param columnIndex
		 * @return
		 */
		private String getOdaParametersValue( OdaDataSetParameter parameter,
				int columnIndex )
		{
			String value = null;
			switch ( columnIndex )
			{
				case 0 :
				{
					if ( parameter.getPosition( ) != null )
					{
						value = parameter.getPosition( ).toString( );
					}
					break;
				}
				case 1 :
				{
					value = parameter.getName( );
					break;
				}
				case 2 :
				{
					if ( parameter != newParameter || isDataTypeSet )
					{
						value = getTypeDisplayName( parameter.getParameterDataType( ) );
					}
					break;
				}
				case 3 :
				{
					if ( parameter != newParameter || isDirectionSet )
					{
						value = getDirectionDisplayName( parameter.isInput( ),
								parameter.isOutput( ) );
					}
					break;
				}
				case 4 :
				{
					if ( parameter.getParamName( ) == null
							|| parameter.getParamName( ).trim( ).length( ) == 0 )
						value = parameter.getDefaultValue( );
					else
						value = NONE_DEFAULT_VALUE;
					break;
				}
				case 5 :
				{
					if ( parameter != newParameter )
					{
						value = parameter.getParamName( );
						if ( value == null || value.trim( ).length( ) == 0 )
							value = UNLINKED_REPORT_PARAM;
					}
					break;
				}
			}
			return value;
		}
	}
	
	private class ParameterInputDialog extends PropertyHandleInputDialog
	{

		private DataSetParameterHandle structureHandle = null;
		private Composite defaultValueComposite = null;
		private Composite reportParamComposite = null;
		private String reportParamName = "";
		private Text dataSetParamName = null;

		protected ParameterInputDialog( Object structureOrHandle )
		{
			super( structureOrHandle );

			structureHandle = getStructureHandle( structureOrHandle );
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#createCustomControls(org.eclipse.swt.widgets.Composite)
		 */
		protected void createCustomControls( Composite parent )
		{
			createTextCell( parent, Utility.findIndex( cellProperties,
					DataSetParameter.NAME_MEMBER ) );
			createComboCellDataType( parent, Utility.findIndex( cellProperties,
					DataSetParameter.DATA_TYPE_MEMBER ) );
			createComboCellDirection( parent,
					Utility.findIndex( cellProperties, DIRECTION ) );
			createExpressionCell( parent, Utility.findIndex( cellProperties,
					DataSetParameter.DEFAULT_VALUE_MEMBER ) );

			if ( isOdaParameterStructure )
				createComboCellParameter( parent,
						Utility.findIndex( cellProperties,
								OdaDataSetParameter.PARAM_NAME_MEMBER ) );
		}

		private void createTextCell( Composite parent, final int index )
		{
			ControlProvider.createLabel( parent, cellLabels[index] );

			dataSetParamName = ControlProvider.createText( parent,
					structureHandle.getName( ) );
			dataSetParamName.setLayoutData( ControlProvider.getGridDataWithHSpan( 2 ) );
			dataSetParamName.addModifyListener( new ModifyListener( ) {

				public void modifyText( ModifyEvent e )
				{
					try
					{
						if ( dataSetParamName.getText( ).trim( ).length( ) == 0 )
						{
							updateStatus( getBlankPropertyStatus( cellLabels[index] ) );
						}
						else
						{
							structureHandle.setName( dataSetParamName.getText( ) );
							validateSyntax( );
						}
					}
					catch ( SemanticException e1 )
					{
						ExceptionHandler.handle( e1 );
					}
				}

			} );
		}

		private void createComboCellDataType( Composite parent, final int index )
		{
			ControlProvider.createLabel( parent, cellLabels[index] );

			final Combo cb = ControlProvider.createCombo( parent, SWT.READ_ONLY );
			cb.setLayoutData( ControlProvider.getGridDataWithHSpan( 2 ) );
			cb.setItems( getDataTypeDisplayNames( ) );
			cb.select( Utility.findIndex( cb.getItems( ),
					getTypeDisplayName( structureHandle.getParameterDataType( ) ) ) );
			cb.addSelectionListener( new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent e )
				{
					try
					{
						structureHandle.setParameterDataType( getTypeName( cb.getText( ) ) );
					}
					catch ( SemanticException e1 )
					{
						ExceptionHandler.handle( e1 );
					}
					validateSyntax( );
				}

			} );
			// special case for a new structure with default value
			if ( getStructureOrHandle( ) instanceof DataSetParameter )
			{
				try
				{
					structureHandle.setParameterDataType( getTypeName( cb.getText( ) ) );
				}
				catch ( SemanticException e1 )
				{
					ExceptionHandler.handle( e1 );
				}
			}
		}

		private String[] getDataTypeDisplayNames( )
		{
			String[] dataTypeDisplayNames = new String[dataTypes.length];
			for ( int i = 0; i < dataTypes.length; i++ )
			{
				dataTypeDisplayNames[i] = dataTypes[i].getDisplayName( );
			}

			return dataTypeDisplayNames;
		}

		private void createComboCellDirection( Composite parent, final int index )
		{
			ControlProvider.createLabel( parent, cellLabels[index] );

			final Combo cb = ControlProvider.createCombo( parent, SWT.READ_ONLY );
			cb.setLayoutData( ControlProvider.getGridDataWithHSpan( 2 ) );
			cb.setItems( getDirections( ) );
			cb.select( Utility.findIndex( cb.getItems( ),
					getDirectionDisplayName( structureHandle.isInput( ),
							structureHandle.isOutput( ) ) ) );
			cb.addSelectionListener( new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent e )
				{
					setDirection( cb.getText( ) );
					validateSyntax( );
				}

			} );
			// special case for a new structure with default value
			if ( getStructureOrHandle( ) instanceof DataSetParameter )
			{
				setDirection( cb.getText( ) );
			}
		}

		private void setDirection( String direction )
		{
			if ( direction == null || direction.equals( "" ) )
				return;

			if ( direction.equals( directions[0] ) )
			{
				structureHandle.setIsInput( true );
				structureHandle.setIsOutput( false );
			}
			else if ( direction.equals( directions[1] ) )
			{
				structureHandle.setIsInput( false );
				structureHandle.setIsOutput( true );
			}
			else if ( direction.equals( directions[2] ) )
			{
				structureHandle.setIsInput( true );
				structureHandle.setIsOutput( true );
			}
		}

		private void createExpressionCell( Composite parent, final int index )
		{
			ControlProvider.createLabel( parent, cellLabels[index] );

			defaultValueComposite = ControlProvider.getDefaultComposite( parent );
			final Text tx = ControlProvider.createText( defaultValueComposite,
					Utility.getNonNullString( structureHandle.getDefaultValue( ) ) );
			tx.setLayoutData( ControlProvider.getGridDataWithHSpan( 1 ) );
			tx.addModifyListener( new ModifyListener( ) {

				public void modifyText( ModifyEvent e )
				{
					if ( tx.isEnabled( )
							&& !tx.getText( )
									.equals( structureHandle.getDefaultValue( ) ) )
					{
						structureHandle.setDefaultValue( tx.getText( ) );
						validateSyntax( );
					}
				}

			} );

			SelectionAdapter listener = new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent event )
				{
					ExpressionBuilder expressionBuilder = new ExpressionBuilder( tx.getText( ) );
					expressionBuilder.setExpressionProvier( null );

					if ( expressionBuilder.open( ) == OK )
					{
						tx.setText( expressionBuilder.getResult( ).trim( ) );
					}
				}
			};

			ControlProvider.createButton( defaultValueComposite,
					SWT.PUSH,
					listener );
		}

		private void createComboCellParameter( Composite parent, final int index )
		{
			ControlProvider.createLabel( parent, cellLabels[index] );

			reportParamComposite = ControlProvider.getDefaultComposite( parent );
			final Combo cb = new Combo( reportParamComposite, SWT.READ_ONLY );
			cb.setLayoutData( ControlProvider.getGridDataWithHSpan( 1 ) );
			cb.setItems( getParameterNames( ) );
			cb.select( Utility.findIndex( cb.getItems( ),
					( (OdaDataSetParameterHandle) structureHandle ).getParamName( ) ) );
			cb.addSelectionListener( new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent e )
				{
					( (OdaDataSetParameterHandle) structureHandle ).setParamName( Utility.findIndex( cb.getItems( ),
							cb.getText( ) ) == 0 ? null : cb.getText( ) );
					validateSyntax( );
				}

			} );
			cb.addModifyListener( new ModifyListener( ) {

				public void modifyText( ModifyEvent e )
				{
					( (OdaDataSetParameterHandle) structureHandle ).setParamName( Utility.findIndex( cb.getItems( ),
							cb.getText( ) ) == 0 ? null : cb.getText( ) );
					validateSyntax( );
				}

			} );

			SelectionAdapter listener = new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent event )
				{
					OdaDataSetParameterHandle dataSetParameterHandle = (OdaDataSetParameterHandle) structureHandle;
					String originalParamName = dataSetParameterHandle.getParamName( );
					ParameterDialog dialog = null;
					ParameterHandle handle = Utility.getScalarParameter( cb.getText( ) );
					boolean isCreateMode = true;
					if ( handle == null )
					{
						handle = (ScalarParameterHandle) ElementProcessorFactory.createProcessor( "ScalarParameter" )//$NON-NLS-1$
								.createElement( null );
						dialog = new ParameterDialog( Messages.getString( "ParameterGroupNodeProvider.Dialogue.ParameterNew" ) ); //$NON-NLS-1$
						if ( dataSetParameterHandle != null )
						{
							ReportParameterAdapter adapter = new ReportParameterAdapter( );
							try
							{
								adapter.updateLinkedReportParameter( (ScalarParameterHandle) handle,
										dataSetParameterHandle,
										( (DataSetEditor) getContainer( ) ).getCurrentDataSetDesign( ) );
							}
							catch ( SemanticException e )
							{
							}
							catch ( OdaException e )
							{
							}
						}
						isCreateMode = true;
					}
					else
					{
						dialog = new ParameterDialog( Messages.getString( "ParameterNodeProvider.dial.title.editScalar" ) ); //$NON-NLS-1$
						isCreateMode = false;
					}
					handle.addListener( new ScalarParameterListener( ) );
					dialog.setInput( handle );
					if ( dialog.open( ) == OK )
					{
						if ( dialog.getResult( ) instanceof ParameterHandle )
						{
							ParameterHandle paramerHandle = (ParameterHandle) dialog.getResult( );
							if ( isCreateMode )
							{
								SlotHandle parameterSlotHandle = Utility.getReportModuleHandle( )
										.getParameters( );
								try
								{
									parameterSlotHandle.add( paramerHandle );
									cb.add( paramerHandle.getQualifiedName( ) );
								}
								catch ( ContentException e )
								{
									ExceptionHandler.handle( e );
								}
								catch ( NameException e )
								{
									ExceptionHandler.handle( e );
								}
							}
							cb.setItems( getParameterNames( ) );
							cb.select( Utility.findIndex( cb.getItems( ),
									paramerHandle.getQualifiedName( ) ) );
						}
					}
					else
					{
						dataSetParameterHandle.setParamName( originalParamName );
					}
				}
			};

			ControlProvider.createButton( reportParamComposite,
					SWT.PUSH,
					listener );
		}

		private String[] getParameterNames( )
		{
			List parameterList = Utility.getAllParameters( );
			List nameList = new ArrayList( );
			nameList.add( UNLINKED_REPORT_PARAM );
			for ( int i = 0; i < parameterList.size( ); i++ )
			{
				ReportElementHandle handle = (ReportElementHandle) parameterList.get( i );
				if ( handle instanceof ScalarParameterHandle )
				{
					nameList.add( handle.getQualifiedName( ) );
				}
			}
			String[] paramName = new String[nameList.size( )];
			for ( int i = 0; i < nameList.size( ); i++ )
			{
				paramName[i] = nameList.get( i ).toString( );
			}

			return paramName;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#rollback()
		 */
		protected void rollback( )
		{
			DataSetParameter structure = getStructure( getStructureOrHandle( ) );
			if ( originalStructure != null )
			{
				structure.setName( originalStructure.getName( ) );
				structure.setParameterDataType( originalStructure.getParameterDataType( ) );
				structure.setIsInput( originalStructure.isInput( ) );
				structure.setIsOutput( originalStructure.isOutput( ) );
				structure.setDefaultValue( originalStructure.getDefaultValue( ) );

				if ( isOdaParameterStructure )
					( (OdaDataSetParameter) structure ).setParamName( ( (OdaDataSetParameter) originalStructure ).getParamName( ) );

				originalStructure = null;
			}
			else
			{
				try
				{
					parameters.removeItem( structure );
					viewer.getViewer( ).refresh( );
				}
				catch ( PropertyValueException e )
				{
					ExceptionHandler.handle( e );
				}
			}
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#validateSemantics(java.lang.Object)
		 */
		protected IStatus validateSemantics( Object structureOrHandle )
		{
			if ( !isUniqueName( ) )
			{
				return new Status( IStatus.ERROR,
						PlatformUI.PLUGIN_ID,
						IStatus.OK,
						Messages.getString( "dataset.editor.error.duplicateParameterName" ),//$NON-NLS-1$
						null );
			}

			return new Status( IStatus.OK,
					PlatformUI.PLUGIN_ID,
					IStatus.OK,
					"",
					null );
		}

		private boolean isUniqueName( )
		{
			DataSetParameter structure = getStructure( getStructureOrHandle( ) );
			Iterator iter = parameters.iterator( );
			if ( iter != null )
			{
				while ( iter.hasNext( ) )
				{
					DataSetParameterHandle handle = (DataSetParameterHandle) iter.next( );
					if ( structure != handle.getStructure( )
							&& handle.getName( ).equals( structure.getName( ) ) )
					{
						return false;
					}
				}
			}

			return true;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#validateSyntax(java.lang.Object)
		 */
		protected IStatus validateSyntax( Object structureOrHandle )
		{
			// output parameter check
			if ( isOutputParameter( ) )
			{
				enableComposite( defaultValueComposite, false );
				Text tx = ( (Text) defaultValueComposite.getChildren( )[0] );
				if ( !tx.getText( ).equals( "" ) )
					tx.setText( "" );

				if ( isOdaParameterStructure )
				{
					enableComposite( reportParamComposite, false );
				}
			}
			else
			{
				enableComposite( defaultValueComposite, true );
				if ( isOdaParameterStructure )
				{
					enableComposite( reportParamComposite, true );
				}
			}

			// defaultValue check
			if ( isOdaParameterStructure )
			{
				String paramName = ( (OdaDataSetParameterHandle) structureHandle ).getParamName( );

				if ( needsCheck( reportParamName, paramName ) )
				{
					reportParamName = paramName;
					Control[] controls = defaultValueComposite.getChildren( );
					assert controls[0] instanceof Text;
					Text tx = (Text) controls[0];

					if ( paramName == null )
					{
						for ( int i = 0; i < controls.length; i++ )
						{
							controls[i].setEnabled( true );
						}
						tx.setText( Utility.getNonNullString( structureHandle.getDefaultValue( ) ) );
					}
					else
					{
						for ( int i = 0; i < controls.length; i++ )
						{
							controls[i].setEnabled( false );
						}
						tx.setText( NONE_DEFAULT_VALUE );
					}
				}
			}

			// blankProperty check
			if ( structureHandle.getName( ).trim( ).length( ) == 0
					|| dataSetParamName.getText( ).trim( ).length( ) == 0 )
			{
				return getBlankPropertyStatus( cellLabels[Utility.findIndex( cellProperties,
						DataSetParameter.NAME_MEMBER )] );
			}

			return new Status( IStatus.OK,
					PlatformUI.PLUGIN_ID,
					IStatus.OK,
					"",
					null );
		}
		
		private boolean needsCheck( String reportParamName, String paramName )
		{
			if ( !reportParamComposite.isEnabled( ) )
				return false;
			if ( reportParamName == null && paramName == null )
				return false;
			if ( reportParamName != null && reportParamName.equals( paramName ) )
				return false;

			return true;
		}

		private boolean isOutputParameter( )
		{
			return !structureHandle.isInput( ) && structureHandle.isOutput( );
		}

		private void enableComposite( Composite composite, boolean enable )
		{
			if ( composite.isEnabled( ) != enable )
			{
				composite.setEnabled( enable );
				Control[] controls = composite.getChildren( );
				for ( int i = 0; i < controls.length; i++ )
				{
					controls[i].setEnabled( enable );
				}
			}
		}
		
		private DataSetParameterHandle getStructureHandle( Object structureOrHandle )
		{
			if ( structureOrHandle instanceof DataSetParameterHandle )
			{
				return (DataSetParameterHandle) structureOrHandle;
			}

			else
			{
				DataSetParameterHandle handle = null;
				try
				{
					handle = (DataSetParameterHandle) parameters.addItem( (DataSetParameter) getStructure( getStructureOrHandle( ) ) );
//					viewer.getViewer( ).refresh( );
				}
				catch ( SemanticException e )
				{
					ExceptionHandler.handle( e );
				}
				assert handle != null;
				return handle;
			}
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#getTitle()
		 */
		protected String getTitle( )
		{
			return super.getTitle( )
					+ " "
					+ Messages.getString( "DataSetParameterPage.title.ParameterInputDialog" );
		}

	}
	
}