/*******************************************************************************
 * Copyright (c) 2004, 2005 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.data.engine.aggregation;

import java.util.HashMap;

import org.eclipse.birt.core.framework.FrameworkException;
import org.eclipse.birt.core.framework.IConfigurationElement;
import org.eclipse.birt.core.framework.IExtension;
import org.eclipse.birt.core.framework.IExtensionPoint;
import org.eclipse.birt.core.framework.IExtensionRegistry;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.data.engine.api.aggregation.IAggregation;
import org.eclipse.birt.data.engine.core.DataException;
import org.eclipse.birt.data.engine.i18n.ResourceConstants;


/**
 * The instances of this class manage all aggregations, including BuiltInAggregation (as defined
 * in BuiltInAggregationFactory) and customized aggregation (as defined in plugins).
 */

public class AggregationFactory 
{
	private static final String ATTRIBUTE_AGGREGATION_CLASS = "aggregationClass";
	private static final String ATTRIBUTE_AGGREGATION_NAME = "name";
	private static final String EXTENSION_POINT = "org.eclipse.birt.data.aggregation";
	private static final String ELEMENT_AGGREGATIONS = "Aggregations";
	private static final String ELEMENT_AGGREGATION = "Aggregation";
	
	private static AggregationFactory instance = null;
	private static HashMap aggregations = null;
	
	/**
	 * Return a shared instance of AggregationFactory.
	 * @return
	 * @throws DataException
	 */
	public static AggregationFactory getInstance( ) throws DataException
	{
		if ( instance == null )
		{
			synchronized ( AggregationFactory.class )
			{
				if ( instance == null )
					instance = new AggregationFactory( );
			}
		}
		
		return instance;
	}
	
	/**
	 * Destroy shared instance of AggregationFactory.
	 * 
	 */
	public static void destroyInstance( )
	{
		instance = null;
		aggregations = null;
	}

	
	private AggregationFactory( ) throws DataException
	{
		populateAggregations( );
	}

	/**
	 * Populate the aggregations. Put all aggregations to the HashMap "aggregations" 
	 * @throws DataException
	 */
	private void populateAggregations( ) throws DataException
	{
		aggregations = new HashMap();
		populateBuiltInAggregations( );
		populateExtendedAggregations( );
	}

	/**
	 * populate the built-in Aggregations
	 */
	private void populateBuiltInAggregations( )
	{
		String[] builtInAggrNames = BuiltInAggregationFactory.getInstance( )
				.getAggregationNames( );
		for ( int i = 0; i < builtInAggrNames.length; i++ )
		{
			aggregations.put( builtInAggrNames[i],
					BuiltInAggregationFactory.getInstance( )
							.getAggregation( builtInAggrNames[i] ) );
		}
	}

	/**
	 * Load aggregation extensions from runtime environment.
	 * @throws DataException 
	 * @throws FrameworkException 
	 */
	private void populateExtendedAggregations( ) throws DataException 
	{
		IExtensionRegistry extReg = Platform.getExtensionRegistry( );

		IExtensionPoint extPoint = extReg.getExtensionPoint( EXTENSION_POINT );

		if ( extPoint == null )
			return;

		IExtension[] exts = extPoint.getExtensions( );
		if ( exts == null )
			return;

		for ( int e = 0; e < exts.length; e++ )
		{
			IConfigurationElement[] configElems = exts[e].getConfigurationElements( );
			if ( configElems == null )
				continue;

			for ( int i = 0; i < configElems.length; i++ )
			{
				if ( configElems[i].getName( ).equals( ELEMENT_AGGREGATIONS ) )
				{
					IConfigurationElement[] subElems = configElems[i].getChildren( ELEMENT_AGGREGATION );
					for ( int j = 0; j < subElems.length; j++ )
					{

						String name = subElems[j].getAttribute( ATTRIBUTE_AGGREGATION_NAME );

						try
						{
							if ( aggregations.put( name.toUpperCase( ).trim( ),
									subElems[j].createExecutableExtension( ATTRIBUTE_AGGREGATION_CLASS ) ) != null )
								throw new DataException( ResourceConstants.DUPLICATE_AGGREGATION_NAME,
										name );
						}
						catch ( FrameworkException exception )
						{
							DataException ep = new DataException( ResourceConstants.CANNOT_INSTANTIATE_AGGREGATION_FACTORY,
									name );
							throw ep;
						}
					}
				}
			}
		}
	}
	
	/**
	 * Return an IAggregation instance according to the given aggregation name
	 * @param name the name of the aggregation
	 * @return an IAggregation instance specified by the give named
	 */
	public IAggregation getAggregation( String name )
	{
		return (IAggregation) aggregations.get( name.toUpperCase( ).trim( ) );
	}

}
