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

package org.eclipse.birt.report.designer.data.ui.dataset;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.birt.core.data.ExpressionUtil;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.data.engine.api.IBaseExpression;
import org.eclipse.birt.data.engine.api.IPreparedQuery;
import org.eclipse.birt.data.engine.api.IQueryDefinition;
import org.eclipse.birt.data.engine.api.IQueryResults;
import org.eclipse.birt.data.engine.api.IResultIterator;
import org.eclipse.birt.data.engine.api.querydefn.BaseQueryDefinition;
import org.eclipse.birt.data.engine.api.querydefn.GroupDefinition;
import org.eclipse.birt.data.engine.api.querydefn.ScriptExpression;
import org.eclipse.birt.report.designer.data.ui.property.AbstractDescriptionPropertyPage;
import org.eclipse.birt.report.designer.data.ui.util.ChoiceSetFactory;
import org.eclipse.birt.report.designer.data.ui.util.ControlProvider;
import org.eclipse.birt.report.designer.data.ui.util.DataSetExpressionProvider;
import org.eclipse.birt.report.designer.data.ui.util.DataSetProvider;
import org.eclipse.birt.report.designer.data.ui.util.ExpressionUtility;
import org.eclipse.birt.report.designer.data.ui.util.Utility;
import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
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.SelectValueDialog;
import org.eclipse.birt.report.model.api.DataSetHandle;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.FilterConditionHandle;
import org.eclipse.birt.report.model.api.ParamBindingHandle;
import org.eclipse.birt.report.model.api.PropertyHandle;
import org.eclipse.birt.report.model.api.ReportElementHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.elements.DesignChoiceConstants;
import org.eclipse.birt.report.model.api.elements.structures.FilterCondition;
import org.eclipse.birt.report.model.api.metadata.IChoice;
import org.eclipse.birt.report.model.api.metadata.IChoiceSet;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IMessageProvider;
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.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.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;

/**
 * Presents dataset filters page of data set creation wizard
 * 
 * 
 */

public final class DataSetFiltersPage extends AbstractDescriptionPropertyPage
		implements
			ITableLabelProvider
{

	private transient PropertyHandleTableViewer viewer = null;
	private transient DataSetViewData[] columns = null;
	private transient String[] columnExpressions = null;
	private transient PropertyHandle filters = null;
	private FilterCondition originalStructure = null;
	
	private static String[] cellLabels = new String[]{
			Messages.getString( "dataset.editor.title.expression" ),//$NON-NLS-1$
			Messages.getString( "dataset.editor.title.operator" ),//$NON-NLS-1$
			Messages.getString( "dataset.editor.title.value1" ),//$NON-NLS-1$
			Messages.getString( "dataset.editor.title.value2" )//$NON-NLS-1$
	};
	private static String[] cellProperties = new String[]{
			FilterCondition.EXPR_MEMBER,
			FilterCondition.OPERATOR_MEMBER,
			FilterCondition.VALUE1_MEMBER,
			FilterCondition.VALUE2_MEMBER
	};
	private static String[] operators;
	private static String[] operatorDisplayNames;
	static
	{
		IChoiceSet chset = ChoiceSetFactory.getStructChoiceSet( FilterCondition.FILTER_COND_STRUCT,
				FilterCondition.OPERATOR_MEMBER );
		IChoice[] chs = chset.getChoices( );
		operators = new String[chs.length];
		operatorDisplayNames = new String[chs.length];

		for ( int i = 0; i < chs.length; i++ )
		{
			operators[i] = chs[i].getName( );
			operatorDisplayNames[i] = chs[i].getDisplayName( );
		}
	}

	/**
	 * Constructor.
	 */
	public DataSetFiltersPage( )
	{
		super( );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#createPageControl(org.eclipse.swt.widgets.Composite)
	 */
	public Control createContents( Composite parent )
	{
		initColumnNames( );
		viewer = new PropertyHandleTableViewer( parent, true, true, true );
		TableColumn column = new TableColumn( viewer.getViewer( ).getTable( ),
				SWT.LEFT );
		column.setText( cellLabels[Utility.findIndex( cellProperties,
				FilterCondition.EXPR_MEMBER )] ); 
		column.setWidth( 150 );
		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( cellLabels[Utility.findIndex( cellProperties,
				FilterCondition.OPERATOR_MEMBER )] ); 
		column.setWidth( 100 );
		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( cellLabels[Utility.findIndex( cellProperties,
				FilterCondition.VALUE1_MEMBER )] ); 
		column.setWidth( 100 );
		column = new TableColumn( viewer.getViewer( ).getTable( ), SWT.LEFT );
		column.setText( cellLabels[Utility.findIndex( cellProperties,
				FilterCondition.VALUE2_MEMBER )] ); 
		column.setWidth( 100 );

		initializeFilters( );

		viewer.getViewer( )
				.setContentProvider( new IStructuredContentProvider( ) {

					public Object[] getElements( Object inputElement )
					{
						ArrayList filterList = new ArrayList( 10 );
						Iterator iter = filters.iterator( );
						if ( iter != null )
						{
							while ( iter.hasNext( ) )
							{
								filterList.add( iter.next( ) );
							}
						}

						return filterList.toArray( );
					}

					public void dispose( )
					{

					}

					public void inputChanged( Viewer viewer, Object oldInput,
							Object newInput )
					{

					}
				} );
		viewer.getViewer( ).setLabelProvider( this );
		viewer.getViewer( ).setInput( filters );
		addListeners( );
		setToolTips( );

		return viewer.getControl( );
	}

	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 )
				{
					setPageProperties( );
				}
			}

		} );

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

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

					public void widgetDefaultSelected( SelectionEvent e )
					{
					}

				} );

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

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

					public void widgetDefaultSelected( SelectionEvent e )
					{
					}

				} );

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

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

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

		viewer.getViewer( )
				.addSelectionChangedListener( new ViewerSelectionListener( ) );
	}
	
	private void doNew( )
	{
		doEdit( new FilterCondition( ) );
	}

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

		FilterConditionHandle handle = (FilterConditionHandle) viewer.getViewer( )
				.getTable( )
				.getItem( index )
				.getData( );
		originalStructure = (FilterCondition) handle.getStructure( ).copy( );

		// replace operatorName with operatorDisplayName
		Utility.setStructureProperty( handle.getStructure( ),
				FilterCondition.OPERATOR_MEMBER,
				getOperatorDisplayName( Utility.getStructureProperty( handle.getStructure( ),
						FilterCondition.OPERATOR_MEMBER ) ) );

		doEdit( handle );
	}

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

		if ( dlg.open( ) == Window.OK )
		{
			update( structureOrHandle );
		}
	}

	private void update( Object structureOrHandle )
	{
		FilterCondition structure = getStructure( structureOrHandle );

		// set Expression
		String expression = Utility.getStructureProperty( structure,
				FilterCondition.EXPR_MEMBER );
		if ( isColumnName( expression ) )
		{
			expression = getQualifiedExpression( expression );
			Utility.setStructureProperty( structure,
					FilterCondition.EXPR_MEMBER,
					expression );
		}

		// replace operatorDisplayName with operatorName
		try
		{
			Utility.setProperty( structureOrHandle,
					FilterCondition.OPERATOR_MEMBER,
					getOperatorName( Utility.getStructureProperty( structure,
							FilterCondition.OPERATOR_MEMBER ) ) );
		}
		catch ( Exception e )
		{
			ExceptionHandler.handle( e );
		}

		if ( structureOrHandle instanceof FilterCondition )
		{
			try
			{
				filters.addItem( (FilterCondition) structureOrHandle );
				viewer.getViewer( ).refresh( );
			}
			catch ( SemanticException e )
			{
				ExceptionHandler.handle( e );
			}
		}
		else
		{
			viewer.getViewer( ).update( structureOrHandle, null );
		}
	}
	
	private FilterCondition getStructure( Object structureOrHandle )
	{
		FilterCondition structure = null;
		if ( structureOrHandle instanceof FilterCondition )
		{
			structure = (FilterCondition) structureOrHandle;
		}
		else
		{
			structure = (FilterCondition) ( (FilterConditionHandle) structureOrHandle ).getStructure( );
		}

		return structure;
	}
	
	private String getOperatorName( String displayName )
	{
		for ( int i = 0; i < operatorDisplayNames.length; i++ )
		{
			if ( operatorDisplayNames[i].equals( displayName ) )
			{
				return operators[i];
			}
		}

		// should never get here
		return operators[0];
	}
	
	private String getOperatorDisplayName( String name )
	{
		for ( int i = 0; i < operators.length; i++ )
		{
			if ( operators[i].equals( name ) )
			{
				return operatorDisplayNames[i];
			}
		}

		// should never get here
		return operatorDisplayNames[0];
	}
	
	private void setToolTips( )
	{
		viewer.getNewButton( )
				.setToolTipText( Messages.getString( "DataSetFiltersPage.toolTipText.New" ) );//$NON-NLS-1$
		viewer.getEditButton( )
				.setToolTipText( Messages.getString( "DataSetFiltersPage.toolTipText.Edit" ) );//$NON-NLS-1$
		viewer.getDownButton( )
				.setToolTipText( Messages.getString( "DataSetFiltersPage.toolTipText.Down" ) );//$NON-NLS-1$
		viewer.getUpButton( )
				.setToolTipText( Messages.getString( "DataSetFiltersPage.toolTipText.Up" ) );//$NON-NLS-1$
		viewer.getRemoveButton( )
				.setToolTipText( Messages.getString( "DataSetFiltersPage.toolTipText.Remove" ) );//$NON-NLS-1$
	}

	private void initColumnNames( )
	{
		columns = ( (DataSetEditor) this.getContainer( ) ).getCurrentItemModel( true,
				true );
		if ( columns != null )
		{
			columnExpressions = new String[columns.length];
			for ( int n = 0; n < columns.length; n++ )
			{
				columnExpressions[n] = columns[n].getName( );
			}
		}
	}
	
	private boolean isColumnName( String name )
	{
		for ( int n = 0; n < columnExpressions.length; n++ )
		{
			if ( columnExpressions[n].equals( name ) )
			{
				return true;
			}
		}
		return false;
	}
	
	private String getQualifiedExpression( String expression )
	{
		return ExpressionUtil.createJSRowExpression( expression ); //$NON-NLS-1$ //$NON-NLS-2$
	}

	private void initializeFilters( )
	{
		filters = ( (DataSetHandle) getContainer( ).getModel( ) ).getPropertyHandle( DataSetHandle.FILTER_PROP );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#pageActivated()
	 */
	public void pageActivated( )
	{
		getContainer( ).setMessage( Messages.getString( "dataset.editor.filters" ), IMessageProvider.NONE ); //$NON-NLS-1$
		initColumnNames( );
		// The proeprties of the various controls on the page
		// will be set depending on the filters
		setPageProperties( );
		viewer.getViewer( ).getTable( ).select( 0 );
	}

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

		filterConditionExists = ( filters != null
				&& filters.getListValue( ) != null && filters.getListValue( )
				.size( ) > 0 );
		viewer.getEditButton( ).setEnabled( filterConditionExists );
		viewer.getDownButton( ).setEnabled( filterConditionExists
				&& filters.getListValue( ).size( ) > 1 );
		viewer.getUpButton( ).setEnabled( filterConditionExists
				&& filters.getListValue( ).size( ) > 1 );
		viewer.getRemoveButton( ).setEnabled( filterConditionExists );
		viewer.getRemoveMenuItem( ).setEnabled( filterConditionExists );
		viewer.getRemoveAllMenuItem( ).setEnabled( filterConditionExists );
	}

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

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object,
	 *      int)
	 */
	public String getColumnText( Object element, int columnIndex )
	{
		String value = null;
		FilterCondition filterCondition = getStructure( element );

		try
		{
			switch ( columnIndex )
			{
				case 0 :
				{
					value = Utility.getStructureProperty( filterCondition,
							FilterCondition.EXPR_MEMBER ); //$NON-NLS-1$
					break;
				}
				case 1 :
				{
					value = getOperatorDisplayName( Utility.getStructureProperty( filterCondition,
							FilterCondition.OPERATOR_MEMBER ) ); //$NON-NLS-1$
					break;
				}
				case 2 :
				{
					value = Utility.getStructureProperty( filterCondition,
							FilterCondition.VALUE1_MEMBER ); //$NON-NLS-1$
					break;
				}
				case 3 :
				{
					value = Utility.getStructureProperty( filterCondition,
							FilterCondition.VALUE2_MEMBER ); //$NON-NLS-1$
					break;
				}
			}
		}
		catch ( Exception ex )
		{
			ExceptionHandler.handle( ex );
		}
		if ( value == null )
		{
			value = ""; //$NON-NLS-1$
		}

		return value;
	}

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

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

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

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

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.AbstractDescriptionPropertyPage#getPageDescription()
	 */
	public String getPageDescription( )
	{
		return Messages.getString( "DataSetFiltersPage.description" ); //$NON-NLS-1$
	}

	private class ViewerSelectionListener implements ISelectionChangedListener
	{

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
		 */
		public void selectionChanged( SelectionChangedEvent event )
		{
			// TODO Auto-generated method stub
			setPageProperties( );
		}

	}

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

		private FilterCondition structure = null;
		private Map controlMap = new Hashtable( );

		private FilterInputDialog( Object structureOrHandle )
		{
			super( structureOrHandle );

			structure = getStructure( structureOrHandle );
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#createCustomControls(org.eclipse.swt.widgets.Composite)
		 */
		protected void createCustomControls( Composite parent )
		{
			createComboBoxExpressionCell( parent,
					Utility.findIndex( cellProperties,
							FilterCondition.EXPR_MEMBER ) );
			createComboBoxCell( parent, Utility.findIndex( cellProperties,
					FilterCondition.OPERATOR_MEMBER ) );
			createExpressionValueCell( parent,
					Utility.findIndex( cellProperties,
							FilterCondition.VALUE1_MEMBER ) );
			createExpressionValueCell( parent,
					Utility.findIndex( cellProperties,
							FilterCondition.VALUE2_MEMBER ) );
		}

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

			// in case method setItems clears structure
			String value = Utility.getStructureProperty( structure,
					cellProperties[index] );

			final Combo cb = ControlProvider.createCombo( parent, SWT.NONE );
			cb.setLayoutData( ControlProvider.getGridDataWithHSpan( 1 ) );
			if ( columnExpressions == null )
				columnExpressions = new String[]{};
			cb.setItems( columnExpressions );
			cb.setText( value );
			cb.addModifyListener( new ModifyListener( ) {

				public void modifyText( ModifyEvent e )
				{
					Utility.setStructureProperty( structure,
							cellProperties[index],
							cb.getText( ) );
					validateSyntax( );
				}

			} );

			SelectionAdapter listener = new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent event )
				{
					ExpressionBuilder expressionBuilder = new ExpressionBuilder( cb.getText( ) );
					expressionBuilder.setExpressionProvier( new DataSetExpressionProvider( (DesignElementHandle) getContainer( ).getModel( ) ) );

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

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

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

			final Combo cb = new Combo( parent, SWT.READ_ONLY );
			cb.setLayoutData( ControlProvider.getGridDataWithHSpan( 2 ) );
			cb.setItems( operatorDisplayNames );
			cb.select( Utility.findIndex( cb.getItems( ),
					Utility.getStructureProperty( structure,
							cellProperties[index] ) ) );
			cb.addSelectionListener( new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent e )
				{
					Utility.setStructureProperty( structure,
							cellProperties[index],
							cb.getText( ) );
					validateSyntax( );
				}

			} );
			// special case for a new structure with default value
			if ( getStructureOrHandle( ) instanceof FilterCondition )
			{
				Utility.setStructureProperty( structure,
						cellProperties[index],
						cb.getText( ) );
			}
		}

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

			final String[] actions = new String[]{
					Messages.getString( "ExpressionValueCellEditor.selectValueAction" ), //$NON-NLS-1$
					Messages.getString( "ExpressionValueCellEditor.buildExpressionAction" ), //$NON-NLS-1$
			};

			Composite composite = new Composite( parent, SWT.NONE );
			composite.setLayoutData( ControlProvider.getGridDataWithHSpan( 2 ) );
			final Text tx = ControlProvider.createText( composite,
					Utility.getStructureProperty( structure,
							cellProperties[index] ) );
			tx.setLayoutData( ControlProvider.getGridDataWithHSpan( 1 ) );
			tx.addModifyListener( new ModifyListener( ) {

				public void modifyText( ModifyEvent e )
				{
					Utility.setStructureProperty( structure,
							cellProperties[index],
							tx.getText( ) );
					validateSyntax( );
				}

			} );

			SelectionAdapter listener = new SelectionAdapter( ) {

				public void widgetSelected( SelectionEvent e )
				{
					Rectangle textBounds = tx.getBounds( );
					Point pt = tx.toDisplay( textBounds.x, textBounds.y );
					Rectangle rect = new Rectangle( pt.x, pt.y, tx.getParent( )
							.getBounds( ).width, textBounds.height );

					PopupSelectionList popup = new PopupSelectionList( tx.getParent( )
							.getShell( ) );
					popup.setItems( actions );
					String value = popup.open( rect );
					if ( value != null )
					{
						if ( value.equals( ( actions[0] ) ) )
						{
							String expression = ( structure instanceof FilterCondition )
									? Utility.getStructureProperty( structure,
											FilterCondition.EXPR_MEMBER ) : "";

							if ( isColumnName( expression ) )
							{
								expression = getQualifiedExpression( expression );
							}

							if ( ExpressionUtility.isColumnExpression( expression ) )
							{
								try
								{
									List selectValueList = getSelectValueList( expression,
											(ReportElementHandle) getContainer( ).getModel( ) );
									SelectValueDialog dlg = new SelectValueDialog( PlatformUI.getWorkbench( )
											.getDisplay( )
											.getActiveShell( ),
											Messages.getString( "ExpressionValueCellEditor.title" ) ); //$NON-NLS-1$
									dlg.setSelectedValueList( selectValueList );
									if ( dlg.open( ) == OK )
									{
										tx.setText( dlg.getSelectedExprValue( ) );
									}
								}
								catch ( Exception ex )
								{
									updateStatus( new Status( IStatus.ERROR,
											PlatformUI.PLUGIN_ID,
											IStatus.OK,
											ex.getMessage( ),
											null ) );
								}
							}
							else
							{
								updateStatus( new Status( IStatus.WARNING,
										PlatformUI.PLUGIN_ID,
										IStatus.OK,
										Messages.getString( "DataSetFiltersPage.messages.selectVauleUnavailable" ),
										null ) );
							}
						}
						else if ( value.equals( actions[1] ) )
						{
							ExpressionBuilder dialog = new ExpressionBuilder( PlatformUI.getWorkbench( )
									.getDisplay( )
									.getActiveShell( ),
									tx.getText( ) );

							dialog.setExpressionProvier( new DataSetExpressionProvider( (DesignElementHandle) getContainer( ).getModel( ) ) );

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

			};

			final Button bt = ControlProvider.createButton( composite,
					SWT.ARROW | SWT.DOWN,
					listener );

			composite.setLayout( new Layout( ) {

				public void layout( Composite editor, boolean force )
				{
					Rectangle bounds = editor.getClientArea( );
					Point size = bt.computeSize( SWT.DEFAULT,
							SWT.DEFAULT,
							force );
					tx.setBounds( 0, 0, bounds.width - size.x, bounds.height );
					bt.setBounds( bounds.width - size.x,
							0,
							size.x,
							bounds.height );
				}

				public Point computeSize( Composite editor, int wHint,
						int hHint, boolean force )
				{
					if ( wHint != SWT.DEFAULT && hHint != SWT.DEFAULT )
						return new Point( wHint, hHint );
					Point contentsSize = tx.computeSize( SWT.DEFAULT,
							SWT.DEFAULT,
							force );
					Point buttonSize = bt.computeSize( SWT.DEFAULT,
							SWT.DEFAULT,
							force );
					Point result = new Point( buttonSize.x,
							Math.max( contentsSize.y, buttonSize.y ) );
					return result;
				}

			} );

			controlMap.put( cellProperties[index], composite );
		}

		/**
		 * Get the value list of selected column
		 * 
		 * @param selectValueExpression
		 * @param currentItem
		 * @return
		 * @throws BirtException
		 */
		private List getSelectValueList( String selectValueExpression,
				ReportElementHandle currentItem ) throws BirtException
		{
			ParamBindingHandle[] bindingParams = null;
			List selectValueList = new ArrayList( );
			if ( selectValueExpression != null
					&& selectValueExpression.trim( ).length( ) > 0
					&& currentItem instanceof DataSetHandle )
			{
				// Execute the query and populate this list
				IPreparedQuery queryDefn = DataSetProvider.getCurrentInstance( )
						.prepareQuery( (DataSetHandle) currentItem,
								bindingParams,
								true,
								false );
				BaseQueryDefinition query = (BaseQueryDefinition) queryDefn.getReportQueryDefn( );

				String bindingNameGroup = "GROUP_SELECTVALUE";
				IBaseExpression bindingExprGroup = new ScriptExpression( ExpressionUtility.getReplacedColRefExpr( selectValueExpression ) );
				GroupDefinition groupDefn = new GroupDefinition( );
				groupDefn.setKeyExpression( "row.GROUP_SELECTVALUE" );
				if ( bindingNameGroup != null )
					query.addResultSetExpression( bindingNameGroup,
							bindingExprGroup );
				query.addGroup( groupDefn );
				query.setUsesDetails( false );

				IPreparedQuery preparedQuery = DataSetProvider.getCurrentInstance( )
						.prepareQuery( (DataSetHandle) currentItem,
								(IQueryDefinition) query,
								true,
								false );

				IQueryResults results = preparedQuery.execute( null );

				if ( results != null )
				{
					IResultIterator iter = null;
					iter = results.getResultIterator( );

					if ( iter != null )
					{
						while ( iter.next( ) )
						{
							Object candiateValue = iter.getValue( bindingNameGroup );
							if ( candiateValue != null )
							{
								selectValueList.add( candiateValue );
							}
							iter.skipToEnd( 1 );
						}
					}

					results.close( );
				}
			}
			else
			{
				selectValueList.clear( );
			}

			return selectValueList;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#validateSemantics(java.lang.Object)
		 */
		protected IStatus validateSemantics( Object structureOrHandle )
		{
			return null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#validateSyntax(java.lang.Object)
		 */
		protected IStatus validateSyntax( Object structureOrHandle )
		{
			// composites check
			Composite[] composites = new Composite[]{
					(Composite) controlMap.get( FilterCondition.VALUE1_MEMBER ),
					(Composite) controlMap.get( FilterCondition.VALUE2_MEMBER )
			};
			for ( int i = 0; i < composites.length; i++ )
			{
				if ( composites[i] == null )
					return null;
			}

			// operator check
			String operator = getOperatorName( Utility.getStructureProperty( structure,
					FilterCondition.OPERATOR_MEMBER ) );
			if ( !operator.equals( "" ) )
			{
				if ( ( operator.equals( DesignChoiceConstants.FILTER_OPERATOR_NULL )
						|| operator.equals( DesignChoiceConstants.FILTER_OPERATOR_NOT_NULL )
						|| operator.equals( DesignChoiceConstants.FILTER_OPERATOR_TRUE ) || operator.equals( DesignChoiceConstants.FILTER_OPERATOR_FALSE ) ) )
				{
					for ( int i = 0; i < composites.length; i++ )
					{
						{
							Control[] controls = composites[i].getChildren( );
							for ( int j = 0; j < controls.length; j++ )
							{
								controls[j].setEnabled( false );
								if ( controls[j] instanceof Text
										&& !( (Text) controls[j] ).getText( )
												.equals( "" ) )
									( (Text) controls[j] ).setText( "" );
							}
						}
					}
				}

				else if ( ( operator.equals( DesignChoiceConstants.FILTER_OPERATOR_BETWEEN ) || operator.equals( DesignChoiceConstants.FILTER_OPERATOR_NOT_BETWEEN ) ) )
				{
					for ( int i = 0; i < composites.length; i++ )
					{
						{
							Control[] controls = composites[i].getChildren( );
							for ( int j = 0; j < controls.length; j++ )
							{
								controls[j].setEnabled( true );
							}
						}
					}
					if ( Utility.getStructureProperty( structure,
							FilterCondition.VALUE1_MEMBER ).trim( ).length( ) == 0 )
						return getBlankPropertyStatus( cellLabels[Utility.findIndex( cellProperties,
								FilterCondition.VALUE1_MEMBER )] );
					else if ( Utility.getStructureProperty( structure,
							FilterCondition.VALUE2_MEMBER ).trim( ).length( ) == 0 )
						return getBlankPropertyStatus( cellLabels[Utility.findIndex( cellProperties,
								FilterCondition.VALUE2_MEMBER )] );
				}
				else
				{
					for ( int i = 0; i < composites.length; i++ )
					{
						Control[] controls = composites[i].getChildren( );
						if ( i == 0 )// value1
						{
							for ( int j = 0; j < controls.length; j++ )
							{
								controls[j].setEnabled( true );
							}
						}
						else
						// value2
						{
							for ( int j = 0; j < controls.length; j++ )
							{
								controls[j].setEnabled( false );
								if ( controls[j] instanceof Text
										&& !( (Text) controls[j] ).getText( )
												.equals( "" ) )
									( (Text) controls[j] ).setText( "" );
							}
						}
					}
					if ( Utility.getStructureProperty( structure,
							FilterCondition.VALUE1_MEMBER ).trim( ).length( ) == 0 )
					{
						return getBlankPropertyStatus( cellLabels[Utility.findIndex( cellProperties,
								FilterCondition.VALUE1_MEMBER )] );
					}
				}
			}

			// blankProperty check
			if ( Utility.getStructureProperty( structure,
					FilterCondition.EXPR_MEMBER ).trim( ).length( ) == 0 )
			{
				return getBlankPropertyStatus( cellLabels[Utility.findIndex( cellProperties,
						FilterCondition.EXPR_MEMBER )] );
			}
			else if ( Utility.getStructureProperty( structure,
					FilterCondition.OPERATOR_MEMBER ).trim( ).length( ) == 0 )
			{
				return getBlankPropertyStatus( cellLabels[Utility.findIndex( cellProperties,
						FilterCondition.OPERATOR_MEMBER )] );
			}

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

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#rollback()
		 */
		protected void rollback( )
		{
			if ( originalStructure != null )
			{
				for ( int i = 0; i < cellProperties.length; i++ )
				{
					Utility.setStructureProperty( structure,
							cellProperties[i],
							Utility.getStructureProperty( originalStructure,
									cellProperties[i] ) );
				}
				originalStructure = null;
			}
		}

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

	}
	
}