/*******************************************************************************
 * 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.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.eclipse.birt.report.designer.internal.ui.editors.schematic.actions.ApplyStyleAction;
import org.eclipse.birt.report.designer.internal.ui.views.attributes.page.WidgetUtil;
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.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.DesignEngine;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
import org.eclipse.birt.report.model.api.ReportItemHandle;
import org.eclipse.birt.report.model.api.SharedStyleHandle;
import org.eclipse.birt.report.model.api.StyleHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.metadata.PredefinedStyle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

/**
 * ComboPropertyDescriptor manages Combo choice control.
 */
public class SimpleComboPropertyDescriptor extends AbstractPropertyDescriptor
{

	protected Combo combo;

	private String oldValue;

	private int style = SWT.BORDER;

	/**
	 * @param propertyProcessor
	 */
	public SimpleComboPropertyDescriptor( PropertyProcessor propertyProcessor )
	{
		super( propertyProcessor );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.internal.ui.views.attributes.widget.PropertyDescriptor#getControl()
	 */
	public Control getControl( )
	{
		return combo;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.ui.extensions.IPropertyDescriptor#createControl(org.eclipse.swt.widgets.Composite)
	 */
	public Control createControl( Composite parent )
	{
		combo = new Combo( parent, style );
		combo.addControlListener( new ControlListener( ) {

			public void controlMoved( ControlEvent e )
			{
				combo.clearSelection( );
			}

			public void controlResized( ControlEvent e )
			{
				combo.clearSelection( );
			}
		} );
		combo.addSelectionListener( new SelectionListener( ) {

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

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

	/**
	 * Processes the save action.
	 */
	private void processAction( )
	{
		String newValue = combo.getText( );
		if ( ChoiceSetFactory.CHOICE_NONE.equals( newValue ) )
		{
			newValue = null;
		}

		try
		{
			getPropertyProcessor( ).setStringValue( newValue, getModelList( ) );
		}
		catch ( SemanticException e )
		{
			WidgetUtil.processError( combo.getShell( ), e );
			combo.setText( oldValue );
			combo.setSelection( new Point( 0, oldValue.length( ) ) );
		}

	}

	private String[] filterPreStyles( String items[] )
	{
		List preStyles = DesignEngine.getMetaDataDictionary( )
				.getPredefinedStyles( );
		List preStyleNames = new ArrayList( );

		for ( int i = 0; i < preStyles.size( ); i++ )
		{
			preStyleNames.add( ( (PredefinedStyle) preStyles.get( i ) ).getName( ) );
		}

		List sytleNames = new ArrayList( );
		for ( int i = 0; i < items.length; i++ )
		{
			if ( preStyleNames.indexOf( items[i] ) == -1 )
			{
				sytleNames.add( items[i] );
			}
		}

		return (String[]) ( sytleNames.toArray( new String[]{} ) );

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.internal.ui.views.attributes.widget.PropertyDescriptor#resetUIData()
	 */
	public void resetUIData( )
	{
		String property = getPropertyProcessor( ).getProperty( );
		String[] items = null;

		if ( ReportItemHandle.DATA_SET_PROP.equals( property ) )
			items = ChoiceSetFactory.getDataSets( );
		else if ( StyleHandle.MASTER_PAGE_PROP.equals( property ) )
			items = ChoiceSetFactory.getMasterPages( );
		else if ( ReportItemHandle.STYLE_PROP.equals( property ) )
		{
			items = ChoiceSetFactory.getStyles( );
			items = filterPreStyles( items );
		}
		else if ( ReportDesignHandle.THEME_PROP.equals( property ) )
			items = ChoiceSetFactory.getThemes( );
		combo.setItems( items );

		oldValue = getPropertyProcessor( ).getStringValue( getModelList( ) );
		boolean stateFlag = ( ( oldValue == null ) == combo.getEnabled( ) );
		if ( stateFlag )
			combo.setEnabled( oldValue != null );

		if ( getPropertyProcessor( ).isReadOnly( getModelList( ) ) )
		{
			combo.setEnabled( false );
		}

		int sindex = Arrays.asList( items ).indexOf( oldValue );

		if (( ReportItemHandle.STYLE_PROP.equals( property )
				|| ReportDesignHandle.THEME_PROP.equals( property )
				|| StyleHandle.MASTER_PAGE_PROP.equals( property ))
				&& sindex < 0 )
		{
			if ( oldValue != null && oldValue.length( ) > 0 )
			{
				combo.setText( oldValue );
				return;
			}

			if ( combo.getItemCount( ) > 0 )
			{
				combo.select( 0 );
				return;
			}
		}
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		combo.setLayoutData(gd);
		combo.layout();
		combo.select( sindex );
	}

	/**
	 * @return Returns the SWT style.
	 */
	public int getStyle( )
	{
		return style;
	}

	/**
	 * Add a SWT style to the combo widget
	 * 
	 * @param style
	 *            The SWT style to add.
	 */
	public void addStyle( int style )
	{
		this.style |= style;
	}
}