/*******************************************************************************
 * 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.internal.ui.views.attributes.page;

import java.util.List;

import org.eclipse.birt.report.designer.core.model.SessionHandleAdapter;
import org.eclipse.birt.report.designer.internal.ui.dialogs.PreviewLabel;
import org.eclipse.birt.report.designer.internal.ui.swt.custom.LayoutTable;
import org.eclipse.birt.report.designer.internal.ui.swt.custom.LayoutTable.ColumnsDescription;
import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.internal.ui.util.UIUtil;
import org.eclipse.birt.report.designer.internal.ui.views.attributes.provider.MapHandleProvider;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.dialogs.MapRuleBuilder;
import org.eclipse.birt.report.designer.util.ColorManager;
import org.eclipse.birt.report.model.api.CommandStack;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.MapRuleHandle;
import org.eclipse.birt.report.model.api.activity.NotificationEvent;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
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.Label;
import org.eclipse.swt.widgets.TableItem;

/**
 * Map page.
 */

public class MapPage extends AttributePage
{

	private TableViewer fTableViewer;

	private Button fAddButton;

	private Button fDeleteButton;

	private Button fMoveUpButton;

	private Button fMoveDownButton;

	private PreviewLabel previewLabel;

	private MapHandleProvider provider = new MapHandleProvider( );

	/**
	 * MapLabelProvider, used by tableViewer to get image and column Text for
	 * table.
	 */
	class MapLabelProvider extends LabelProvider implements ITableLabelProvider
	{

		public Image getColumnImage( Object element, int columnIndex )
		{
			return null;
		}

		public String getColumnText( Object element, int columnIndex )
		{
			return provider.getColumnText( element, 1 );
		}

	}

	/**
	 * 
	 * MapContentProvider, used by tableViewer to get elements for table
	 */
	class MapContentProvider implements IStructuredContentProvider
	{

		public Object[] getElements( Object inputElement )
		{
			Object[] elements = provider.getElements( inputElement );

			for ( int i = 0; i < elements.length; i++ )
			{
				if ( elements[i] instanceof DesignElementHandle )
				{
					DesignElementHandle element = (DesignElementHandle) elements[i];
					element.removeListener( MapPage.this );
					element.addListener( MapPage.this );
				}
			}

			return elements;
		}

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

		public void dispose( )
		{
			Object[] elements = provider.getElements( input );

			for ( int i = 0; i < elements.length; i++ )
			{
				if ( elements[i] instanceof DesignElementHandle )
				{
					DesignElementHandle element = (DesignElementHandle) elements[i];
					element.removeListener( MapPage.this );
				}
			}
		}

	}

	/**
	 * @param parent
	 * @param style
	 */
	public MapPage( Composite parent, int style )
	{
		super( parent, style );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.internal.ui.views.attributes.page.AttributePage#buildUI()
	 */
	protected void buildUI( )
	{

		GridLayout layout = UIUtil.createGridLayoutWithoutMargin( 2, false );
		layout.horizontalSpacing = 10;
		setLayout( layout );

		// final Composite content = new Composite( parent, SWT.NONE );
		// layout = new GridLayout( );
		// layout.marginHeight = 0;
		// layout.marginWidth = 0;
		// content.setLayout( layout );
		// content.setLayoutData( new GridData( GridData.FILL_BOTH ) );

		Composite buttons = new Composite( this, SWT.NONE );
		GridData data = new GridData( GridData.FILL_HORIZONTAL );
		// data.heightHint = QUICK_BUTTON_HEIGHT;
		buttons.setLayoutData( data );
		layout = new GridLayout( );
		layout.numColumns = 5;
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		buttons.setLayout( layout );

		Label lb = new Label( buttons, SWT.NONE );
		lb.setText( Messages.getString( "MapPage.label.mapList" ) ); //$NON-NLS-1$
		lb.setLayoutData( new GridData( GridData.HORIZONTAL_ALIGN_BEGINNING
				| GridData.FILL_HORIZONTAL ) );

		fAddButton = new Button( buttons, SWT.BORDER );
		fAddButton.setText( Messages.getString( "MapPage.label.add" ) ); //$NON-NLS-1$
		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		data.widthHint = Math.max( 60, fAddButton.computeSize( SWT.DEFAULT,
				SWT.DEFAULT,
				true ).x );
		// data.heightHint = QUICK_BUTTON_HEIGHT - 2;
		fAddButton.setLayoutData( data );
		fAddButton.addSelectionListener( new SelectionAdapter( ) {

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

		fDeleteButton = new Button( buttons, SWT.BORDER );
		fDeleteButton.setText( Messages.getString( "MapPage.label.delete" ) ); //$NON-NLS-1$
		data = new GridData( GridData.HORIZONTAL_ALIGN_END );

		data.widthHint = Math.max( 60, fDeleteButton.computeSize( SWT.DEFAULT,
				SWT.DEFAULT,
				true ).x );
		// data.heightHint = QUICK_BUTTON_HEIGHT - 2;
		fDeleteButton.setLayoutData( data );
		fDeleteButton.addSelectionListener( new SelectionAdapter( ) {

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

		fMoveUpButton = new Button( buttons, SWT.BORDER );
		fMoveUpButton.setText( Messages.getString( "FormPage.Button.Up" ) ); //$NON-NLS-1$
		fMoveUpButton.setToolTipText( Messages.getString( "MapPage.toolTipText.moveUp" ) ); //$NON-NLS-1$
		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		data.widthHint = Math.max( 60, fMoveUpButton.computeSize( SWT.DEFAULT,
				SWT.DEFAULT,
				true ).x );
		// data.heightHint = QUICK_BUTTON_HEIGHT - 2;
		fMoveUpButton.setLayoutData( data );
		fMoveUpButton.addSelectionListener( new SelectionAdapter( ) {

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

		fMoveDownButton = new Button( buttons, SWT.BORDER );
		fMoveDownButton.setText( Messages.getString( "FormPage.Button.Down" ) ); //$NON-NLS-1$
		fMoveDownButton.setToolTipText( Messages.getString( "MapPage.toolTipText.moveDown" ) ); //$NON-NLS-1$
		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		data.widthHint = Math.max( 60, fMoveDownButton.computeSize( SWT.DEFAULT,
				SWT.DEFAULT,
				true ).x );
		// data.heightHint = QUICK_BUTTON_HEIGHT - 2;
		fMoveDownButton.setLayoutData( data );
		fMoveDownButton.addSelectionListener( new SelectionAdapter( ) {

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

		new Label( this, SWT.NONE ).setText( Messages.getString( "MapPage.label.displayValue" ) ); //$NON-NLS-1$

		LayoutTable table = new LayoutTable( this,
				new ColumnsDescription( new String[]{
					Messages.getString( "MapPage.label.condition" ) //$NON-NLS-1$
				},
						true ),
				SWT.BORDER | SWT.FULL_SELECTION );

		table.setLayoutData( new GridData( GridData.FILL_BOTH ) );

		fTableViewer = new TableViewer( table.getTable( ) );
		fTableViewer.setLabelProvider( new MapLabelProvider( ) );
		fTableViewer.setContentProvider( new MapContentProvider( ) );
		fTableViewer.setSorter( null );

		fTableViewer.addSelectionChangedListener( new ISelectionChangedListener( ) {

			public void selectionChanged( SelectionChangedEvent event )
			{
				updateButtons( );
				refreshTableItemView( );
			}
		} );

		fTableViewer.addDoubleClickListener( new IDoubleClickListener( ) {

			public void doubleClick( DoubleClickEvent event )
			{
				edit( );
			}
		} );

		fTableViewer.getTable( ).addKeyListener( new KeyAdapter( ) {

			public void keyPressed( KeyEvent e )
			{
				if ( e.keyCode == SWT.DEL )
				{
					delete( );
				}
			}

		} );

		previewLabel = new PreviewLabel( this, SWT.BORDER );
		previewLabel.setText( "" ); //$NON-NLS-1$		
		previewLabel.setLayoutData( new GridData( GridData.FILL_BOTH ) );
		
		updateButtons( );
		
	}

	/**
	 * Refreshes the enablement of all controls with this page.
	 * 
	 * @param enabled
	 */
	private void enableUI( boolean enabled )
	{
		if ( fTableViewer != null )
		{
			fAddButton.setEnabled( enabled );
			fDeleteButton.setEnabled( enabled );
			fMoveUpButton.setEnabled( enabled );
			fMoveDownButton.setEnabled( enabled );
			fTableViewer.getTable( ).setEnabled( enabled );

			if ( enabled )
			{
				updateButtons( );
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.internal.ui.views.attributes.page.AttributePage#setInput(java.util.List)
	 */
	public void setInput( List elements )
	{
		if ( elements.size( ) != 1 )
		{
			enableUI( false );
			return;
		}

		enableUI( true );
		super.setInput( elements );

		fTableViewer.setInput( elements );

		refreshTableItemView( );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.internal.ui.views.attributes.page.AttributePage#elementChanged(org.eclipse.birt.model.api.DesignElementHandle,
	 *      org.eclipse.birt.model.activity.NotificationEvent)
	 */
	public void elementChanged( DesignElementHandle focus, NotificationEvent ev )
	{
		if ( fTableViewer.getContentProvider( ) == null )
		{
			return;
		}
		if ( fTableViewer != null )
		{
			fTableViewer.setInput( input );
			refreshTableItemView( );
		}
	}

	/**
	 * Updates the enablements of buttons.
	 * 
	 */
	private void updateButtons( )
	{
		fDeleteButton.setEnabled( fTableViewer.getTable( ).getSelectionIndex( ) >= 0
				&& fTableViewer.getTable( ).getSelectionIndex( ) < fTableViewer.getTable( )
						.getItemCount( ) );

		fMoveUpButton.setEnabled( fTableViewer.getTable( ).getSelectionIndex( ) > 0
				&& fTableViewer.getTable( ).getSelectionIndex( ) < fTableViewer.getTable( )
						.getItemCount( ) );

		fMoveDownButton.setEnabled( fTableViewer.getTable( )
				.getSelectionIndex( ) >= 0
				&& fTableViewer.getTable( ).getSelectionIndex( ) < fTableViewer.getTable( )
						.getItemCount( ) - 1 );
	}

	/**
	 * Refreshes table item views.
	 * 
	 */
	private void refreshTableItemView( )
	{
		for ( int i = 0; i < fTableViewer.getTable( ).getItemCount( ); i++ )
		{
			TableItem ti = fTableViewer.getTable( ).getItem( i );

			MapRuleHandle handle = (MapRuleHandle) ti.getData( );

			ti.setText( 0, provider.getColumnText( handle, 1 ) );
		}

		if ( fTableViewer.getTable( ).getSelectionIndex( ) >= 0 )
		{
			updatePreview( (MapRuleHandle) fTableViewer.getTable( )
					.getItem( fTableViewer.getTable( ).getSelectionIndex( ) )
					.getData( ) );
		}
		else
		{
			updatePreview( null );
		}
	}

	/**
	 * Updates preview part according to selection or change.
	 * 
	 * @param mrhandle
	 */
	private void updatePreview( MapRuleHandle mrhandle )
	{
		if ( mrhandle != null )
		{
			previewLabel.setText( mrhandle.getDisplay( ) );
			previewLabel.updateView( );
		}
		else
		{
			previewLabel.restoreDefaultState( );

			previewLabel.setForeground( ColorManager.getColor( -1 ) );
			previewLabel.setBackground( ColorManager.getColor( -1 ) );

			previewLabel.setText( "" ); //$NON-NLS-1$
			previewLabel.updateView( );
		}
	}

	/**
	 * Adds a map.
	 */
	private void add( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "MapPage.transName.addMapRule" ) ); //$NON-NLS-1$

			MapRuleBuilder builder = new MapRuleBuilder( getShell( ),
					MapRuleBuilder.DLG_TITLE_NEW, //$NON-NLS-1$
					provider );

			builder.updateHandle( null, fTableViewer.getTable( ).getItemCount( ) );

			builder.setDesignHandle( provider.getDesignElementHandle( ) );

			if ( builder.open( ) == Window.OK )
			{
				int itemCount = fTableViewer.getTable( ).getItemCount( );

				fTableViewer.getTable( ).deselectAll( );

				fTableViewer.getTable( ).select( itemCount - 1 );

				fTableViewer.getTable( ).setFocus( );

				updateButtons( );
				refreshTableItemView( );
			}

			stack.commit( );
		}
		catch ( Exception e )
		{
			stack.rollback( );
			ExceptionHandler.handle( e );
		}
	}

	/**
	 * Edits a map.
	 * 
	 */
	private void edit( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "MapPage.transName.editMapRule" ) ); //$NON-NLS-1$

			if ( fTableViewer.getTable( ).getSelectionIndex( ) >= 0
					&& fTableViewer.getTable( ).getSelectionIndex( ) < fTableViewer.getTable( )
							.getItemCount( ) )
			{
				MapRuleBuilder builder = new MapRuleBuilder( getShell( ),
						MapRuleBuilder.DLG_TITLE_EDIT, //$NON-NLS-1$
						provider );

				MapRuleHandle handle = (MapRuleHandle) fTableViewer.getTable( )
						.getItem( fTableViewer.getTable( ).getSelectionIndex( ) )
						.getData( );

				builder.updateHandle( handle, fTableViewer.getTable( )
						.getItemCount( ) );

				builder.setDesignHandle( provider.getDesignElementHandle( ) );

				int idx = fTableViewer.getTable( ).getSelectionIndex( );

				if ( builder.open( ) == Window.OK )
				{
					fTableViewer.getTable( ).select( idx );

					fTableViewer.getTable( ).setFocus( );

					updateButtons( );
					refreshTableItemView( );
				}
			}

			stack.commit( );
		}
		catch ( Exception e )
		{
			stack.rollback( );
			ExceptionHandler.handle( e );
		}
	}

	/**
	 * Deletes a map.
	 * 
	 */
	private void delete( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "MapPage.transName.deleteMapRule" ) ); //$NON-NLS-1$

			if ( fTableViewer.getTable( ).getSelectionIndex( ) >= 0
					&& fTableViewer.getTable( ).getSelectionIndex( ) < fTableViewer.getTable( )
							.getItemCount( ) )
			{
				int idx = fTableViewer.getTable( ).getSelectionIndex( );

				provider.doDeleteItem( idx );

				if ( idx >= fTableViewer.getTable( ).getItemCount( ) )
				{
					idx--;
				}

				fTableViewer.getTable( ).select( idx );

				fTableViewer.getTable( ).setFocus( );

				updateButtons( );
				refreshTableItemView( );
			}

			stack.commit( );
		}
		catch ( Exception e )
		{
			stack.rollback( );
			ExceptionHandler.handle( e );
		}
		finally
		{
			updateButtons( );
			refreshTableItemView( );
		}
	}

	/**
	 * Moves up a map.
	 * 
	 */
	private void moveUp( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "MapPage.transName.moveUpMapRule" ) ); //$NON-NLS-1$

			int index = fTableViewer.getTable( ).getSelectionIndex( );

			provider.doSwapItem( index, -1 );

			fTableViewer.getTable( ).select( index - 1 );

			fTableViewer.getTable( ).setFocus( );

			stack.commit( );
		}
		catch ( Exception e )
		{
			stack.rollback( );
			ExceptionHandler.handle( e );
		}
		finally
		{
			updateButtons( );
			refreshTableItemView( );
		}
	}

	/**
	 * Moves down a map.
	 * 
	 */
	private void moveDown( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "MapPage.transName.moveDownRule" ) ); //$NON-NLS-1$

			int index = fTableViewer.getTable( ).getSelectionIndex( );

			provider.doSwapItem( index, 1 );

			fTableViewer.getTable( ).select( index + 1 );

			fTableViewer.getTable( ).setFocus( );

			stack.commit( );
		}
		catch ( Exception e )
		{
			stack.rollback( );
			ExceptionHandler.handle( e );
		}
		finally
		{
			updateButtons( );
			refreshTableItemView( );
		}
	}
}