/*******************************************************************************
 * 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.HighlightHandleProvider;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.dialogs.HighlightRuleBuilder;
import org.eclipse.birt.report.designer.util.ColorManager;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.CommandStack;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.HighlightRuleHandle;
import org.eclipse.birt.report.model.api.activity.NotificationEvent;
import org.eclipse.birt.report.model.api.elements.DesignChoiceConstants;
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.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.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TableItem;

/**
 * The highlights attribute page for DE element.
 */

public class HighlightsPage extends AttributePage
{

	class HighlightLabelProvider 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 );
		}

	}

	class HighlightContentProvider 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( HighlightsPage.this );
					element.addListener( HighlightsPage.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( HighlightsPage.this );
				}
			}
		}

	}

	private TableViewer fTableViewer;

	private Button fAddButton;

	private Button fDeleteButton;

	private Button fMoveUpButton;

	private Button fMoveDownButton;

	private PreviewLabel previewLabel;

	private HighlightHandleProvider provider = new HighlightHandleProvider( );

	/**
	 * Default constructor.
	 * 
	 * @param parent
	 *            widget parent.
	 * @param style
	 *            crate style.
	 */
	public HighlightsPage( 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 );

		Composite buttons = new Composite( this, SWT.NONE );
		GridData data = new GridData( GridData.FILL_HORIZONTAL );
		// data.heightHint = QUICK_BUTTON_HEIGHT;
		buttons.setLayoutData( data );
		buttons.setLayout( UIUtil.createGridLayoutWithoutMargin( 5, false ) );

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

		fAddButton = new Button( buttons, SWT.BORDER );
		fAddButton.setText( Messages.getString( "HighlightsPage.Button.Add" ) ); //$NON-NLS-1$
		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		data.widthHint = Math.max( fAddButton.computeSize( -1, -1 ).x, 60 );
		// data.heightHint = Math.max( fAddButton.computeSize( -1, -1 ).y,
		// 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( "HighlightsPage.Button.Delete" ) ); //$NON-NLS-1$
		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		data.widthHint = Math.max( fDeleteButton.computeSize( -1, -1 ).x, 60 );
		// data.heightHint = Math.max( fDeleteButton.computeSize( -1, -1 ).y,
		// 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( "HighlightsPage.toolTipText.MoveUp" ) ); //$NON-NLS-1$

		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		// data.heightHint = QUICK_BUTTON_HEIGHT - 2;
		data.widthHint = Math.max( fMoveUpButton.computeSize( -1, -1 ).x, 60 );
		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( "HighlightsPage.toolTipText.MoveDown" ) ); //$NON-NLS-1$

		data = new GridData( GridData.HORIZONTAL_ALIGN_END );
		// data.heightHint = QUICK_BUTTON_HEIGHT - 2;
		data.widthHint = Math.max( fMoveDownButton.computeSize( -1, -1 ).x, 60 );
		fMoveDownButton.setLayoutData( data );
		fMoveDownButton.addSelectionListener( new SelectionAdapter( ) {

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

		new Label( this, SWT.NONE ).setText( Messages.getString( "HighlightsPage.TableColumn.Preview" ) ); //$NON-NLS-1$		

		LayoutTable table = new LayoutTable( this,
				new ColumnsDescription( new String[]{
					Messages.getString( "HighlightsPage.TableColumn.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 HighlightLabelProvider( ) );
		fTableViewer.setContentProvider( new HighlightContentProvider( ) );

		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( ).addListener( SWT.KeyDown, new Listener( ) {

			public void handleEvent( Event event )
			{
				if ( event.keyCode == SWT.DEL )
				{
					delete( );
				}
			}

		} );

		previewLabel = new PreviewLabel( this, SWT.BORDER );
		previewLabel.setText( Messages.getString( "HighlightRuleBuilderDialog.text.PreviewContent" ) ); //$NON-NLS-1$		
		previewLabel.setLayoutData( new GridData( GridData.FILL_BOTH ) );

		updateButtons( );
	}

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

	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 );
	}

	private void refreshTableItemView( )
	{
		for ( int i = 0; i < fTableViewer.getTable( ).getItemCount( ); i++ )
		{
			TableItem ti = fTableViewer.getTable( ).getItem( i );

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

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

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

	private void updatePreview( HighlightRuleHandle hrhandle )
	{
		if ( hrhandle != null )
		{
			String familyValue = getFontFamily( hrhandle );
			int sizeValue = getFontSize( hrhandle );

			previewLabel.setFontFamily( familyValue );
			previewLabel.setFontSize( sizeValue );
			previewLabel.setBold( DesignChoiceConstants.FONT_WEIGHT_BOLD.equals( hrhandle.getFontWeight( ) ) );
			previewLabel.setItalic( DesignChoiceConstants.FONT_STYLE_ITALIC.equals( hrhandle.getFontStyle( ) ) );
			previewLabel.setForeground( ColorManager.getColor( hrhandle.getColor( )
					.getRGB( ) ) );
			previewLabel.setBackground( ColorManager.getColor( hrhandle.getBackgroundColor( )
					.getRGB( ) ) );
			previewLabel.setUnderline( DesignChoiceConstants.TEXT_UNDERLINE_UNDERLINE.equals( hrhandle.getTextUnderline( ) ) );
			previewLabel.setLinethrough( DesignChoiceConstants.TEXT_LINE_THROUGH_LINE_THROUGH.equals( hrhandle.getTextLineThrough( ) ) );

			previewLabel.updateView( );
		}
		else
		{
			previewLabel.restoreDefaultState( );

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

			previewLabel.updateView( );
		}
	}

	private String getFontFamily( HighlightRuleHandle hrhandle )
	{
		String rfm = hrhandle.getFontFamilyHandle( ).getStringValue( );

		if ( rfm == null || rfm.length( ) == 0 )
		{
			if ( provider.getDesignElementHandle( ) != null )
			{
				rfm = provider.getDesignElementHandle( )
						.getPrivateStyle( )
						.getFontFamilyHandle( )
						.getStringValue( );
			}
			else
			{
				rfm = DesignChoiceConstants.FONT_FAMILY_SERIF;
			}
		}

		return HighlightHandleProvider.getFontFamily( rfm );
	}

	private int getFontSize( HighlightRuleHandle hrhandle )
	{
		String rfs = hrhandle.getFontSize( ).getStringValue( );

		if ( ( rfs == null || rfs.length( ) == 0 )
				&& provider.getDesignElementHandle( ) != null )
		{
			rfs = provider.getDesignElementHandle( )
					.getPrivateStyle( )
					.getFontSize( )
					.getStringValue( );
		}

		return DEUtil.getFontSize( rfs );
	}

	private void add( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "HighlightsPage.trans.Add" ) ); //$NON-NLS-1$

			HighlightRuleBuilder builder = new HighlightRuleBuilder( getShell( ),
					Messages.getString( "HighlightsPage.Dialog.NewHighlight" ), //$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 );
		}
	}

	private void edit( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "HighlightsPage.trans.Edit" ) ); //$NON-NLS-1$

			if ( fTableViewer.getTable( ).getSelectionIndex( ) >= 0
					&& fTableViewer.getTable( ).getSelectionIndex( ) < fTableViewer.getTable( )
							.getItemCount( ) )
			{
				HighlightRuleBuilder builder = new HighlightRuleBuilder( getShell( ),
						Messages.getString( "HighlightsPage.Dialog.EditHighlight" ), //$NON-NLS-1$
						provider );

				HighlightRuleHandle handle = (HighlightRuleHandle) 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 );
		}
	}

	private void delete( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "HighlightsPage.trans.Delete" ) ); //$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( );
		}
	}

	private void moveUp( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "HighlightsPage.trans.MoveUp" ) ); //$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( );
		}
	}

	private void moveDown( )
	{
		CommandStack stack = SessionHandleAdapter.getInstance( )
				.getCommandStack( );

		try
		{
			stack.startTrans( Messages.getString( "HighlightsPage.trans.MoveDown" ) ); //$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( );
		}
	}

}