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

import org.eclipse.birt.report.designer.core.model.SessionHandleAdapter;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.DataSetHandle;
import org.eclipse.birt.report.model.api.DesignEngine;
import org.eclipse.birt.report.model.api.GroupHandle;
import org.eclipse.birt.report.model.api.MasterPageHandle;
import org.eclipse.birt.report.model.api.ModuleHandle;
import org.eclipse.birt.report.model.api.ReportElementHandle;
import org.eclipse.birt.report.model.api.SlotHandle;
import org.eclipse.birt.report.model.api.StyleHandle;
import org.eclipse.birt.report.model.api.core.IAccessControl;
import org.eclipse.birt.report.model.api.elements.DesignChoiceConstants;
import org.eclipse.birt.report.model.api.elements.structures.FilterCondition;
import org.eclipse.birt.report.model.api.elements.structures.FormatValue;
import org.eclipse.birt.report.model.api.elements.structures.SortKey;
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.IColorConstants;
import org.eclipse.birt.report.model.api.metadata.IElementPropertyDefn;
import org.eclipse.birt.report.model.api.metadata.IPropertyDefn;
import org.eclipse.birt.report.model.api.metadata.IPropertyType;
import org.eclipse.birt.report.model.api.metadata.IStructureDefn;

/**
 * ChoiceSetFactory provides common interface to access all kinds of collection
 * on given property.
 */

public class ChoiceSetFactory
{

	public static final String CHOICE_NONE = Messages.getString( "ChoiceSetFactory.choice.None" ); //$NON-NLS-1$

	public static final String CHOICE_AUTO = Messages.getString( "ChoiceSetFactory.choice.Auto" ); //$NON-NLS-1$

	/**
	 * Gets the collection that given property value can selected from them.
	 * 
	 * @param property
	 *            DE Property key.
	 * @return The ChoiceSet instance contains all the allowed values.
	 * @deprecated Use getDEChoiceSet( String property ,String elementName)
	 *             instead
	 */
	public static IChoiceSet getDEChoiceSet( String property )
	{
		String unitKey = DesignChoiceConstants.CHOICE_UNITS;
		if ( AttributeConstant.BACKGROUND_COLOR.equals( property ) )
		{
			unitKey = IColorConstants.COLORS_CHOICE_SET;
		}
		else if ( AttributeConstant.FONT_COLOR.equals( property ) )
		{
			unitKey = IColorConstants.COLORS_CHOICE_SET;
		}
		else if ( AttributeConstant.FONT_SIZE.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_FONT_SIZE;
		}
		else if ( AttributeConstant.FONT_FAMILY.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_FONT_FAMILY;
		}
		else if ( AttributeConstant.TEXT_FORMAT.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_TEXT_CONTENT_TYPE;
		}
		else if ( AttributeConstant.BORDER_STYLE.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_LINE_STYLE;
		}
		else if ( AttributeConstant.BORDER_WIDTH.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_LINE_WIDTH;
		}
		else if ( SortKey.DIRECTION_MEMBER.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_SORT_DIRECTION;
		}
		else if ( FilterCondition.OPERATOR_MEMBER.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_FILTER_OPERATOR;
		}
		else if ( StyleHandle.VERTICAL_ALIGN_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_VERTICAL_ALIGN;
		}
		else if ( StyleHandle.TEXT_ALIGN_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_TEXT_ALIGN;
		}
		else if ( MasterPageHandle.ORIENTATION_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_ORIENTATION;
		}
		else if ( MasterPageHandle.TYPE_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_SIZE;
		}
		else if ( GroupHandle.INTERVAL_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_INTERVAL;
		}
		else if ( StyleHandle.PAGE_BREAK_BEFORE_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_BREAK_BEFORE;
		}
		else if ( StyleHandle.PAGE_BREAK_AFTER_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_BREAK_AFTER;
		}
		else if ( StyleHandle.PAGE_BREAK_INSIDE_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_BREAK_INSIDE;
		}
		return DesignEngine.getMetaDataDictionary( ).getChoiceSet( unitKey );

	}

	/**
	 * Gets the collection that given property value can selected from them.
	 * 
	 * @param elementName
	 *            The name of the element.
	 * @param property
	 *            DE Property key.
	 * @return The ChoiceSet instance contains all the allowed values.
	 */

	public static IChoiceSet getElementChoiceSet( String elementName,
			String property )
	{
		IElementPropertyDefn propertyDefn = DesignEngine.getMetaDataDictionary( )
				.getElement( elementName )
				.getProperty( property );
		if ( propertyDefn.getTypeCode( ) == IPropertyType.DIMENSION_TYPE
				&& propertyDefn.getChoices( ) != null )
		{
			return propertyDefn.getChoices( );
		}
		return propertyDefn.getAllowedChoices( );
	}

	/**
	 * Gets the dimension collection that given property value can selected from
	 * them.
	 * 
	 * @param elementName
	 *            The name of the element.
	 * @param property
	 *            DE Property key.
	 * @return The ChoiceSet instance contains all the allowed values.
	 */
	public static IChoiceSet getDimensionChoiceSet( String elementName,
			String property )
	{
		IElementPropertyDefn propertyDefn = DesignEngine.getMetaDataDictionary( )
				.getElement( elementName )
				.getProperty( property );
		if ( propertyDefn.getTypeCode( ) == IPropertyType.DIMENSION_TYPE )
		{
			return propertyDefn.getAllowedChoices( );
		}
		return null;
	}

	/**
	 * Gets the collection that given structure property value can selected from
	 * them.
	 * 
	 * @param elementName
	 *            The name of the element.
	 * @param property
	 *            DE Property key.
	 * @return The ChoiceSet instance contains all the allowed values.
	 */
	public static IChoiceSet getStructChoiceSet( String structName,
			String property )
	{
		IPropertyDefn propertyDefn = DesignEngine.getMetaDataDictionary( )
				.getStructure( structName )
				.findProperty( property );
		return propertyDefn.getChoices( );
	}

	/**
	 * Gets all displayNames that a given ChoiceSet instance contained.
	 * 
	 * @param choiceSet
	 *            The ChoiceSet instance.
	 * @return A String array contains displayNames.
	 */
	public static String[] getDisplayNamefromChoiceSet( IChoiceSet choiceSet )
	{
		return getDisplayNamefromChoiceSet( choiceSet, null );
	}

	/**
	 * Gets all displayNames that a given ChoiceSet instance contained.
	 * 
	 * @param choiceSet
	 *            The ChoiceSet instance.
	 * @param comparator
	 *            The sort comparator.
	 * @return A String array contains displayNames.
	 */
	public static String[] getDisplayNamefromChoiceSet( IChoiceSet choiceSet,
			Comparator comparator )
	{
		String[] displayNames = new String[0];
		if ( choiceSet == null )
		{
			return displayNames;
		}
		IChoice[] choices = choiceSet.getChoices( comparator );

		if ( choices == null )
			return displayNames;

		displayNames = new String[choices.length];
		for ( int i = 0; i < choices.length; i++ )
		{
			displayNames[i] = choices[i].getDisplayName( );
		}
		return displayNames;
	}

	/**
	 * Gets all names that a given ChoiceSet instance contained.
	 * 
	 * @param choiceSet
	 *            The ChoiceSet instance.
	 * @return A String array contains names.
	 */
	public static String[] getNamefromChoiceSet( IChoiceSet choiceSet )
	{
		String[] names = new String[0];
		if ( choiceSet == null )
			return names;
		IChoice[] choices = choiceSet.getChoices( );
		if ( choices == null )
			return names;

		names = new String[choices.length];
		for ( int i = 0; i < choices.length; i++ )
		{
			names[i] = choices[i].getName( );
		}
		return names;
	}

	/**
	 * Gets property 's display names given element name and the property name.
	 * 
	 * @param elemenName
	 *            The design element name.
	 * @param property
	 *            The property name.
	 * @return The given property 's display names
	 */
	public static String[] getPropertyDisplayNames( String elementName,
			String property )
	{
		IChoiceSet choiceSet = getElementChoiceSet( elementName, property );
		return getDisplayNamefromChoiceSet( choiceSet );
	}

	/**
	 * Gets property 's display name given element name, property name and the
	 * property's value.
	 * 
	 * @param elemenName
	 *            The design element name.
	 * @param property
	 *            The property name.
	 * @param valule
	 *            The property 's value.
	 * @return The given property 's display name
	 */
	public static String getPropDisplayName( String elementName,
			String property, String value )
	{
		IChoiceSet set = getElementChoiceSet( elementName, property );
		return getDisplayNameFromChoiceSet( value, set );
	}

	/**
	 * Gets structure property 's display name given element name, property name
	 * and the property's value.
	 * 
	 * @param structName
	 *            The structure name.
	 * @param memberName
	 *            The member name.
	 * @param valule
	 *            The property 's value.
	 * @return The given property 's display name
	 */

	public static String getStructDisplayName( String structName,
			String memberName, String value )
	{
		IChoiceSet set = getStructChoiceSet( structName, memberName );
		return getDisplayNameFromChoiceSet( value, set );
	}

	/**
	 * Gets property value given element name, property name and its the
	 * property's display name.
	 * 
	 * @param elemenName
	 *            The design element name.
	 * @param property
	 *            The property name.
	 * @param displayName
	 *            The property 's display name.
	 * @return The given property 's value
	 */
	public static String getPropValue( String elementName, String property,
			String displayName )
	{
		IChoiceSet set = getElementChoiceSet( elementName, property );
		return getValueFromChoiceSet( displayName, set );
	}

	/**
	 * Gets structure property value given element name, property name and its
	 * the property's display name.
	 * 
	 * @param structName
	 *            The design element name.
	 * @param memberName
	 *            The property name.
	 * @param displayName
	 *            The property 's display name.
	 * @return The given property 's value
	 */
	public static String getStructPropValue( String structName,
			String memberName, String displayName )
	{
		IChoiceSet set = getStructChoiceSet( structName, memberName );
		return getValueFromChoiceSet( displayName, set );
	}

	/**
	 * Gets UI display name from a choice set given the the value and the choice
	 * set name.
	 * 
	 * @param value
	 *            The value corresponding to the display name.
	 * @param set
	 *            The choice set name from which to get display name.
	 * @return The display name of the given value
	 */
	public static String getDisplayNameFromChoiceSet( String value,
			IChoiceSet set )
	{
		String name = value;
		if ( set == null )
		{
			return name;
		}
		IChoice[] choices = set.getChoices( );
		if ( choices == null )
		{
			return name;
		}
		for ( int i = 0; i < choices.length; i++ )
		{
			if ( choices[i].getName( ).equals( value ) )
			{
				return choices[i].getDisplayName( );
			}
		}
		return name;
	}

	/**
	 * Gets the value from a choice set given the UI display name and the choice
	 * set name.
	 * 
	 * @param displayName
	 *            The UI display name corresponding to the value.
	 * @param set
	 *            The choice set name from which to get property value.
	 * @return The value of the given UI display name.
	 */
	public static String getValueFromChoiceSet( String displayName,
			IChoiceSet set )
	{
		String value = displayName;
		if ( set == null )
		{
			return value;
		}
		IChoice[] choices = set.getChoices( );
		if ( choices == null )
		{
			return value;
		}
		for ( int i = 0; i < choices.length; i++ )
		{
			if ( choices[i].getDisplayName( ).equals( displayName ) )
			{
				return choices[i].getName( );
			}
		}
		return value;
	}

	/**
	 * Gets the collection that given property value can selected from them.
	 * 
	 * @param property
	 *            DE Property key.
	 * @return A String array contains all the allowed values.
	 * @deprecated Use getDEChoiceSet( String property ,String elementName)
	 *             instead
	 */

	public static Object[] getChoiceSet( String property )
	{
		// The dataSet has different access method.
		if ( AttributeConstant.DATASET.equals( property ) )
		{
			return getDataSets( );
		}

		String unitKey = DesignChoiceConstants.CHOICE_UNITS;
		if ( AttributeConstant.BACKGROUND_COLOR.equals( property ) )
		{
			unitKey = IColorConstants.COLORS_CHOICE_SET;
		}
		else if ( AttributeConstant.FONT_COLOR.equals( property ) )
		{
			unitKey = IColorConstants.COLORS_CHOICE_SET;
		}
		else if ( AttributeConstant.FONT_SIZE.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_FONT_SIZE;
		}
		else if ( AttributeConstant.FONT_FAMILY.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_FONT_FAMILY;
		}
		else if ( AttributeConstant.TEXT_FORMAT.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_TEXT_CONTENT_TYPE;
		}
		else if ( AttributeConstant.BORDER_STYLE.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_LINE_STYLE;
		}
		else if ( AttributeConstant.BORDER_WIDTH.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_LINE_WIDTH;
		}
		else if ( SortKey.DIRECTION_MEMBER.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_SORT_DIRECTION;
		}
		else if ( FilterCondition.OPERATOR_MEMBER.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_FILTER_OPERATOR;
		}
		else if ( StyleHandle.VERTICAL_ALIGN_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_VERTICAL_ALIGN;
		}
		else if ( StyleHandle.TEXT_ALIGN_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_TEXT_ALIGN;
		}
		else if ( MasterPageHandle.ORIENTATION_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_ORIENTATION;
		}
		else if ( MasterPageHandle.TYPE_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_SIZE;
		}
		else if ( GroupHandle.INTERVAL_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_INTERVAL;
		}
		else if ( StyleHandle.PAGE_BREAK_BEFORE_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_BREAK_BEFORE;
		}
		else if ( StyleHandle.PAGE_BREAK_AFTER_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_BREAK_AFTER;
		}
		else if ( StyleHandle.PAGE_BREAK_INSIDE_PROP.equals( property ) )
		{
			unitKey = DesignChoiceConstants.CHOICE_PAGE_BREAK_INSIDE;
		}
		return getUnitChoiceSet( unitKey );
	}

	/**
	 * Gets the collection that DE provides.
	 * 
	 * @param unitKey
	 *            Choice type key.
	 * @return A String array contains all the allowed values.
	 */

	private static Object[] getUnitChoiceSet( String unitKey )
	{
		ArrayList list = new ArrayList( );
		IChoiceSet choiceSet = DesignEngine.getMetaDataDictionary( )
				.getChoiceSet( unitKey );
		if ( choiceSet != null )
		{
			IChoice[] choices = choiceSet.getChoices( );
			for ( int i = 0; i < choices.length; i++ )
			{
				list.add( choices[i] );
			}
		}
		return list.toArray( new IChoice[0] );
	}

	/**
	 * Gets all the DataSets available.
	 * 
	 * @return A String array contains all the DataSets.
	 */
	public static String[] getDataSets( )
	{
		ArrayList list = new ArrayList( );

		ModuleHandle handle = SessionHandleAdapter.getInstance( )
				.getReportDesignHandle( );

		for ( Iterator iterator = handle.getVisibleDataSets( ).iterator( ); iterator.hasNext( ); )
		{
			DataSetHandle DataSetHandle = (DataSetHandle) iterator.next( );
			list.add( DataSetHandle.getQualifiedName( ) );
		}

		return (String[]) list.toArray( new String[0] );
	}

	/**
	 * Gets all the MasterPages available.
	 * 
	 * @return A String array contains all the MasterPages.
	 */
	public static String[] getMasterPages( )
	{
		ArrayList list = new ArrayList( );
		list.add( CHOICE_NONE );
		ModuleHandle handle = SessionHandleAdapter.getInstance( )
				.getReportDesignHandle( );
		SlotHandle pages = handle.getMasterPages( );
		if ( pages != null )
		{
			Iterator iterator = pages.iterator( );
			while ( iterator.hasNext( ) )
			{
				ReportElementHandle elementHandle = (ReportElementHandle) iterator.next( );
				list.add( elementHandle.getQualifiedName() );
			}
		}
		return (String[]) list.toArray( new String[0] );
	}

	/**
	 * Gets all the Styles available.
	 * 
	 * @return A String array contains all the Styles.
	 */
	public static String[] getStyles( )
	{
		ArrayList list = new ArrayList( );
		list.add( CHOICE_NONE );

		Iterator iterator = DEUtil.getStyles( );

		if ( iterator != null )
		{
			while ( iterator.hasNext( ) )
			{
				ReportElementHandle elementHandle = (ReportElementHandle) iterator.next( );
				list.add( elementHandle.getDisplayLabel() );
			}
		}
		return (String[]) list.toArray( new String[0] );
	}

	/**
	 * Gets all available themes .
	 * 
	 * @return A String array contains all available themes.
	 */
	public static String[] getThemes( )
	{
		ArrayList list = new ArrayList( );
		list.add( CHOICE_NONE );

		ModuleHandle handle = SessionHandleAdapter.getInstance( )
				.getReportDesignHandle( );
		Iterator iterator = handle.getVisibleThemes( IAccessControl.DIRECTLY_INCLUDED_LEVEL ).iterator( );

		if ( iterator != null )
		{
			while ( iterator.hasNext( ) )
			{
				ReportElementHandle elementHandle = (ReportElementHandle) iterator.next( );
				list.add( elementHandle.getQualifiedName( ) );
			}
		}
		return (String[]) list.toArray( new String[0] );
	}

	/**
	 * Gets the default format value given the struct name of format property .
	 * 
	 * @param structName
	 *            The struct name of the format property.
	 * @return formatValue = new String[2]. The default format value, String[0]:
	 *         default category; String[1]: default pattern.
	 */
	public static String[] getDefaultFormatValue( String structName )
	{
		String[] formatValue = new String[2];
		IStructureDefn def = DesignEngine.getMetaDataDictionary( )
				.getStructure( structName );
		formatValue[0] = (String) def.getMember( FormatValue.CATEGORY_MEMBER )
				.getDefault( );
		formatValue[1] = (String) def.getMember( FormatValue.PATTERN_MEMBER )
				.getDefault( );
		return formatValue;
	}
}