/*******************************************************************************
 * 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.ui.views.attributes.providers;

import java.util.List;

import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.util.CSSUtil;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.DesignEngine;
import org.eclipse.birt.report.model.api.GroupElementHandle;
import org.eclipse.birt.report.model.api.GroupPropertyHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.metadata.DimensionValue;
import org.eclipse.birt.report.model.api.metadata.IChoiceSet;
import org.eclipse.birt.report.model.api.metadata.IElementPropertyDefn;
import org.eclipse.birt.report.model.api.metadata.PropertyValueException;
import org.eclipse.birt.report.model.api.util.StringUtil;

/**
 * PropertyProcessor processes general property information.
 */
public class PropertyProcessor
{

	/**
	 * Property ID of DE model
	 */
	protected String property;

	/**
	 * The Element name that the property defined.
	 */
	protected String elementName;

	/**
	 * Constructor
	 * 
	 * @param property
	 *            Property key.
	 */
	public PropertyProcessor( String elementName, String property )
	{
		this.elementName = elementName;
		this.property = property;
	}

	/**
	 * Gets the defined display-name of the property.
	 * 
	 * @return String instance represented the defined display-name of the
	 *         property.
	 */
	public String getDisplayName( )
	{
		String name = null;
		IElementPropertyDefn propertyDefn = DesignEngine.getMetaDataDictionary( )
				.getElement( elementName )
				.getProperty( property );
		if ( propertyDefn != null )
		{
			name = Messages.getString( propertyDefn.getDisplayNameID( ) );
		}

		if ( name == null )
			return ""; //$NON-NLS-1$
		return name;
	}

	/**
	 * Gets the defined display-name of the property from element handle.
	 * 
	 * @param modelList
	 * @return
	 */
	public String getDisplayName( List modelList )
	{
		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );

		String name = null;
		IElementPropertyDefn propertyDefn = multiSelectionHandle.getPropertyHandle( property )
				.getPropertyDefn( );

		if ( propertyDefn != null )
		{
			name = propertyDefn.getDisplayName( );
		}

		if ( name == null )
			return ""; //$NON-NLS-1$
		return name;
	}

	/**
	 * Get all the Choices of property
	 * 
	 * @param modelList
	 * @return
	 */
	public IChoiceSet getChoiceSet( List modelList )
	{
		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );
		return multiSelectionHandle.getPropertyHandle( property )
				.getPropertyDefn( )
				.getChoices( );
	}

	/**
	 * Gets String value of the property.If all in the modelList have the same
	 * value, return it, else return empty string.
	 * 
	 * @param modelList
	 *            DE model list.
	 * @return String instance represented value of the property.
	 */
	public String getStringValue( List modelList )
	{

		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );
		String value = multiSelectionHandle.getStringProperty( property );

		if ( modelList.size( ) == 1 && value == null )
		{
			value = ""; //$NON-NLS-1$
		}
		else if ( value == null )
		// && multiSelectionHandle.shareSameValue( property ) )
		{
			value = ""; //$NON-NLS-1$
		}
		return value;
	}

	/**
	 * Get local string value of property
	 * 
	 * @param modelList
	 * @return
	 */
	public String getLocalStringValue( List modelList )
	{
		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );
		String value = multiSelectionHandle.getLocalStringProperty( property );

		if ( modelList.size( ) == 1 && value == null )
		{
			value = ""; //$NON-NLS-1$
		}
		else if ( value == null )
		// && multiSelectionHandle.shareSameValue( property ) )
		{
			value = ""; //$NON-NLS-1$
		}
		return value;
	}

	/**
	 * 
	 * @param modelList
	 * @return whether true if there is no handle for property
	 */
	public boolean isReadOnly( List modelList )
	{
		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );
		GroupPropertyHandle propertyHandle = multiSelectionHandle.getPropertyHandle( property );
		if ( propertyHandle != null )
		{
			return propertyHandle.isReadOnly( );
		}
		return false;
	}

	/**
	 * Gets the tool used to process multil-selection.
	 * 
	 * @param modelList
	 *            DE model list.
	 * @return The tool used to process multil-selection.
	 */
	private GroupElementHandle getMultiSelectionHandle( List modelList )
	{
		return DEUtil.getMultiSelectionHandle( modelList );
	}

	/**
	 * The getStringValue() method may return value as "10cm", uses this method
	 * to get numerical value from this kind of value.
	 * 
	 * @param modelList
	 *            DE model list.
	 * @return Numerical value.
	 */

	public String getMeasureValue( List modelList )
	{
		String value = getStringValue( modelList );
		if ( value == null || value.equals( "" ) ) //$NON-NLS-1$
			return value;
		try
		{
			DimensionValue dimensionValue = DimensionValue.parse( value );
			return StringUtil.doubleToString( dimensionValue.getMeasure( ), 3 );
		}
		catch ( PropertyValueException e )
		{
			ExceptionHandler.handle( e );
		}
		return ""; //$NON-NLS-1$
	}

	/**
	 * The getStringValue() method may return value as "10cm", uses this method
	 * to get unit from this kind of value.
	 * 
	 * @param modelList
	 *            DE model list.
	 * @return Unit value.
	 */

	public String getUnit( List modelList )
	{
		String value = getStringValue( modelList );

		if ( value == null || value.equals( "" ) ) //$NON-NLS-1$
			return value;
		try
		{
			DimensionValue dimensionValue = DimensionValue.parse( value );
			return dimensionValue.getUnits( );
		}
		catch ( PropertyValueException e )
		{
			ExceptionHandler.handle( e );
		}
		return ""; //$NON-NLS-1$
	}

	/**
	 * Gets the default unit for the model list.
	 * 
	 * @param modelList
	 * @return
	 */
	public String getDefaultUnit( List modelList )
	{
		if ( modelList == null || modelList.size( ) == 0 )
		{
			return null;
		}
		String unit = null;
		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );
		if ( !multiSelectionHandle.isSameType( ) )
		{
			return null;
		}
		DesignElementHandle handle = (DesignElementHandle) modelList.get( 0 );
		unit = handle.getPropertyHandle( property ).getDefaultUnit( );
		return unit;
	}

	/**
	 * 
	 * @param value
	 * @param modelList
	 * @return proper Dimension value according property'a name
	 * @throws PropertyValueException
	 */
	public boolean validateDimensionValue( String value, List modelList )
			throws PropertyValueException
	{
		DimensionValue dimensionValue = DimensionValue.parse( value );

		if ( dimensionValue == null )
		{
			return true;
		}

		int size = DEUtil.getFontSizeIntValue( (DesignElementHandle) modelList.get( 0 ) );

		double pointValue = CSSUtil.convertToPoint( dimensionValue, size );
		return pointValue < 1000000;
	}

	/**
	 * Saves the value to DE models.
	 * 
	 * @param value
	 *            The String value to set.
	 * @param modelList
	 *            DE model list.
	 * @throws SemanticException
	 */
	public void setStringValue( String value, List modelList )
			throws SemanticException
	{
		GroupElementHandle multiSelectionHandle = getMultiSelectionHandle( modelList );
		multiSelectionHandle.setStringProperty( property, value );
	}

	/**
	 * Gets the property key.
	 * 
	 * @return Returns the property.
	 */

	public String getProperty( )
	{
		return property;
	}

	/**
	 * Sets the property key.
	 * 
	 * @param property
	 *            The property key to set.
	 */

	public void setProperty( String property )
	{
		this.property = property;
	}

	/**
	 * Gets Element Name.
	 * 
	 * @return Returns the Element Name.
	 */

	public String getElementName( )
	{
		return elementName;
	}

	/**
	 * Sets the Element Name.
	 * 
	 * @param elementName
	 *            The Element Name to set.
	 */

	public void setElementName( String elementName )
	{
		this.elementName = elementName;
	}
}