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

import java.util.ArrayList;
import java.util.List;

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.report.model.api.elements.ReportDesignConstants;
import org.eclipse.birt.report.model.api.extension.IResourceBundleProvider;
import org.eclipse.birt.report.model.api.metadata.IElementDefn;
import org.eclipse.birt.report.model.api.metadata.PropertyValueException;
import org.eclipse.birt.report.model.api.util.StringUtil;
import org.eclipse.birt.report.model.extension.DefaultMessages;

/**
 * Represents the extension loader for add-on extension.
 * @deprecated odaDriverModel has been removed; do not use this class - gxue 2005-5-19
 */

public class AddOnExtensionLoader extends ExtensionLoader
{

	/**
	 * The name of extension point
	 */

	public static final String EXTENSION_POINT = "org.eclipse.birt.report.model.odaDriverModel"; //$NON-NLS-1$

	/**
	 */
	public AddOnExtensionLoader( )
	{
		super( EXTENSION_POINT );
	}

	private static final String ODA_DATA_SOURCE_TAG = "odaDataSource"; //$NON-NLS-1$
	private static final String ODA_DATA_SET_TAG = "odaDataSet"; //$NON-NLS-1$

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.model.metadata.ExtensionLoader#loadExtension(org.eclipse.birt.core.framework.IExtension)
	 */

	void loadExtension( IExtension extension ) throws ExtensionException,
			MetaDataException
	{
		IConfigurationElement[] configElements = extension
				.getConfigurationElements( );

		AddOnExtensionElementLoader dataSourceLoader = new AddOnExtensionElementLoader(
				extension, ReportDesignConstants.ODA_DATA_SOURCE );
		AddOnExtensionElementLoader dataSetLoader = new AddOnExtensionElementLoader(
				extension, ReportDesignConstants.ODA_DATA_SET );

		for ( int i = 0; i < configElements.length; i++ )
		{
			IConfigurationElement currentTag = configElements[i];
			if ( ODA_DATA_SOURCE_TAG.equals( currentTag.getName( ) ) )
			{
				dataSourceLoader.loadElement( currentTag );
			}
			else if ( ODA_DATA_SET_TAG.equals( currentTag.getName( ) ) )
			{
				dataSetLoader.loadElement( currentTag );
			}
		}
	}

	class AddOnExtensionElementLoader extends ExtensionElementLoader
	{

		static final String RESOURCE_BUNDLE_PROVIDER_ATTRIB = "resourceBundleProvider"; //$NON-NLS-1$

		String baseElementName;

		DefaultMessages messages = null;

		AddOnExtensionElementLoader( IExtension extension,
				String baseElementName )
		{
			super( extension );

			this.baseElementName = baseElementName;
		}

		/**
		 * Loads the extension element definition and its properties.
		 * 
		 * @param elementTag
		 *            the element tag
		 * @throws MetaDataException
		 *             if error encountered when adding the element to metadata
		 *             dictionary.
		 * @throws ExtensionException
		 *             if the class some attribute specifies can not be
		 *             instanced.
		 */

		void loadElement( IConfigurationElement elementTag )
				throws MetaDataException, ExtensionException
		{
			String extensionName = elementTag
					.getAttribute( EXTENSION_NAME_ATTRIB );
			String className = elementTag
					.getAttribute( RESOURCE_BUNDLE_PROVIDER_ATTRIB );

			checkRequiredAttribute( EXTENSION_NAME_ATTRIB, extensionName );

			IElementDefn baseElementDefn = MetaDataDictionary.getInstance( )
					.getElement( baseElementName );
			assert baseElementDefn != null;

			if ( !StringUtil.isBlank( className ) )
			{
				try
				{
					IResourceBundleProvider provider = (IResourceBundleProvider) elementTag
							.createExecutableExtension( RESOURCE_BUNDLE_PROVIDER_ATTRIB );

					messages = new DefaultMessages( provider );
				}
				catch ( FrameworkException e )
				{
					throw new ExtensionException(
							new String[]{className},
							ExtensionException.DESIGN_EXCEPTION_FAILED_TO_CREATE_INSTANCE );
				}
			}

			ExtensionElementDefn elementDefn = new AddOnExtensionElementDefn(
					extensionName, baseElementDefn );

			List propList = new ArrayList( );

			IConfigurationElement[] elements = elementTag.getChildren( );
			for ( int i = 0; i < elements.length; i++ )
			{
				if ( PROPERTY_TAG.equalsIgnoreCase( elements[i].getName( ) ) )
				{
					SystemPropertyDefn extPropDefn = loadProperty( elementTag,
							elements[i], elementDefn );
					// Unique check is performed in addProperty()
					elementDefn.addProperty( extPropDefn );
				}
				else if ( PROPERTY_VISIBILITY_TAG.equalsIgnoreCase( elements[i]
						.getName( ) ) )
				{
					loadPropertyVisibility( elements[i], elementDefn );
				}
				else if ( PROPERTY_GROUP_TAG.equalsIgnoreCase( elements[i]
						.getName( ) ) )
				{
					loadPropertyGroup( elementTag, elements[i], elementDefn,
							propList );
				}
			}
			elementDefn.extensionPoint = EXTENSION_POINT;
			MetaDataDictionary.getInstance( ).addExtension( elementDefn );
		}

		/**
		 * Loads one property definition of the given element.
		 * 
		 * @param elementTag
		 *            the element tag
		 * @param propTag
		 *            the property tag
		 * @param elementDefn
		 *            element definition
		 * 
		 * @return the property definition
		 * @throws ExtensionException
		 *             if the class some attribute specifies can not be
		 *             instanced.
		 */

		ExtensionPropertyDefn loadProperty( IConfigurationElement elementTag,
				IConfigurationElement propTag, ExtensionElementDefn elementDefn )
				throws ExtensionException
		{
			String name = propTag.getAttribute( NAME_ATTRIB );
			String displayNameID = propTag
					.getAttribute( DISPLAY_NAME_ID_ATTRIB );
			String type = propTag.getAttribute( TYPE_ATTRIB );
			String canInherit = propTag.getAttribute( CAN_INHERIT_ATTRIB );
			String defaultValue = propTag.getAttribute( DEFAULT_VALUE_ATTRIB );
			String isEncrypted = propTag.getAttribute( IS_ENCRYPTABLE_ATTRIB );
			String defaultDisplayName = propTag
					.getAttribute( DEFAULT_DISPLAY_NAME_ATTRIB );

			checkRequiredAttribute( NAME_ATTRIB, name );
			checkRequiredAttribute( TYPE_ATTRIB, type );

			PropertyType propType = MetaDataDictionary.getInstance( )
					.getPropertyType( type );
			if ( propType == null )
				throw new ExtensionException(
						new String[]{type},
						ExtensionException.DESIGN_EXCEPTION_INVALID_PROPERTY_TYPE );
			
			if ( propType.getTypeCode( ) != PropertyType.STRING_TYPE
					&& propType.getTypeCode( ) != PropertyType.CHOICE_TYPE )
			{
				throw new ExtensionException(
						new String[]{type},
						ExtensionException.DESIGN_EXCEPTION_INVALID_PROPERTY_TYPE );
			}

			ExtensionPropertyDefn extPropDefn = null;

			extPropDefn = new ExtensionPropertyDefn( messages );
			extPropDefn.setName( name );
			extPropDefn.setDisplayNameID( displayNameID );
			extPropDefn.setType( propType );
			try
			{
				Object value = extPropDefn.validateXml( null, defaultValue );
				extPropDefn.setDefault( value );
			}
			catch ( PropertyValueException e )
			{
				throw new ExtensionException(
						new String[]{defaultValue},
						ExtensionException.DESIGN_EXCEPTION_INVALID_DEFAULT_VALUE );
			}
			
			extPropDefn.setIntrinsic( false );
			extPropDefn.setStyleProperty( false );
			extPropDefn.setDefaultDisplayName( defaultDisplayName );

			if ( !StringUtil.isBlank( canInherit ) )
				extPropDefn.setCanInherit( Boolean.valueOf( canInherit )
						.booleanValue( ) );

			if ( !StringUtil.isBlank( isEncrypted ) )
				extPropDefn.setIsEncryptable( Boolean.valueOf( isEncrypted )
						.booleanValue( ) );

			List choiceList = new ArrayList( );

			IConfigurationElement[] elements = propTag.getChildren( );
			for ( int k = 0; k < elements.length; k++ )
			{
				if ( CHOICE_TAG.equalsIgnoreCase( elements[k].getName( ) ) )
				{
					ExtensionChoice choiceDefn = new ExtensionChoice( null );
					loadChoice( elements[k], choiceDefn, extPropDefn );
					choiceList.add( choiceDefn );
				}
			}

			if ( choiceList.size( ) > 0 )
			{
				Choice[] choices = new Choice[choiceList.size( )];
				choiceList.toArray( choices );
				ChoiceSet choiceSet = new ChoiceSet( );
				choiceSet.setChoices( choices );
				extPropDefn.setDetails( choiceSet );
			}

			return extPropDefn;
		}
	}

}