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

import java.util.Arrays;

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.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;

/**
 * PropertyDescriptor manages input text control & combo choice control.
 */
public class UnitPropertyDescriptor extends AbstractPropertyDescriptor
{

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

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

	protected Text text;

	protected Combo combo;

	protected Composite container;

	protected IChoiceSet choiceSet;

	protected String deMeasureValue, deUnitValue;

	private boolean hasError = false;

	/**
	 * constructor
	 * 
	 * @param propertyHandle
	 *            The model instance
	 */
	public UnitPropertyDescriptor( PropertyProcessor propertyProcessor )
	{
		super( propertyProcessor );
	}

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

		boolean stateFlag = ( ( value == null ) == text.getEnabled( ) );
		if ( stateFlag )
		{
			text.setEnabled( value != null );
			combo.setEnabled( value != null );
		}

		deMeasureValue = getPropertyProcessor( ).getMeasureValue( getModelList( ) );

		if ( deMeasureValue == null )
			deMeasureValue = ""; //$NON-NLS-1$
		if ( !deMeasureValue.equals( text.getText( ) ) )
		{
			text.setText( deMeasureValue );
		}

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

		deUnitValue = getPropertyProcessor( ).getUnit( getModelList( ) );
		IChoice choice = choiceSet.findChoice( deUnitValue );
		if ( choice == null )
		{
			combo.deselectAll( );
			return;
		}
		if ( !choice.getDisplayName( ).equals( combo.getText( ) ) )
			combo.select( Arrays.asList( displayNames )
					.indexOf( choice.getDisplayName( ) ) );
	}

	/*
	 * (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#createControl(org.eclipse.swt.widgets.Composite)
	 */
	public Control createControl( Composite parent )
	{
		container = new Composite( parent, SWT.NONE );
		FormLayout layout = new FormLayout( );
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		layout.spacing = 0;
		container.setLayout( layout );

		SelectionListener listener = new SelectionListener( ) {

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

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

		text = new Text( container, SWT.BORDER | SWT.RIGHT );
		text.addSelectionListener( listener );
		text.addModifyListener( new ModifyListener( ) {

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

			public void focusGained( FocusEvent e )
			{
			}

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

		combo = new Combo( container, SWT.BORDER | SWT.READ_ONLY );
		combo.addSelectionListener( listener );
		FormData data = new FormData( );
		data.left = new FormAttachment( 60 );
		data.right = new FormAttachment( 100 );
		combo.setLayoutData( data );

		data = new FormData( );
		data.bottom = new FormAttachment( combo, 0, SWT.BOTTOM );
		data.top = new FormAttachment( 0 );
		data.left = new FormAttachment( 0 );
		data.right = new FormAttachment( 60 );
		text.setLayoutData( data );
		return container;
	}

	protected boolean validateDimensionValue( )
	{
		if ( combo.isEnabled( ) && combo.getSelectionIndex( ) != -1 )
		{
			String value = text.getText( );
			String unit = getUnitChoiceSet( ).findChoiceByDisplayName( combo.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 = text.getText( ).trim( );
		if ( value.equals( "" ) ) //$NON-NLS-1$
		{
			value = null;
		}
		else
		{
			if ( choiceSet != null )
			{
				IChoice choice = choiceSet.findChoiceByDisplayName( combo.getText( ) );
				if ( choice != null )
					value += choice.getName( );
			}
			if ( value.equals( deMeasureValue + deUnitValue ) )
				return;
		}
		try
		{
			getPropertyProcessor( ).setStringValue( value, getModelList( ) );
		}
		catch ( SemanticException e )
		{
			text.setText( deMeasureValue );
			WidgetUtil.processError( combo.getShell( ), e );

		}
	}

	private void setError( )
	{
		hasError = true;
	}

	private void clearError( )
	{
		hasError = false;
	}

}