/*
 *************************************************************************
 * 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.oda.adapter.dtp;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.birt.core.framework.IBundle;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.datatools.connectivity.oda.IConnection;
import org.eclipse.datatools.connectivity.oda.IDriver;
import org.eclipse.datatools.connectivity.oda.LogConfiguration;
import org.eclipse.datatools.connectivity.oda.OdaException;
import org.eclipse.datatools.connectivity.oda.util.manifest.ExtensionManifest;
import org.eclipse.datatools.connectivity.oda.util.manifest.JavaRuntimeInterface;
import org.eclipse.datatools.connectivity.oda.util.manifest.ManifestExplorer;
import org.eclipse.datatools.connectivity.oda.util.manifest.RuntimeInterface;

/**
 * Driver is the DTP ODA adapter for the BIRT ODA driver interface IDriver.
 */
public class Driver implements IDriver
{
    private org.eclipse.birt.data.oda.IDriver m_birtDriver = null;   
    private org.eclipse.birt.data.oda.LogConfiguration m_birtLogConfig = null;
    
    private static final String sm_className = Driver.class.getName();
    private static final String sm_packageName = Driver.class.getPackage().getName();
    private static Logger sm_logger = Logger.getLogger( sm_packageName );

    /**
     * ODA DTP-to-BIRT adapter entry point.
     * @throws OdaException		if data source error occurs.
     */
    public Driver() throws OdaException
    {
    }

	/* (non-Javadoc)
	 * @see org.eclipse.datatools.connectivity.oda.IDriver#getConnection(java.lang.String)
	 */
	public IConnection getConnection( String dataSourceId )
		throws OdaException
	{
	    if ( m_birtDriver == null )
	    {
	        m_birtDriver = newBirtDriver( dataSourceId );

			// setLogConfiguration may have been called before m_birtDriver was initialized;
			// if any logConfig is cached, call underlying driver's setLogConfiguration now.
			doSetLogConfiguration();
	    }

	    // wraps and returns the connection provided by the
	    // underlying BIRT ODA driver
		try
        {
            return new Connection( m_birtDriver.getConnection( dataSourceId ) );
        }
        catch( org.eclipse.birt.data.oda.OdaException e )
        {
            throw new OdaAdapterException( e );
        }
	}

	/*
	 * Instantiate new BIRT ODA driver instance for given data source id.
	 */
	private org.eclipse.birt.data.oda.IDriver newBirtDriver( String dataSourceId ) 
		throws OdaException
	{
	    try
        {		    
		    // look up the BIRT ODA driver class name from its manifest
		    ExtensionManifest manifest = 
		        ManifestExplorer.getInstance().getExtensionManifest( dataSourceId, 
		            "org.eclipse.birt.data.oda.dataSource" );
		    
		    RuntimeInterface runtime = manifest.getRuntimeInterface();
		    assert( runtime instanceof JavaRuntimeInterface );
		    JavaRuntimeInterface javaRuntime = (JavaRuntimeInterface) runtime;
		    String driverClassName = javaRuntime.getDriverClass();

		    // instantiate the BIRT ODA driver's class
			IBundle bundle = Platform.getBundle( manifest.getNamespace() );			
			Class driverClass = bundle.loadClass( driverClassName );
			Object driverInstance = driverClass.newInstance();
			
			// verify that the custom BIRT ODA driver manifest has specified the 
			// correct class name that implements IDriver
			if( driverInstance instanceof org.eclipse.birt.data.oda.IDriver )
				return ( org.eclipse.birt.data.oda.IDriver ) driverInstance;
			    
			throw new IllegalArgumentException( driverClassName );	
        }
        catch( Exception ex )
        {
            final String errorMsg = "Not able to instantiate custom BIRT ODA driver class.";
            sm_logger.logp( Level.SEVERE, sm_className, 
                    "newBirtDriver", errorMsg );

            // TODO - localized user message
            throw new OdaAdapterException( errorMsg, ex );
        }
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.datatools.connectivity.oda.IDriver#getMaxConnections()
	 */
	public int getMaxConnections()
		throws OdaException
	{
	    // the underlying BIRT ODA driver is not yet known, probably
	    // because this method is called before getConnection
	    if ( m_birtDriver == null )
	    {
		    sm_logger.logp( Level.WARNING, sm_className, 
                    "getMaxConnections", "Unknown underlying BIRT driver- unknown maximum connections." );
	        return 0;
	    }

	    // get info from underlying BIRT ODA driver
	    try
        {
		    return m_birtDriver.getMaxConnections();
        }
        catch( org.eclipse.birt.data.oda.OdaException e )
        {
            throw new OdaAdapterException( e );
        }
	}
	
	/*
	 * @see org.eclipse.datatools.connectivity.oda.IDriver#setAppContext(java.lang.Object)
	 */
	public void setAppContext( Object context ) throws OdaException
	{
	    // do nothing; ODA 2.0 driver does not support pass-through context
	}	

	/* (non-Javadoc)
	 * @see org.eclipse.datatools.connectivity.oda.IDriver#setLogConfiguration(org.eclipse.datatools.connectivity.oda.LogConfiguration)
	 */
	public void setLogConfiguration( LogConfiguration logConfig )
		throws OdaException
	{
	    // converts to BIRT log configuration instance;
	    // overrides any existing instance not passed thru yet
	    m_birtLogConfig =
	        new org.eclipse.birt.data.oda.LogConfiguration( 
	                logConfig.getDataSourceId(),
	                logConfig.getLogLevel(),
	                logConfig.getLogDirectory(),
	                logConfig.getLogPrefix(),
	                logConfig.getFormatterClassName() );

	    // now attempt to pass it thru to underlying BIRT driver
		doSetLogConfiguration();
	}
	
	/*
	 * Pass previously specified log configuration to the
	 * underlying BIRT ODA driver, if known.
	 */
	private void doSetLogConfiguration() throws OdaException
	{
	    // if underlying BIRT driver is not initialized yet, or
	    // no log configuration is specified, 
	    // cannot pass thru at this point, do nothing now
	    if ( m_birtDriver == null || m_birtLogConfig == null )
	    {
		    sm_logger.logp( Level.INFO, sm_className, 
                    "doSetLogConfiguration", "Un-initialized BIRT driver, or no log configuration to pass through." );
	        return;
	    }
	    
	    // ok to pass previously specified log configuration to the
	    // underlying BIRT ODA driver
	    
	    // first reset variable, so it won't be passed again,
	    // even if an error occurs
	    org.eclipse.birt.data.oda.LogConfiguration logConfig = m_birtLogConfig;
	    m_birtLogConfig = null;
	    
        try
        {
            m_birtDriver.setLogConfiguration( logConfig );
        }
        catch( org.eclipse.birt.data.oda.OdaException e )
        {
            throw new OdaAdapterException( e );
        }
	}
	
}