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

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

import org.eclipse.birt.core.data.ExpressionUtil;
import org.eclipse.birt.report.designer.data.ui.util.DataSetProvider;
import org.eclipse.birt.report.designer.data.ui.util.IHelpConstants;
import org.eclipse.birt.report.designer.data.ui.util.Utility;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.ReportPlugin;
import org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage;
import org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPageContainer;
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.JoinConditionHandle;
import org.eclipse.birt.report.model.api.JointDataSetHandle;
import org.eclipse.birt.report.model.api.LibraryHandle;
import org.eclipse.birt.report.model.api.ModuleHandle;
import org.eclipse.birt.report.model.api.PropertyHandle;
import org.eclipse.birt.report.model.api.SlotHandle;
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.ReportDesignConstants;
import org.eclipse.birt.report.model.api.elements.structures.DataSetParameter;
import org.eclipse.birt.report.model.api.elements.structures.JoinCondition;
import org.eclipse.birt.report.model.api.util.StringUtil;
import org.eclipse.birt.report.model.elements.JointDataSet;
import org.eclipse.birt.report.model.elements.interfaces.IDataSetModel;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
/**
 * This page is to define joint data set.Select one data set and column from
 * each side to define a join data set
 */

public class JointDataSetPage extends WizardPage
		implements
			ISelectionChangedListener,IPropertyPage
{
	private final static transient String seperator = "::";
	
	private transient ComboViewer leftDataSetChooser = null;
	private transient ComboViewer rightDataSetChooser = null;
	private transient ListViewer leftColumnList = null;
	private transient ListViewer rightColumnList = null;
	private transient DataSetHandle leftHandle = null;
	private transient DataSetHandle rightHandle = null;
	
	private transient Group leftGroup;
	private transient Group centerGroup;
	private transient Group rightGroup;
	
	private transient Button innerJoinButton;
	private transient Button leftOuterJoinButton;
	private transient Button rightOuterJoinButton;
	
	private transient Composite topComposite;
	private transient Composite bottomComposite;
	
	private transient List dataSetList;
    private boolean leftSelected = true;
    private String leftColumnSelection;
    private String rightColumnSelection;
    private String leftDataSetName;
    private String rightDataSetName;
    
    private IPropertyPageContainer propertyPageContainer;
	private Text nameEditor;
	private Label nameLabel;
	final private static String EMPTY_NAME = Messages.getString( "error.emptyName" );//$NON-NLS-1$
	final private static String DUPLICATE_NAME = Messages.getString( "error.duplicateName" );//$NON-NLS-1$
	final private static String CREATE_PROMPT = Messages.getString( "dataset.message.create" );//$NON-NLS-1$

	final private static String TEXT_JOINTYYPE = Messages.getString( "JointDataSetPage.joinType" );//$NON-NLS-1$
	final private static String TEXT_INNORJOIN = Messages.getString( "JointDataSetPage.button.innerJoin" );//$NON-NLS-1$
	final private static String TEXT_LEFTJOIN = Messages.getString( "JointDataSetPage.button.leftJoin" );//$NON-NLS-1$
	final private static String TEXT_RIGHTJOIN = Messages.getString( "JointDataSetPage.button.rightJoin" );//$NON-NLS-1$
	final private static String[] TEXT4JOIN = {
			TEXT_JOINTYYPE, TEXT_INNORJOIN, TEXT_LEFTJOIN, TEXT_RIGHTJOIN
	};
	
	private static String DEFAULT_MESSAGE = Messages.getString( "JointDataSetPage.page.detail" );
	private int leftGroupNumerator = 40;
	private int centerGroupNumerator = 20; 
	
	private String joinType;

	final private static int LEFT_DATASET = 0;
	final private static int RIGHT_DATASET = -1;
	private PropertyHandle propertyHandle ;
  	
  
	/**
	 * Creates a new data set wizard page
	 * 
	 * @param useTransaction
	 *            the style of page
	 */
	public JointDataSetPage( )
	{
		super( "Joint DataSet Page" );//$NON-NLS-1$
		setTitle( Messages.getString( "dataset.new" ) );//$NON-NLS-1$
		setPageMessage( Messages.getString( "JointDataSetPage.page.detail" ), IMessageProvider.NONE ); //$NON-NLS-1$
	}
	
	public JointDataSetPage( String pageName )
	{
		super( pageName );
		setTitle( pageName );//$NON-NLS-1$
		setPageMessage( Messages.getString( "JointDataSetPage.page.detail" ), IMessageProvider.NONE ); //$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
	 */
	public void createControl( Composite parent )
	{
		setControl( this.createPageControl( parent ) );
		setPageComplete( false );
		
		Utility.setSystemHelp( getControl( ),
				IHelpConstants.CONEXT_ID_JOINTDATASET );
	}


	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#createPageControl(org.eclipse.swt.widgets.Composite)
	 */
	public Control createPageControl( Composite parent )
	{
		Composite composite = new Composite( parent, SWT.NONE );
		GridLayout layout = new GridLayout( );
		layout.numColumns = 1;
		composite.setLayout( layout );

		dataSetList = getDataSets( );

		if ( getPageDescription( ) != null )
		{
			Label pageDescription = new Label( composite, SWT.NONE );
			pageDescription.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) );
			pageDescription.setText( getPageDescription( ) );
			pageDescription.setToolTipText( getPageDescription( ) );
		}
        
		topComposite = new Composite( composite, SWT.NONE );
		createTopComposite( topComposite );

		bottomComposite = new Composite( composite, SWT.NONE );
		createBottomComposite( bottomComposite );
		
		joinType = DesignChoiceConstants.JOIN_TYPE_INNER;
		return composite;
	}
	 
	/**
	 * create top composite for page
	 * @param parent
	 */
	private void createTopComposite( Composite parent )
	{
		FormLayout layout = new FormLayout( );
		parent.setLayout( layout );
		
		GridData data = new GridData( GridData.FILL_BOTH );
		parent.setLayoutData( data );
		
		localizeGroupNumerators( );
		
		createLeftGroup( parent );
		createCenterGroup( parent );
		createRightGroup( parent );
	}
	
	/**
	 * To localize group numerators based on the following rules: the initial
	 * percentage for center is set to 20, which makes left and right both to
	 * 40. This percentage will be set to 30 though if any of the given
	 * externalized strings is greater than 20, which obviously makes left and
	 * right both to 35.
	 */
	private void localizeGroupNumerators( )
	{
		centerGroupNumerator += getMaxStringWidth( TEXT4JOIN ) > 20 ? 10 : 0;
		leftGroupNumerator = ( 100 - centerGroupNumerator ) / 2;
	}

	private int getMaxStringWidth( String[] strArray )
	{
		int maxWidth = -1;
		for ( int i = 0; i < strArray.length; i++ )
		{
			int width = strArray[i].length( );
			maxWidth = Math.max( maxWidth, width );
		}

		return maxWidth;
	}

	/**
	 * create left composite for page
	 * @param composite
	 */
	private void createLeftGroup( Composite composite )
	{
		FormData data = new FormData( );

		data.top = new FormAttachment( 0, 5 );
		data.left = new FormAttachment( 0, 5 );
		data.right = new FormAttachment( leftGroupNumerator, -5 );
		data.bottom = new FormAttachment( 100, -5 );

		leftGroup = new Group( composite, SWT.NONE );
		leftGroup.setLayout( new FormLayout( ) );
		leftGroup.setLayoutData( data );

		data = new FormData( );

		data.top = new FormAttachment( 0, 5 );
		data.left = new FormAttachment( 0, 5 );
		data.right = new FormAttachment( 100, -5 );
		data.bottom = new FormAttachment( 10, -5 );
		
		leftDataSetChooser = new ComboViewer( leftGroup, SWT.DROP_DOWN
				| SWT.READ_ONLY );
		leftDataSetChooser.getCombo( ).setLayoutData( data );
		DataSetComboProvider provider = new DataSetComboProvider( );
		leftDataSetChooser.setContentProvider( provider );
		leftDataSetChooser.setLabelProvider( provider );		
		leftDataSetChooser.setInput( dataSetList );
		leftDataSetChooser.addSelectionChangedListener( this );
		
		data = new FormData( );

		data.top = new FormAttachment( leftDataSetChooser.getCombo( ), 10 );
		data.left = new FormAttachment( 0, 5 );
		data.right = new FormAttachment( 100, -5 );
		data.bottom = new FormAttachment( 100, -5 );
		
		leftColumnList = new ListViewer( leftGroup, SWT.V_SCROLL
				| SWT.H_SCROLL | SWT.BORDER );
		leftColumnList.getControl( ).setLayoutData( data );
		ColumnProvider colProvider = new ColumnProvider();
		leftColumnList.setContentProvider( colProvider );
		leftColumnList.setLabelProvider( colProvider );
		leftColumnList.addSelectionChangedListener( this );
		
	}
	
	/**
	 * create center composite for page
	 * @param composite
	 */
	private void createCenterGroup( Composite composite )
	{
		FormData data = new FormData( );
		data.top = new FormAttachment( 0, 100 );
		data.left = new FormAttachment( leftGroup, 5 );
		data.right = new FormAttachment( leftGroupNumerator
				+ centerGroupNumerator, -5 );
	
		centerGroup = new Group( composite, SWT.NONE );
		centerGroup.setLayout( new FormLayout( ) );
		centerGroup.setLayoutData( data );

		centerGroup.setText( TEXT_JOINTYYPE );
		createRadioButtonList( centerGroup );
		
	}
	
	
	/**
	 * create right composite for page
	 * @param composite
	 */
	private void createRightGroup( Composite composite )
	{
		FormData data = new FormData( );
		data.top = new FormAttachment( 0, 5 );
		data.left = new FormAttachment( centerGroup, 5 );
		data.right = new FormAttachment( 100, -5 );
		data.bottom = new FormAttachment( 100, -5 );

		rightGroup = new Group( composite, SWT.NONE );
		rightGroup.setLayout( new FormLayout( ) );
		rightGroup.setLayoutData( data );
		
		data = new FormData( );

		data.top = new FormAttachment( 0, 5 );
		data.left = new FormAttachment( 0, 5 );
		data.right = new FormAttachment( 100, -5 );
		data.bottom = new FormAttachment( 10, -5 );
		rightDataSetChooser = new ComboViewer( rightGroup, SWT.DROP_DOWN
				| SWT.READ_ONLY );
		rightDataSetChooser.getControl( ).setLayoutData( data );
		DataSetComboProvider provider = new DataSetComboProvider( );
		rightDataSetChooser.setContentProvider( provider );
		rightDataSetChooser.setLabelProvider( provider );
		rightDataSetChooser.setInput( dataSetList );
		rightDataSetChooser.addSelectionChangedListener( this );
				
		data = new FormData( );
		data.top = new FormAttachment( rightDataSetChooser.getControl( ), 10 );
		data.left = new FormAttachment( 0, 5 );
		data.right = new FormAttachment( 100, -5 );
		data.bottom = new FormAttachment( 100, -5 );
		rightColumnList = new ListViewer( rightGroup, SWT.V_SCROLL
				| SWT.H_SCROLL | SWT.BORDER );
		rightColumnList.getControl( ).setLayoutData( data );
		ColumnProvider colProvider = new ColumnProvider();
		rightColumnList.setContentProvider( colProvider );
		rightColumnList.setLabelProvider( colProvider );
		rightColumnList.addSelectionChangedListener( this );
	}
	
	/**
	 * create bottom composite for page
	 * @param parent
	 */
	private void createBottomComposite( Composite parent )
	{
		//initialize the dialog layout
		parent.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) );
		GridLayout layout = new GridLayout( );
		layout.numColumns = 2;
		parent.setLayout( layout );

		nameLabel = new Label( parent, SWT.RIGHT );
		nameLabel.setText( Messages.getString( "dataset.wizard.label.datasetName" ) );//$NON-NLS-1$
		nameEditor = new Text( parent, SWT.BORDER );
		String name = ReportPlugin.getDefault( ).getCustomName( ReportDesignConstants.DATA_SET_ELEMENT );
		if(name != null)
		{
			nameEditor.setText( Utility.getUniqueDataSetName( name ) );
		}else // can't get defaut name
		{
			nameEditor.setText( Utility.getUniqueDataSetName( Messages.getString( "dataset.new.defaultName" ) ) );//$NON-NLS-1$			
		}
		
		nameEditor.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) );
		nameEditor.setToolTipText( Messages.getString( "DataSetBasePage.tooltip" ) ); //$NON-NLS-1$
		nameEditor.addModifyListener( new ModifyListener( ) {

			public void modifyText( ModifyEvent e )
			{
				if ( StringUtil.isBlank( nameEditor.getText( ).trim( ) ) )
				{
					setPageMessage( EMPTY_NAME, ERROR );
					setPageComplete( false );
				}
				else if ( isDuplicateName( ) )
				{//name is duplicated
					setPageMessage( DUPLICATE_NAME, ERROR );
					setPageComplete( false );
				}
				else if ( containDotCharactor( nameEditor.getText( ) ) )
				{// name contains invalid "." charactor
					String msg = Messages.getFormattedString( "error.invalidName",
							new Object[]{
							nameEditor.getText( )
							} );
					setMessage( msg, ERROR );
					setPageComplete( false );
				}
				else
				{//everything is OK
					setPageComplete( canPageComplete( ) );
					setPageMessage( CREATE_PROMPT, NONE );
				}
			}
		} );
		
	}
	
	/**
	 * cread radio button list for center composite
	 * @param composite
	 */
	private void createRadioButtonList( Composite composite )
	{

		FormData data = new FormData( );
		data.top = new FormAttachment( composite, 5 );
		data.left = new FormAttachment( composite, 5 );
		data.right = new FormAttachment( 100, -5 );
		innerJoinButton = new Button( composite, SWT.RADIO );
		innerJoinButton.setText( TEXT_INNORJOIN );
		innerJoinButton.setLayoutData( data );
		innerJoinButton.setSelection( true );

		data = new FormData( );
		data.top = new FormAttachment( innerJoinButton, 5 );
		data.left = new FormAttachment( composite, 5 );
		data.right = new FormAttachment( 100, -5 );
		leftOuterJoinButton = new Button( composite, SWT.RADIO );
		leftOuterJoinButton.setText( TEXT_LEFTJOIN );
		leftOuterJoinButton.setLayoutData( data );

		data = new FormData( );
		data.top = new FormAttachment( leftOuterJoinButton, 5 );
		data.left = new FormAttachment( composite, 5 );
		data.right = new FormAttachment( 100, -5 );
		rightOuterJoinButton = new Button( composite, SWT.RADIO );
		rightOuterJoinButton.setText( TEXT_RIGHTJOIN );
		rightOuterJoinButton.setLayoutData( data );
		
		RadioSelectionLister listener = new RadioSelectionLister( );
		innerJoinButton.addSelectionListener( listener );
		leftOuterJoinButton.addSelectionListener( listener );
		rightOuterJoinButton.addSelectionListener( listener );
	}
	

	/**
	 * checks if the name is duplicate
	 * 
	 * @return Returns true if the name is duplicate,and false if it is
	 *         duplicate
	 */
	private boolean isDuplicateName( )
	{
		String name = nameEditor.getText( ).trim( );
		return Utility.checkDataSetName( name );
	}

	/**
	 * whether name contains '.' charactor
	 * @param name
	 * @return
	 */
	private boolean containDotCharactor( String name )
	{
		if ( name == null )
			return false;
		else if ( name.indexOf( "." ) >= 0 )
			return true;
		else
			return false;
	}

	/**
	 * get all data set list including those that should be referenced from
	 * librarys
	 * 
	 * @return the list of data set
	 */
	private List getDataSets( )
	{
		List dataSets = Utility.getVisibleDataSets( );
		List relative = new ArrayList( );

		for ( int i = 0; i < dataSets.size( ); i++ )
		{
			if ( dataSets.get( i ) instanceof JointDataSetHandle )
			{
				List nameList = ( (JointDataSetHandle) dataSets.get( i ) ).getDataSetNames( );
				for ( int j = 0; j < nameList.size( ); j++ )
				{
					DataSetHandle dataSet = Utility.findDataSet( nameList.get( j )
							.toString( ) );

					if ( dataSet.getModuleHandle( ) instanceof LibraryHandle )
						relative.add( dataSet );
				}
			}
		}

		if ( relative.size( ) > 0 )
		{
			dataSets.addAll( relative );
		}

		return dataSets;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
	 */
	public void selectionChanged( SelectionChangedEvent event )
	{
		if ( event.getSource( ) instanceof ComboViewer )
		{
			this.setPageMessage( DEFAULT_MESSAGE, IMessageProvider.NONE );
			if ( ( (ComboViewer) event.getSource( ) ).equals( rightDataSetChooser ) )
				leftSelected = false;
			else
				leftSelected = true;
			DataSetHandle handle = (DataSetHandle) ( (IStructuredSelection) event.getSelection( ) ).getFirstElement( );
			if ( leftSelected )
			{
				leftDataSetName = handle.getQualifiedName( );
				leftHandle = handle;
			}
			else
			{
				rightDataSetName = handle.getQualifiedName( );
				rightHandle = handle;
			}
			DataSetViewData[] columsItems = DataSetProvider.getCurrentInstance( )
					.getColumns( handle, true );
			PopulateColumns( columsItems );

		}
		else if ( event.getSource( ) instanceof ListViewer )
		{
			if ( ( (ListViewer) event.getSource( ) ).equals( rightColumnList ) )
				leftSelected = false;
			else
				leftSelected = true;
			DataSetViewData itemModel = (DataSetViewData) ( (IStructuredSelection) event.getSelection( ) ).getFirstElement( );
			if ( leftSelected )
				leftColumnSelection = itemModel.getName( );
			else
				rightColumnSelection = itemModel.getName( );
		}
		if ( !this.nameEditor.isDisposed( ) )
			setPageComplete( canPageComplete( ) );
	}

	/**
	 * populate columns for the selection changed of comboViewer
	 * @param columsItems
	 */
	private void PopulateColumns( DataSetViewData[] columsItems )
	{
		if ( leftSelected )
		{
			this.leftColumnList.setInput( columsItems );
			if ( columsItems != null
					&& leftColumnList.getElementAt( 0 ) != null )
			{
				this.leftColumnList.setSelection( new StructuredSelection( leftColumnList.getElementAt( 0 ) ) );
				this.leftColumnSelection = ( (DataSetViewData) leftColumnList.getElementAt( 0 ) ).getName( );
			}
		}
		else
		{
			this.rightColumnList.setInput( columsItems );
			if ( columsItems != null
					&& rightColumnList.getElementAt( 0 ) != null )
			{
				this.rightColumnList.setSelection( new StructuredSelection( rightColumnList.getElementAt( 0 ) ) );
				this.rightColumnSelection = ( (DataSetViewData) rightColumnList.getElementAt( 0 ) ).getName( );
			}
		}
	}
	
	/**
	 * create joint datasetHandle
	 * @return
	 */
	public DataSetHandle createSelectedDataSet( )
	{
		try
		{
			DataSetHandle dataSetHandle = createJointDataSet( );
			DesignElementHandle parentHandle = Utility.getReportModuleHandle( );
			//
			SlotHandle slotHandle = ( (ModuleHandle) parentHandle ).getDataSets( );
			parentHandle.addElement( dataSetHandle, slotHandle.getSlotID( ) );

			return dataSetHandle;
		}
		catch ( SemanticException e )
		{
			e.printStackTrace( );
		}

		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * create joint data set
	 * @return
	 * @throws SemanticException
	 */
	private DataSetHandle createJointDataSet( )
			throws SemanticException
	{

		String dataSetName = "";
		if ( nameEditor != null )
			dataSetName = nameEditor.getText( );
		JointDataSetHandle dsHandle = Utility.newJointDataSet( dataSetName );
		if ( leftDataSetName.equals( rightDataSetName ) )
			dsHandle.addDataSet( leftDataSetName );
		else
		{
			dsHandle.addDataSet( leftDataSetName );
			dsHandle.addDataSet( rightDataSetName );
		}
		
		setParameters( dsHandle );
		
        propertyHandle = dsHandle.getPropertyHandle( JointDataSet.JOIN_CONDITONS_PROP );
		propertyHandle.addItem( createJoinCondition( ) );
		return dsHandle;
	}

	/**
	 * Add the parameters of left and right dataset to JointDatasetHandle.
	 * 
	 * @param dsHandle
	 * @throws SemanticException
	 */
	private void setParameters( JointDataSetHandle dsHandle )
			throws SemanticException
	{
		int num = 0;
		if ( leftDataSetName.equals( rightDataSetName ) )
		{
			num = addParameters( dsHandle,
					leftDataSetName + "1",
					leftHandle.getPropertyHandle( IDataSetModel.PARAMETERS_PROP ),
					0 );
			addParameters( dsHandle,
					rightDataSetName + "2",
					rightHandle.getPropertyHandle( IDataSetModel.PARAMETERS_PROP ),
					num );
		}
		else
		{
			num = addParameters( dsHandle,
					leftDataSetName,
					leftHandle.getPropertyHandle( IDataSetModel.PARAMETERS_PROP ),
					0 );
			addParameters( dsHandle,
					rightDataSetName,
					rightHandle.getPropertyHandle( IDataSetModel.PARAMETERS_PROP ),
					num );
		}
	}

	/**
	 * Add the parameters to JointDatasetHandle from a sub dataset.
	 * 
	 * @param dsHandle
	 * @param datasetName
	 * @param parameterHandle
	 * @param startPosition
	 * @return
	 * @throws SemanticException
	 */
	private int addParameters( JointDataSetHandle dsHandle, String dataSetName,
			PropertyHandle parameterHandle, int startPosition )
			throws SemanticException
	{
		int returnValue = 0;
		PropertyHandle dsParameterHandle = dsHandle.getPropertyHandle( IDataSetModel.PARAMETERS_PROP );
		Iterator paramterIterator = parameterHandle.iterator( );
		while ( paramterIterator.hasNext( ) )
		{
			DataSetParameterHandle paramter = (DataSetParameterHandle) ( paramterIterator.next( ) );
//			IStructure parameterStructure = paramter.getStructure( );
			DataSetParameter dataSetParameter = null;
			dataSetParameter = toDataSetParameter( (DataSetParameter) paramter.getStructure( ),
					dataSetName,
					new Integer( startPosition + returnValue ) );
			
//			if ( parameterStructure instanceof OdaDataSetParameter )
//			{
//				dataSetParameter = toDataSetParameter( (OdaDataSetParameter) paramter.getStructure( ),
//						dataSetName,
//						new Integer( startPosition + returnValue ) );
//			}
//			else
//			{
//				dataSetParameter = (DataSetParameter) parameterStructure.copy( );
//				dataSetParameter.setName( getParameterName( dataSetName,
//						dataSetParameter.getName( ) ) );
//			}
			dsParameterHandle.addItem( dataSetParameter );
			returnValue++;
		}
		return returnValue;
	}
	
	/**
	 * 
	 * @param parameter
	 * @return
	 */
	private DataSetParameter toDataSetParameter(
			DataSetParameter parameter, String dataSetName,
			Integer position )
	{
		DataSetParameter dataSetParameter = new DataSetParameter( );
		dataSetParameter.setDataType( parameter.getDataType( ) );
		dataSetParameter.setAllowNull( parameter.allowNull( ) );
		dataSetParameter.setDefaultValue( parameter.getDefaultValue( ) );
		dataSetParameter.setIsInput( parameter.isInput( ) );
		dataSetParameter.setIsOutput( parameter.isOutput( ) );
		dataSetParameter.setName( getParameterName( dataSetName,
				parameter.getName( ) ) );
		dataSetParameter.setIsOptional( parameter.isOptional( ) );
		dataSetParameter.setPosition( position );
		return dataSetParameter;
	}
	
	/**
	 * 
	 * @param dataSetName
	 * @param sourceParameterName
	 * @return
	 */
	public static String getParameterName( String dataSetName, String sourceParameterName )
	{
		return dataSetName + seperator + sourceParameterName;
	}
	
	/**
	 * Create joint condition
	 * @return
	 * @see  org.eclipse.birt.report.model.api.elements.structures.JoinCondition
	 */
	private JoinCondition createJoinCondition( )
	{
		JoinCondition joinCondition = new JoinCondition( );
		joinCondition.setJoinType( joinType );
		// TODO
		joinCondition.setOperator( "eq" );
		joinCondition.setLeftDataSet( leftDataSetName );
		joinCondition.setRightDataSet( rightDataSetName );
		joinCondition.setLeftExpression( ExpressionUtil.createJSDataSetRowExpression( this.leftColumnSelection ) );
		joinCondition.setRightExpression( ExpressionUtil.createJSDataSetRowExpression( this.rightColumnSelection ) );
		return joinCondition;
	}

	private String transformToJSString( String expr )
	{
		if( expr == null )
			return null;
		else
			return expr.replaceAll( "\\\\", "\\\\\\\\" ).replaceAll( "\"", "\\\\\"" ); 
	}
	/**
	 * Whether the page can complete
	 * @return
	 */
	private boolean canPageComplete( )
	{
		if ( leftDataSetName != null
				&& rightDataSetName != null && leftColumnSelection != null
				&& rightColumnSelection != null && !nameEditor.isDisposed( )
				&& !StringUtil.isBlank( nameEditor.getText( ).trim( ) )
				&& !isDuplicateName( ) )
			return true;
		else
			return false;
	}
	
	/**
	 * Provider class for comboViewer to view the list of data sets
	 * 
	 */
	class DataSetComboProvider
			implements
				IStructuredContentProvider,
				ILabelProvider
	{
		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
		 */
		public Object[] getElements( Object inputElement )
		{
			return ( (List) inputElement ).toArray( );
		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
		 */
		public void dispose( )
		{
		}
		
		/*
		 * (non-Javadoc)
		 * @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 )
		{

		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
		 */
		public Image getImage( Object element )
		{
			return null;
		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
		 */
		public String getText( Object element )
		{
			if ( element instanceof DataSetHandle )
			{
				return ( (DataSetHandle) element ).getQualifiedName( );
			}
			return "";
		}

		/*
		 * (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#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 )
		{
		}

	}

	/**
	 * 
	 * Provider class for listViewer to list the column items from data set
	 * 
	 */
	class ColumnProvider implements IStructuredContentProvider, ILabelProvider
	{
		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
		 */
		public Object[] getElements( Object inputElement )
		{
			if ( inputElement instanceof Object[] )
				return (Object[]) inputElement;
			else
				return null;
		}

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

		/*
		 * (non-Javadoc)
		 * @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 )
		{

		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
		 */
		public Image getImage( Object element )
		{
			return null;
		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
		 */
		public String getText( Object element )
		{
			if ( element instanceof DataSetViewData )
			{
				return ( (DataSetViewData) element ).getName( );
			}
			return "";
		}

		/*
		 * (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#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 )
		{
		}

	}

	class RadioSelectionLister implements SelectionListener
	{

		public void widgetSelected( SelectionEvent e )
		{
			if ( e.getSource( ) instanceof Button )
			{
				if ( ( (Button) e.getSource( ) ).equals( innerJoinButton ) )
					joinType = DesignChoiceConstants.JOIN_TYPE_INNER;
				else if ( ( (Button) e.getSource( ) ).equals( leftOuterJoinButton ) )
					joinType = DesignChoiceConstants.JOIN_TYPE_LEFT_OUT;
				else if ( ( (Button) e.getSource( ) ).equals( rightOuterJoinButton ) )
					joinType = DesignChoiceConstants.JOIN_TYPE_RIGHT_OUT;

			}
		}

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



	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#setContainer(org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPageContainer)
	 */
	public void setContainer( IPropertyPageContainer parentContainer )
	{
		propertyPageContainer = parentContainer;

	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#canLeave()
	 */
	public boolean canLeave( )
	{
		try
		{
			return modifyJointCondition( );
		}
		catch ( SemanticException e )
		{
			return false;
		}
	}

	/**
	 * 
	 * @return
	 * @throws SemanticException
	 */
	private boolean modifyJointCondition( ) throws SemanticException
	{
		JointDataSetHandle handle;
		if ( leftDataSetName == null || rightDataSetName == null )
			return false;
		if ( propertyPageContainer instanceof DataSetEditor )
		{
			handle = (JointDataSetHandle) ( (DataSetEditor) propertyPageContainer ).getModel( );
			List datasetName = handle.getDataSetNames( );
			for ( int i = 0; i < datasetName.size( ); i++ )
			{
				try
				{
					handle.removeDataSet( (String) datasetName.get( i ) );
				}
				catch ( SemanticException e )
				{
					// do nothing
				}
			}
			if ( leftDataSetName.equals( rightDataSetName ) )
				handle.addDataSet( leftDataSetName );
			else
			{
				handle.addDataSet( leftDataSetName );
				handle.addDataSet( rightDataSetName );
			}
		}
		if ( propertyHandle != null )
		{
			JoinCondition condition = createJoinCondition( );
			propertyHandle.removeItem( 0 );
			propertyHandle.addItem( condition );
			return true;
		}
		else
			return false;
	}
	
	/**
	 * set page description
	 * @return
	 */
	private String getPageDescription( )
	{
		return Messages.getString( "JointDataSetPage.pageDescription" ); //$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#performOk()
	 */
	public boolean performOk( )
	{
		try
		{
			if ( propertyHandle == null )
				return true;
			return modifyJointCondition( );
		}
		catch ( SemanticException e )
		{
			return false;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#performCancel()
	 */
	public boolean performCancel( )
	{
		return true;
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#pageActivated()
	 */
	public void pageActivated( )
	{
		if ( this.propertyPageContainer != null )
		{
			DEFAULT_MESSAGE = Messages.getString( "JointDataSetPage.pageName" );
			setPageMessage( DEFAULT_MESSAGE, IMessageProvider.NONE );
			JointDataSetHandle handle = (JointDataSetHandle) this.propertyPageContainer.getModel( );
			if ( !nameEditor.isDisposed( ) )
				this.nameEditor.dispose( );
			if ( !nameLabel.isDisposed( ) )
				this.nameLabel.dispose( );
			if ( this.dataSetList != null )
			{
				for ( int i = 0; i < dataSetList.size( ); i++ )
				{
					if ( dataSetList.get( i ) instanceof JointDataSetHandle
							&& ( (JointDataSetHandle) dataSetList.get( i ) ).getDataSetNames( )
									.equals( handle.getDataSetNames( ) ) )
					{
						this.dataSetList.remove( i );
					}
				}
			}
			this.leftDataSetChooser.setInput( this.dataSetList );
			this.rightDataSetChooser.setInput( this.dataSetList );
			propertyHandle = handle.getPropertyHandle( JointDataSet.JOIN_CONDITONS_PROP );
			Iterator conditionIter = handle.joinConditionsIterator( );
			JoinConditionHandle condition;
			while ( conditionIter.hasNext( ) )
			{
				condition = (JoinConditionHandle) conditionIter.next( );
				populateDataSet( condition.getLeftDataSet( ),
						condition.getLeftExpression( ),
						LEFT_DATASET );
				populateDataSet( condition.getRightDataSet( ),
						condition.getRightExpression( ),
						RIGHT_DATASET );
				populateJoinType( condition.getJoinType( ) );
			}

		}
	}
	
	/**
	 * 
	 * @param joinType
	 */
    private void populateJoinType( String joinType )
	{
		this.joinType = joinType;
		if ( joinType.equals( DesignChoiceConstants.JOIN_TYPE_INNER ) )
		{
			innerJoinButton.setSelection( true );
			leftOuterJoinButton.setSelection( false );
			rightOuterJoinButton.setSelection( false );
		}
		else if ( joinType.equals( DesignChoiceConstants.JOIN_TYPE_LEFT_OUT ) )
		{
			innerJoinButton.setSelection( false );
			leftOuterJoinButton.setSelection( true );
			rightOuterJoinButton.setSelection( false );
		}
		else if ( joinType.equals( DesignChoiceConstants.JOIN_TYPE_RIGHT_OUT ) )
		{
			innerJoinButton.setSelection( false );
			leftOuterJoinButton.setSelection( false );
			rightOuterJoinButton.setSelection( true );
		}
	}
	
	/**
	 * 
	 * @param name
	 * @param expression
	 * @param type
	 */
	private void populateDataSet( String name, String expression, int type )
	{
		int selectionIndex = -1;
		for ( int i = 0; i < dataSetList.size( ); i++ )
		{
			DataSetHandle dataHandle = (DataSetHandle) dataSetList.get( i );
			if ( dataHandle.getQualifiedName( ).equals( name ) )
			{
				selectionIndex = i;
				break;
			}
		}

		if ( type == LEFT_DATASET )
		{
			if ( selectionIndex >= 0 )
			{
				leftDataSetChooser.setSelection( new StructuredSelection( dataSetList.get( selectionIndex ) ) );
				if ( leftColumnList.getInput( ) != null
						&& leftColumnList.getInput( ) instanceof DataSetViewData[] )
				{
					DataSetViewData[] dataSetItems = (DataSetViewData[]) leftColumnList.getInput( );
					String rowExpr;
					for ( int i = 0; i < dataSetItems.length; i++ )
					{
						rowExpr = ExpressionUtil.createJSDataSetRowExpression( dataSetItems[i].getName( ) );
						if ( rowExpr.equals( expression ) )
						{
							selectionIndex = i;
							break;
						}
					}
					leftColumnList.setSelection( new StructuredSelection( dataSetItems[selectionIndex] ) );
				}
			}
			else
			{
				setPageMessage( Messages.getString( "JointDataSetPage.error.nodataset.left" ),
						IMessageProvider.ERROR );
			}
		}

		if ( type == RIGHT_DATASET )
		{
			if ( selectionIndex >= 0 )
			{
				rightDataSetChooser.setSelection( new StructuredSelection( dataSetList.get( selectionIndex ) ) );
				if ( rightColumnList.getInput( ) != null
						&& rightColumnList.getInput( ) instanceof DataSetViewData[] )
				{
					DataSetViewData[] dataSetItems = (DataSetViewData[]) rightColumnList.getInput( );
					String rowExpr;
					for ( int i = 0; i < dataSetItems.length; i++ )
					{
						rowExpr = ExpressionUtil.createJSDataSetRowExpression( this.transformToJSString( dataSetItems[i].getName( ) ) );
						if ( rowExpr.equals( expression ) )
						{
							selectionIndex = i;
							break;
						}
					}
					rightColumnList.setSelection( new StructuredSelection( dataSetItems[selectionIndex] ) );
				}
			}
			else
			{
				setPageMessage( Messages.getString( "JointDataSetPage.error.nodataset.right" ),
						IMessageProvider.ERROR );
			}
		}
	}

	/**
	 * 
	 * @param newMessage
	 * @param type
	 */
	private void setPageMessage( String newMessage, int type )
	{
		if(this.propertyPageContainer!= null)
		{
			propertyPageContainer.setMessage( newMessage, type );
		}
		else
		{
			this.setMessage( newMessage, type );
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#getToolTip()
	 */
	public String getToolTip( )
	{
		return Messages.getString( "JointDataSetPage.pageName" );
	}
	
    /*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.dialogs.DialogPage#setVisible(boolean)
	 */
	public void setVisible( boolean visible )
	{
		super.setVisible( visible );
		getControl( ).setFocus( );
	}
}
