/*******************************************************************************
 * Copyright (c) 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.internal.ui.views.attributes.widget;

import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.internal.ui.views.attributes.page.WidgetUtil;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.views.attributes.providers.ChoiceSetFactory;
import org.eclipse.birt.report.designer.ui.views.attributes.providers.PropertyProcessor;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.metadata.IChoice;
import org.eclipse.birt.report.model.api.metadata.IChoiceSet;
import org.eclipse.birt.report.model.api.metadata.PropertyValueException;
import org.eclipse.birt.report.model.api.util.StringUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
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.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

/**
 * PropertyDescriptor manages combo & combo choice control.
 */
public class MarignPropertyDescriptor extends AbstractPropertyDescriptor
{

	private static final String ERROR_MESSAGE = Messages.getString( "MarignPropertyDescriptor.error.message" ); //$NON-NLS-1$

	private static final String ERROR_BOX_TITLE = Messages.getString( "MarignPropertyDescriptor.error.title" ); //$NON-NLS-1$

	protected Combo valueCombo, unitCombo;

	protected Composite container;

	protected IChoiceSet unitChoiceSet, valueChoiceSet;

	private String deMesurementValue, deUnitValue;

	private boolean hasError = false;

	/**
	 * @param propertyHandle
	 *            the property handle
	 */
	public MarignPropertyDescriptor( PropertyProcessor propertyProcessor )
	{
		super( propertyProcessor );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.extensions.IPropertyDescriptor#createControl(org.eclipse.swt.widgets.Composite)
	 */
	public Control createControl( Composite parent )
	{
		container = new Composite( parent, SWT.NONE );
		GridLayout layout = new GridLayout( 2, false );
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 0;
		container.setLayout( layout );

		SelectionListener listener = new SelectionListener( ) {

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

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

		valueCombo = new Combo( container, SWT.BORDER );
		valueCombo.addSelectionListener( listener );
		valueCombo.addModifyListener( new ModifyListener( ) {

			public void modifyText( ModifyEvent e )
			{
				unitCombo.setEnabled( valueCombo.indexOf( valueCombo.getText( ) ) == -1 );
				if ( unitCombo.isEnabled( )
						&& unitCombo.getItemCount( ) > 0
						&& ( unitCombo.getText( ) == null || unitCombo.getText( )
								.length( ) == 0 ) )
				{
					String unit = getPropertyProcessor( ).getDefaultUnit( getModelList( ) );
					if ( unit != null )
					{
						if ( !StringUtil.isBlank( unit ) )
						{
							unit = getUnitChoiceSet( ).findChoice( unit )
									.getDisplayName( );
						}
						unitCombo.setText( unit );
					}
					else
					{
						unitCombo.setText( unitCombo.getItem( 0 ) );
					}
				}
			}
		} );
		valueCombo.addFocusListener( new FocusListener( ) {

			public void focusGained( FocusEvent e )
			{
			}

			public void focusLost( FocusEvent e )
			{
				if ( !hasError )
				{
					processAction( );
				}
			}
		} );

		unitCombo = new Combo( container, SWT.BORDER | SWT.READ_ONLY );
		unitCombo.addSelectionListener( listener );

		GridData data = new GridData( );
		data.grabExcessHorizontalSpace = true;
		data.horizontalAlignment = GridData.FILL;
		valueCombo.setLayoutData( data );
		data = new GridData( );

		data.grabExcessHorizontalSpace = true;
		data.horizontalAlignment = GridData.FILL;
		data.widthHint = valueCombo.getSize( ).x;
		unitCombo.setLayoutData( data );

		return container;
	}

	protected boolean validateDimensionValue( )
	{
		if ( unitCombo.isEnabled( ) && unitCombo.getSelectionIndex( ) != -1 )
		{
			String value = valueCombo.getText( );
			String unit = getUnitChoiceSet( ).findChoiceByDisplayName( unitCombo.getText( ) )
					.getName( );
			boolean val = true;
			try
			{
				val = getPropertyProcessor( ).validateDimensionValue( value
						+ unit,
						getModelList( ) );
			}
			catch ( PropertyValueException e1 )
			{
				// do nothing
			}

			return val;
		}
		return true;
	}

	private void processAction( )
	{
		if ( !validateDimensionValue( ) )
		{
			setError( );
			ExceptionHandler.openErrorMessageBox( ERROR_BOX_TITLE,
					ERROR_MESSAGE );
			resetUIData( );
			clearError( );
			return;
		}

		String value = valueCombo.getText( );

		if ( value.equals( "" ) ) //$NON-NLS-1$
		{
			value = null;
		}
		else if ( valueChoiceSet != null )
		{
			IChoice ci = valueChoiceSet.findChoiceByDisplayName( value );

			if ( ci == null )
			{
				String unit = getUnitChoiceSet( ).findChoiceByDisplayName( unitCombo.getText( ) )
						.getName( );
				value = value + unit;

			}
			else
			{
				value = ci.getName( );
			}
		}

		try
		{
			getPropertyProcessor( ).setStringValue( value, getModelList( ) );
		}
		catch ( SemanticException e )
		{
			valueCombo.setText( deMesurementValue );
			unitCombo.setText( deUnitValue );
			WidgetUtil.processError( unitCombo.getShell( ), e );
		}
	} /*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.birt.report.designer.internal.ui.views.attributes.widget.PropertyDescriptor#getControl()
		 */

	public Control getControl( )
	{
		return container;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.extensions.IPropertyDescriptor#resetUIData()
	 */
	public void resetUIData( )
	{
		String value = getPropertyProcessor( ).getStringValue( getModelList( ) );
		deMesurementValue = value;

		// special case for null value.
		if ( value == null )
		{
			valueCombo.deselectAll( );
			valueCombo.setEnabled( false );
			unitCombo.deselectAll( );
			unitCombo.setEnabled( false );
			return;
		}
		boolean stateFlag = ( ( value == null ) == valueCombo.getEnabled( ) );
		if ( stateFlag )
		{
			valueCombo.setEnabled( value != null );
			unitCombo.setEnabled( value != null );
		}

		if ( valueChoiceSet == null )
		{
			valueChoiceSet = ChoiceSetFactory.getElementChoiceSet( getPropertyProcessor( ).getElementName( ),
					getPropertyProcessor( ).getProperty( ) );
			String[] displayNames = ChoiceSetFactory.getDisplayNamefromChoiceSet( valueChoiceSet );
			valueCombo.setItems( displayNames );
		}

		if ( unitChoiceSet == null )
		{
			unitChoiceSet = ChoiceSetFactory.getDimensionChoiceSet( getPropertyProcessor( ).getElementName( ),
					getPropertyProcessor( ).getProperty( ) );
			String[] displayNames = ChoiceSetFactory.getDisplayNamefromChoiceSet( unitChoiceSet );
			unitCombo.setItems( displayNames );
		}

		IChoice choice = null;
		if ( valueChoiceSet != null )
			choice = valueChoiceSet.findChoice( value );
		if ( choice != null )
		{
			valueCombo.setText( choice.getDisplayName( ) );
			deMesurementValue = choice.getDisplayName( );
			unitCombo.deselectAll( );
			unitCombo.setEnabled( false );
			return;
		}

		deUnitValue = getPropertyProcessor( ).getUnit( getModelList( ) );
		if ( unitChoiceSet != null )
			choice = unitChoiceSet.findChoice( deUnitValue );
		if ( choice != null )
		{
			unitCombo.setText( choice.getDisplayName( ) );
			deUnitValue = choice.getDisplayName( );
		}

		deMesurementValue = getPropertyProcessor( ).getMeasureValue( getModelList( ) );
		valueCombo.setText( deMesurementValue );
	}

	private void setError( )
	{
		hasError = true;
	}

	private void clearError( )
	{
		hasError = false;
	}

}