/*******************************************************************************
 * 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.datasource;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

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.core.runtime.Path;
import org.eclipse.datatools.connectivity.oda.OdaException;
import org.eclipse.datatools.connectivity.oda.design.ui.designsession.DataSourceDesignSession;
import org.eclipse.datatools.connectivity.oda.design.ui.designsession.DesignSessionUtil;
import org.eclipse.datatools.connectivity.oda.util.manifest.ManifestExplorer;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

/**
 * 
 */

public class ConnectionProfileSelectionPage extends WizardPage
{

	private transient Label dataSourceNameLabel = null;
	private transient Text connectionProfilePath = null;
	private transient Text dataSourceName = null;
	private transient String profileID = "";
	private transient String odaDataSourceID = "";
	private transient Button useDefaultDSNameCheckBox = null;
	private transient Tree odaDataSourceTree = null;
	private transient Properties dataSourceIDProperties = null;
	private transient Properties cpProperties = null;
	private transient DataSourceDesignSession m_designSession = null;
	private final String DUPLICATE_NAME = Messages.getString( "error.duplicateName" );//$NON-NLS-1$
	private final String EMPTY_NAME = Messages.getString( "error.emptyName" );//$NON-NLS-1$
	private final String DATASOURCE_NAME = Messages.getString( "connectionprofile.wizard.tree.datasourcename" );

	/**
	 * @param pageName
	 */
	public ConnectionProfileSelectionPage( String pageName )
	{
		super( pageName );

		setTitle( Messages.getString( "connectionprofile.wizard.title.connectionprofileselect" ) );//$NON-NLS-1$
		setMessage( Messages.getString( "connectionprofile.wizard.defaultmessage.connectionprofileselect" ) );//$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
	 */
	public void createControl( Composite parent )
	{
		Composite composite = new Composite( parent, SWT.NONE );
		GridLayout layout = new GridLayout( );
		layout.numColumns = 3;
		composite.setLayout( layout );

		setupConnectionProfilePath( composite );
		setupTreeViewer( composite );
		setupDataSourceName( composite );

		setPageComplete( hasConnectionProfilePath( ) );
		setControl( composite );
		
		Utility.setSystemHelp( getControl( ),
				IHelpConstants.CONEXT_ID_CONNECTIONPROFILE );
	}

	/**
	 * Setup ConnectionProfilePath layout
	 * 
	 * @param composite
	 */
	private void setupConnectionProfilePath( Composite composite )
	{
		Label label = new Label( composite, SWT.NONE );
		label.setText( Messages.getString( "connectionprofile.wizard.label.connectionprofilestore" ) );//$NON-NLS-1$
		label.setLayoutData( new GridData( GridData.HORIZONTAL_ALIGN_BEGINNING ) );

		connectionProfilePath = new Text( composite, SWT.BORDER );
		GridData layoutData = new GridData( GridData.FILL_HORIZONTAL );
		layoutData.widthHint = 260;
		connectionProfilePath.setLayoutData( layoutData );
		connectionProfilePath.addModifyListener( new ModifyListener( ) {

			/*
			 * (non-Javadoc)
			 * 
			 * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
			 */
			public void modifyText( ModifyEvent e )
			{
				BusyIndicator.showWhile( getShell( ) == null ? null
						: getShell( ).getDisplay( ), new Runnable( ) {

					public void run( )
					{
						populateTree( );
					}
				} );
			}

		} );

		Button button = new Button( composite, SWT.PUSH );
		button.setText( Messages.getString( "connectionprofile.wizard.button.browse" ) );//$NON-NLS-1$
		button.addSelectionListener( new SelectionAdapter( ) {

			/*
			 * (non-Javadoc)
			 * 
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
			 */
			public void widgetSelected( SelectionEvent e )
			{
				connectionProfilePath.setText( new FileDialog( getShell( ) ).open( ) );
			}
		} );
		button.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) );
	}

	/**
	 * Setup TreeViewer layout
	 * 
	 * @param composite
	 */
	private void setupTreeViewer( Composite composite )
	{
		odaDataSourceTree = new Tree( composite, SWT.BORDER
				| SWT.SINGLE | SWT.V_SCROLL );
		odaDataSourceTree.setLayout( new GridLayout( ) );
		GridData layoutData = new GridData( GridData.FILL_BOTH );
		layoutData.horizontalSpan = 3;
		odaDataSourceTree.setLayoutData( layoutData );

		odaDataSourceTree.addSelectionListener( new SelectionAdapter( ) {

			/*
			 * (non-Javadoc)
			 * 
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
			 */
			public void widgetSelected( SelectionEvent event )
			{
				handleTreeSelection( );
			}

			private void handleTreeSelection( )
			{
				TreeItem item = odaDataSourceTree.getSelection( )[0];

				// refinable move
				if ( item.getParentItem( ) == null
						|| dataSourceIDProperties.containsKey( item.getData( ) ) )
				{
					dataSourceName.setText( "" );
				}
				else
				{
					profileID = item.getData( ).toString( );
					odaDataSourceID = item.getParentItem( )
							.getData( )
							.toString( );
					dataSourceName.setText( item.getText( ) );

				}
			}
		} );

		populateTree( );
	}

	/**
	 * Populate the connection profile instances in the tree viewer
	 * 
	 */
	private void populateTree( )
	{
		if ( connectionProfilePath.getText( ).trim( ).length( ) == 0 )
			return;

		resetTreeViewer( );
		generateDataSourceIdentifiers( );

		TreeItem root = new TreeItem( odaDataSourceTree, SWT.NONE );
		root.setText( DATASOURCE_NAME );

		try
		{
			Iterator iterator = dataSourceIDProperties.keySet( ).iterator( );
			while ( iterator.hasNext( ) )
			{
				Object odaDataSourceId = iterator.next( );
				if ( !hasCPInstance( odaDataSourceId ) )
					continue;

				TreeItem dsCategory = new TreeItem( root, SWT.NONE );
				String dsID = odaDataSourceId.toString( );
				String dsDisplayName = dataSourceIDProperties.getProperty( dsID );
				dsCategory.setData( dsID );
				dsCategory.setText( dsDisplayName );

				createDSTreeItems( dsCategory );
				odaDataSourceTree.showItem( dsCategory );
			}
		}
		catch ( OdaException e )
		{
			// TODO Auto-generated catch block
			e.printStackTrace( );
		}

	}

	/**
	 * Reset TreeViwewer layout
	 * 
	 */
	private void resetTreeViewer( )
	{
		dataSourceName.setText( "" );
		odaDataSourceTree.removeAll( );
	}

	/**
	 * To Collect DataSourceIdentifiers from DTP
	 * 
	 */
	private void generateDataSourceIdentifiers( )
	{
		if ( dataSourceIDProperties == null )
			dataSourceIDProperties = ManifestExplorer.getInstance( )
					.getDataSourceIdentifiers( );
	}

	/**
	 * Test if there exists a connection profile instance
	 * 
	 * @param odaDataSourceId
	 * @return
	 * @throws OdaException
	 */
	private boolean hasCPInstance( Object odaDataSourceId ) throws OdaException
	{
		Map profiles = getProfileIdentifiers( odaDataSourceId.toString( ) );

		// for NPE
		if ( profiles == null )
			return false;

		return profiles.keySet( ).iterator( ).hasNext( );

	}

	/**
	 * 
	 * @param odaDataSourceId
	 * @return
	 */
	private Map getProfileIdentifiers( String odaDataSourceId )
	{
		try
		{
			return DesignSessionUtil.getProfileIdentifiers( odaDataSourceId,
					new Path( connectionProfilePath.getText( ) ).toFile( ) );
		}
		catch ( OdaException e )
		{
			// TODO Auto-generated catch block
			e.printStackTrace( );
		}

		return null;
	}

	/**
	 * Create tree items for each data source category
	 * 
	 * @param dsCategory
	 * @throws OdaException
	 */
	private void createDSTreeItems( TreeItem dsCategory ) throws OdaException
	{
		Map profiles = getProfileIdentifiers( dsCategory.getData( ).toString( ) );

		ArrayList treeList = new ArrayList( );
		Iterator iterator = profiles.keySet( ).iterator( );
		while ( iterator.hasNext( ) )
		{
			treeList.add( iterator.next( ) );
		}

		createTreeItems( profiles, dsCategory, treeList, SWT.NONE );
	}

	/**
	 * 
	 * @param profiles
	 * @param dsCategory
	 * @param dataSource
	 * @param style
	 * @return
	 */
	private TreeItem[] createTreeItems( Map profiles, TreeItem dsCategory,
			ArrayList dataSource, int style )
	{
		if ( dataSource == null )
			return null;

		TreeItem item[] = new TreeItem[dataSource.size( )];
		for ( int i = 0; i < dataSource.size( ); i++ )
		{
			item[i] = new TreeItem( dsCategory, style );
			Object source = dataSource.get( i );
			item[i].setData( source );
			item[i].setText( profiles.get( source ).toString( ) );
		}

		return item;
	}

	/**
	 * Setup DataSourceName layout
	 * 
	 * @param composite
	 */
	private void setupDataSourceName( Composite composite )
	{
		GridData layoutData = new GridData( GridData.FILL_HORIZONTAL );
		layoutData.horizontalSpan = 3;
		useDefaultDSNameCheckBox = new Button( composite, SWT.CHECK );
		useDefaultDSNameCheckBox.setText( Messages.getString( "connectionprofile.wizard.checkbox.datasourcenameusedefaultdsname" ) ); //$NON-NLS-1$
		useDefaultDSNameCheckBox.setSelection( true );
		useDefaultDSNameCheckBox.setLayoutData( layoutData );
		useDefaultDSNameCheckBox.addSelectionListener( new SelectionAdapter( ) {

			/*
			 * (non-Javadoc)
			 * 
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
			 */
			public void widgetSelected( SelectionEvent e )
			{
				enableDataSourceNameEditor( !useDefaultDSNameCheckBox.getSelection( ) );
			}

		} );

		dataSourceNameLabel = new Label( composite, SWT.NONE );
		dataSourceNameLabel.setText( Messages.getString( "connectionprofile.wizard.label.datasourcename" ) ); //$NON-NLS-1$
		dataSourceNameLabel.setLayoutData( new GridData( GridData.HORIZONTAL_ALIGN_BEGINNING ) );

		layoutData = new GridData( GridData.FILL_HORIZONTAL );
		layoutData.horizontalSpan = 2;
		dataSourceName = new Text( composite, SWT.BORDER );
		dataSourceName.setLayoutData( layoutData );
		dataSourceName.addModifyListener( new ModifyListener( ) {

			public void modifyText( ModifyEvent e )
			{
				if ( isNameBlank( ) )
				{
					setMessage( EMPTY_NAME, ERROR );
					setPageComplete( false );
				}
				else if ( isNameDuplicated( ) )
				{
					setMessage( DUPLICATE_NAME, ERROR );
					setPageComplete( false );
				}
				else
				{
					setMessage( Messages.getString( "connectionprofile.wizard.defaultmessage.connectionprofileselect" ) ); //$NON-NLS-1$
					setPageComplete( true );
					setCPProperties( );
				}

				canFlipToNextPage( );
				getWizard( ).getContainer( ).updateButtons( );

			}
		} );

		enableDataSourceNameEditor( false );

	}

	/**
	 * Test if the data source name is blank
	 * 
	 * @return
	 */
	private boolean isNameBlank( )
	{
		return dataSourceName.getText( ).trim( ).equals( "" );
	}

	/**
	 * Test if the data source name is duplicated
	 * 
	 * @return
	 */
	private boolean isNameDuplicated( )
	{
		String name = dataSourceName.getText( ).trim( );
		return Utility.checkDataSourceName( name );
	}

	/**
	 * Enable DataSourceNameEditor
	 * 
	 * @param bool
	 */
	private void enableDataSourceNameEditor( boolean bool )
	{
		dataSourceNameLabel.setEnabled( bool );
		dataSourceName.setEnabled( bool );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.wizard.IWizardPage#canFlipToNextPage()
	 */
	public boolean canFlipToNextPage( )
	{
		return ( getMessageType( ) != ERROR && hasConnectionProfilePath( ) );
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.wizard.WizardPage#getNextPage()
	 */
	public IWizardPage getNextPage( )
	{
		try
		{
			startNewDesignSession( );
			return m_designSession.getWizardStartingPage( );
		}
		catch ( OdaException e )
		{
			// TODO Auto-generated catch block
			e.printStackTrace( );
		}

		return super.getNextPage( );
	}

	/**
	 * Start a new design session,happens before bringing users to the custom
	 * page
	 * 
	 * @throws OdaException
	 */
	private void startNewDesignSession( ) throws OdaException
	{
		boolean linkToProfile = false;

		DataSourceDesignSession.ProfileReference profileRef = new DataSourceDesignSession.ProfileReference( profileID,
				new Path( connectionProfilePath.getText( ) ).toFile( ),
				linkToProfile );

		if ( m_designSession == null )
			m_designSession = DataSourceDesignSession.startNewDesign( odaDataSourceID,
					dataSourceName.getText( ),
					profileRef,
					null );
		else
			// preserve user edits on custom wizard page, if appropriate
			m_designSession.restartNewDesign( odaDataSourceID,
					dataSourceName.getText( ),
					profileRef,
					null );
	}

	/**
	 * Set CPProperties
	 * 
	 */
	private void setCPProperties( )
	{
		cpProperties = new Properties( );

		String[] cpPropertyKey = {
				ConnectionProfileWizard.DATA_SOURCE_ID,
				ConnectionProfileWizard.DATA_SOURCE_NAME,
				ConnectionProfileWizard.PROFILE_INSTANCE_ID,
				ConnectionProfileWizard.STOREAGE_FILE_PATH
		};

		String[] cpPropertyValue = {
				odaDataSourceID,
				dataSourceName.getText( ),
				profileID,
				connectionProfilePath.getText( )
		};

		for ( int i = 0; i < cpPropertyKey.length; i++ )
		{
			cpProperties.put( cpPropertyKey[i], cpPropertyValue[i] );
		}
	}

	/**
	 * 
	 * @return
	 */
	private boolean hasConnectionProfilePath( )
	{
		return connectionProfilePath.getText( ).trim( ).length( ) > 0;
	}

	/**
	 * 
	 * @return
	 */
	public Properties getCPProperties( )
	{
		return cpProperties;
	}

	/**
	 * 
	 * @return
	 */
	public DataSourceDesignSession getDataSourceDesignSession( )
	{
		return m_designSession;
	}
	
    /*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.dialogs.DialogPage#setVisible(boolean)
	 */
	public void setVisible( boolean visible )
	{
		super.setVisible( visible );
		getControl( ).setFocus( );
	}
}
