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

import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.internal.ui.views.attributes.widget.PropertyDescriptorFactory;
import org.eclipse.birt.report.designer.ui.views.attributes.IPropertyDescriptor;
import org.eclipse.birt.report.designer.ui.views.attributes.providers.PropertyProcessor;
import org.eclipse.birt.report.model.api.StyleHandle;
import org.eclipse.birt.report.model.api.elements.ReportDesignConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * WidgetUtil defines constant values to custom control size and provides common
 * layout mechanism.
 */
public class WidgetUtil
{

	/**
	 * Default height of Text control
	 */
	public final static int TEXT_HEIGHT = 12;

	/**
	 * Default width of Text control
	 */
	public final static int TEXT_WIDTH = 40;

	/**
	 * Default Height of Combo control
	 */
	public final static int COMBO_HEIGHT = 8;

	/**
	 * Default width of Combo control
	 */
	public final static int COMBO_WIDTH = 18;

	/**
	 * The number of pixels between the edge of one control and the edge of its
	 * neighbouring control.
	 */
	public final static int SPACING = 7;

	/**
	 * The height of margin.
	 */
	public final static int MARGIN_HEIGHT = 7;

	/**
	 * The width of margin.
	 */
	public final static int MARGIN_WIDTH = 7;

	/**
	 * The minimum width for a text control
	 */
	public final static int MIN_TEXT_WIDTH = 80;

	/**
	 * Creates a default GridLayout layout Manager.
	 * 
	 * @param columns
	 *            The number of columns in the grid
	 * @return A GridLayout instance.
	 */
	public static GridLayout createGridLayout( int columns )
	{
		GridLayout layout = new GridLayout( columns, false );
		layout.marginHeight = WidgetUtil.MARGIN_HEIGHT;
		layout.marginWidth = WidgetUtil.MARGIN_WIDTH;
		layout.horizontalSpacing = WidgetUtil.SPACING;
		layout.verticalSpacing = WidgetUtil.SPACING;
		return layout;
	}

	/**
	 * Creates a GridLayout layout Manager that specified spaces of each border.
	 * 
	 * @param columns
	 *            The number of columns in the grid
	 * @param space
	 *            The space.
	 * @return A GridLayout instance.
	 */
	public static GridLayout createSpaceGridLayout( int columns, int space )
	{
		GridLayout layout = new GridLayout( columns, false );
		layout.marginHeight = space;
		layout.marginWidth = space;
		layout.horizontalSpacing = space;
		layout.verticalSpacing = space;
		return layout;
	}

	/**
	 * Creates a default FormLayout layout Manager.
	 * 
	 * @return A FormLayout instance.
	 */
	public static FormLayout createFormLayout( )
	{
		FormLayout layout = new FormLayout( );
		layout.marginHeight = WidgetUtil.MARGIN_HEIGHT;
		layout.marginWidth = WidgetUtil.MARGIN_WIDTH;
		layout.spacing = WidgetUtil.SPACING;
		return layout;
	}

	/**
	 * Creates a default FormLayout layout Manager.
	 * 
	 * @param space
	 *            The space.
	 * @return A FormLayout instance.
	 */
	public static FormLayout createSpaceFormLayout( int space )
	{
		FormLayout layout = new FormLayout( );
		layout.marginHeight = space;
		layout.marginWidth = space;
		layout.spacing = space;
		return layout;
	}

	/**
	 * Creates [ Label operable-control] controls pair and layouts them.
	 * 
	 * @param parent
	 *            A widget which will be the parent of the new instance (cannot
	 *            be null)
	 * @param descriptorList
	 *            the descriptor list
	 * @param elementName
	 *            The DE element name that controls operate on
	 * @param property
	 *            The property that controls process
	 * @param hSpan
	 *            The number of column cells that operable-control will take up.
	 * @param grabSpace
	 *            grabSpace specifies whether the cell will be made wide enough
	 *            to fit the remaining horizontal space.
	 * @return
	 */
	public static Control buildGridControl( Composite parent,
			Map propertiesMap, String elementName, String property, int hSpan,
			boolean grabSpace )
	{
		IPropertyDescriptor descriptor = PropertyDescriptorFactory.getPropertyDescriptor( elementName,
				property );
		propertiesMap.put( property, descriptor );
		Label label = new Label( parent, SWT.NONE );
		label.setText( getDisplayName( descriptor ) );
		Control control = descriptor.createControl( parent );
		GridData data = new GridData( );
		data.horizontalSpan = hSpan;
		data.grabExcessHorizontalSpace = grabSpace;
		if ( control instanceof Text  || control instanceof Combo)
		{
			data.widthHint = MIN_TEXT_WIDTH;
		}		
		data.horizontalAlignment = GridData.FILL;
		control.setLayoutData( data );
		return control;
	}

	/**
	 * Creates [ Label operable-control] controls pair and layouts them.
	 * 
	 * @param parent
	 *            A widget which will be the parent of the new instance (cannot
	 *            be null)
	 * @param descriptorList
	 *            the descriptor list
	 * @param elementName
	 *            The DE element name that controls operate on
	 * @param property
	 *            The property that controls process
	 * @param hSpan
	 *            The number of column cells that operable-control will take up.
	 * @param width 
	 *            The width of the control
	 *            
	 * @return
	 */
	public static Control buildGridControl( Composite parent,
			Map propertiesMap, String elementName, String property, int hSpan,
			int width )
	{
		IPropertyDescriptor descriptor = PropertyDescriptorFactory.getPropertyDescriptor( elementName,
				property );
		propertiesMap.put( property, descriptor );
		Label label = new Label( parent, SWT.NONE );
		label.setText( getDisplayName( descriptor ) );
		Control control = descriptor.createControl( parent );
		GridData data = new GridData( );
		data.horizontalSpan = hSpan;
		data.widthHint = width;
		control.setLayoutData( data );
		return control;
	}
	
	public static Composite buildGridComposite( Composite parent, int hSpan , boolean grabSpace ){
		
		Composite composite = new Composite(parent,SWT.NONE);
		GridData data = new GridData( GridData.FILL_HORIZONTAL );
		data.horizontalSpan = hSpan;
		data.grabExcessHorizontalSpace = grabSpace;
		composite.setLayoutData( data );
		
		return composite;
	}
	
	private static String getDisplayName( IPropertyDescriptor descriptor )
	{
		String name = null;
		PropertyProcessor processor = null;
		if ( descriptor != null )
			processor = descriptor.getPropertyProcessor( );
		if ( processor != null )
			name = processor.getDisplayName( );
		return name == null ? "" : name;//$NON-NLS-1$
	}

	/**
	 * Creates Font style button group,the group contains
	 * bold,italic,underline,strike-through styles for font.
	 * 
	 * @param parent
	 *            A widget which will be the parent of the new instance (cannot
	 *            be null)
	 * @param descriptorList
	 *            the descriptor list
	 * @return
	 */
	public static Composite buildFontStyleUI( Composite parent,
			Map propertiesMap )
	{
		Composite container = new Composite( parent, SWT.NONE );
		RowLayout layout = new RowLayout( SWT.HORIZONTAL );
		layout.marginBottom = 0;
		layout.marginHeight = 0;
		layout.marginLeft = 0;
		layout.marginRight = 0;
		layout.marginTop = 0;
		layout.marginWidth = 0;
		layout.spacing = 0;
		container.setLayout( layout );
		String[] properties = {
				StyleHandle.FONT_WEIGHT_PROP,
				StyleHandle.FONT_STYLE_PROP,
				StyleHandle.TEXT_UNDERLINE_PROP,
				StyleHandle.TEXT_LINE_THROUGH_PROP
		};
		for ( int i = 0; i < properties.length; i++ )
		{
			IPropertyDescriptor descriptor = PropertyDescriptorFactory.getPropertyDescriptor( ReportDesignConstants.STYLE_ELEMENT,
					properties[i] );
			propertiesMap.put( properties[i], descriptor );
			descriptor.createControl( container );
		}
		return container;
	}

	/**
	 * Creates a place-holder Label for using in GridLayout.
	 * 
	 * @param parent
	 *            A widget which will be the parent of the new instance (cannot
	 *            be null)
	 * @param hSpan
	 *            The number of column cells that operable-control will take up.
	 * @param grabSpace
	 *            grabSpace specifies whether the cell will be made wide enough
	 *            to fit the remaining horizontal space.
	 * @return The place-holder Label control.
	 */
	public static Label createGridPlaceholder( Composite parent, int hSpan,
			boolean grabSpace )
	{
		Label label = new Label( parent, SWT.NONE );
		GridData data = new GridData( );
		data.horizontalSpan = hSpan;
		data.grabExcessHorizontalSpace = grabSpace;
		label.setLayoutData( data );
		return label;
	}

	/**
	 * Creates a horizontal seperator line.
	 * 
	 * @param parent
	 *            A widget which will be the parent of the new instance (cannot
	 *            be null)
	 * @param hSpan
	 *            The number of column cells that operable-control will take up.
	 * @return The Label control.
	 */
	public static Label createHorizontalLine( Composite parent, int hSpan )
	{
		Label label = new Label( parent, SWT.SEPARATOR | SWT.HORIZONTAL );
		GridData data = new GridData( );
		data.horizontalSpan = hSpan;
		data.horizontalAlignment = GridData.FILL;
		label.setLayoutData( data );
		return label;
	}

	/**
	 * Error processor, shows the Error message.
	 * 
	 * @param shell
	 *            the parent window.
	 * @param e
	 *            Exception object.
	 */
	public static void processError( Shell shell, Exception e )
	{
		ExceptionHandler.handle( e );
	}
	
	public static void setExcludeGridData(Control control,boolean exclude){
		Object obj = control.getLayoutData( );
		if(obj == null)control.setLayoutData( new GridData() );
		else if(!(obj instanceof GridData))return;
		GridData data = (GridData)control.getLayoutData( );
		data.exclude = exclude;
		control.setLayoutData( data );
		control.setVisible( !exclude );
	}
}