/*******************************************************************************
 * 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.report.designer.data.ui.util;

import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.model.adapter.oda.ModelOdaAdapter;
import org.eclipse.birt.report.model.api.ModuleHandle;
import org.eclipse.birt.report.model.api.OdaDataSetHandle;
import org.eclipse.birt.report.model.api.OdaDataSourceHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.datatools.connectivity.oda.OdaException;
import org.eclipse.datatools.connectivity.oda.design.DataSetDesign;
import org.eclipse.datatools.connectivity.oda.design.DataSourceDesign;
import org.eclipse.datatools.connectivity.oda.design.DesignFactory;
import org.eclipse.datatools.connectivity.oda.design.DesignSessionRequest;
import org.eclipse.datatools.connectivity.oda.design.DesignSessionResponse;
import org.eclipse.datatools.connectivity.oda.design.DesignerState;
import org.eclipse.datatools.connectivity.oda.design.SessionStatus;
import org.eclipse.emf.ecore.util.EcoreUtil;

/**
 * A Utility Class to handle procedures needed to be done <br>
 * before <code>edit</code> or after <code>finish</code>
 */

public class DTPUtil
{

	private static DTPUtil instance = null;
	private SessionStatus sessionStatus = null;
	private DesignerState designerState = null;
	private ModelOdaAdapter modelOdaAdapter = new ModelOdaAdapter( );
	private static final String SAMPELDB_DATA_SOURCE_ID = "org.eclipse.birt.report.data.oda.sampledb";
	private static final String JDBC_DATA_SOURCE_ID = "org.eclipse.birt.report.data.oda.jdbc";

	private DTPUtil( )
	{
	}

	public static synchronized DTPUtil getInstance( )
	{
		if ( instance == null )
			instance = new DTPUtil( );

		return instance;
	}

	/**
	 * update DataSourceHandle
	 * 
	 * @param response
	 * @param dataSourceHandle
	 * @throws OdaException
	 */
	public void updateDataSourceHandle( DesignSessionResponse response,
			OdaDataSourceHandle dataSourceHandle ) throws OdaException
	{
		if ( new EcoreUtil.EqualityHelper( ).equals( modelOdaAdapter.createDataSourceDesign( dataSourceHandle ),
				response.getDataSourceDesign( ) ) )
			return;
		
		initDesignSessionFields( response );
		isSessionOk( );

		try
		{
			updateROMDesignerState( dataSourceHandle );
			modelOdaAdapter.updateDataSourceHandle( response.getDataSourceDesign( ),
					dataSourceHandle );
		}
		catch ( SemanticException e )
		{
			ExceptionHandler.handle( e );
		}
	}

	/**
	 * update DataSetHandle
	 * 
	 * @param response
	 * @param dataSetHandle
	 * @param isSourceChanged
	 * @throws OdaException
	 */
	public void updateDataSetHandle( DesignSessionResponse response,
			OdaDataSetHandle dataSetHandle, boolean isSourceChanged )
			throws OdaException
	{
		if ( new EcoreUtil.EqualityHelper( ).equals( modelOdaAdapter.createDataSetDesign( dataSetHandle ),
				response.getDataSetDesign( ) ) )
			return;

		initDesignSessionFields( response );
		isSessionOk( );

		try
		{
			updateROMDesignerState( dataSetHandle );
			modelOdaAdapter.updateDataSetHandle( response.getDataSetDesign( ),
					dataSetHandle,
					isSourceChanged );
		}
		catch ( SemanticException e )
		{
			ExceptionHandler.handle( e );
		}
	}

	/**
	 * create OdaDataSourceHandle
	 * 
	 * @param response
	 * @param parentHandle
	 * @return
	 * @throws OdaException
	 * @throws SemanticException 
	 */
	public OdaDataSourceHandle createOdaDataSourceHandle(
			DesignSessionResponse response, ModuleHandle parentHandle )
			throws OdaException, SemanticException
	{
		initDesignSessionFields( response );
		isSessionOk( );

		DataSourceDesign dataSourceDesign = response.getDataSourceDesign( );
		if ( dataSourceDesign.getOdaExtensionId( )
				.equals( SAMPELDB_DATA_SOURCE_ID ) )
		{
			dataSourceDesign.setOdaExtensionId( JDBC_DATA_SOURCE_ID );
		}

		OdaDataSourceHandle dataSourceHandle = null;
		try
		{
			dataSourceHandle = modelOdaAdapter.createDataSourceHandle( dataSourceDesign,
					parentHandle );
			updateROMDesignerState( dataSourceHandle );
		}
		catch ( SemanticException e )
		{
			throw e;
		}

		return dataSourceHandle;
	}

	/**
	 * create OdaDataSetHandle
	 * 
	 * @param response
	 * @param parentHandle
	 * @return
	 * @throws OdaException
	 * @throws SemanticException 
	 */
	public OdaDataSetHandle createOdaDataSetHandle(
			DesignSessionResponse response, ModuleHandle parentHandle )
			throws OdaException, SemanticException
	{
		initDesignSessionFields( response );
		isSessionOk( );

		OdaDataSetHandle dataSetHandle = null;
		try
		{
			dataSetHandle = modelOdaAdapter.createDataSetHandle( response.getDataSetDesign( ),
					parentHandle );
			updateROMDesignerState( dataSetHandle );
		}
		catch ( SemanticException e )
		{
			throw e;
		}

		return dataSetHandle;
	}

	/**
	 * create DesignSessionRequest
	 * 
	 * @param dataSourceHandle
	 * @return
	 */
	public DesignSessionRequest createDesignSessionRequest(
			OdaDataSourceHandle dataSourceHandle )
	{
		DesignSessionRequest designSessionRequest = 
            DesignFactory.eINSTANCE.createDesignSessionRequest( 
                modelOdaAdapter.createDataSourceDesign( dataSourceHandle ) );

		designerState = modelOdaAdapter.newOdaDesignerState( dataSourceHandle );
		if ( designerState != null )
			designSessionRequest.setDesignerState( designerState );

		return designSessionRequest;
	}

	/**
	 * create DesignSessionRequest
	 * 
	 * @param dataSetHandle
	 * @return
	 */
	public DesignSessionRequest createDesignSessionRequest(
			OdaDataSetHandle dataSetHandle )
	{
		DataSetDesign dataSetDesign = modelOdaAdapter.createDataSetDesign( dataSetHandle );
		// To assure that query text is valid
		// if ( dataSetDesign != null && dataSetDesign.getQueryText( ) == null )
		// dataSetDesign.setQueryText( "" );

		return createDesignSessionRequest( dataSetDesign, 
                modelOdaAdapter.newOdaDesignerState( dataSetHandle ) );
	}

    /**
     * Create a DesignSessionRequest with the specified
     * dataSetDesign and designerState.
     * @param dataSetDesign
     * @param designerState
     * @return
     */
    public DesignSessionRequest createDesignSessionRequest(
            	DataSetDesign requestDataSetDesign, 
            	DesignerState requestDesignerState )
    {
        DesignSessionRequest newRequest = 
            DesignFactory.eINSTANCE.createDesignSessionRequest( requestDataSetDesign );

        designerState = requestDesignerState;
        newRequest.setDesignerState( requestDesignerState );

        return newRequest;
    }
    
	/**
	 * assign values to the fields of current session
	 * 
	 * @param response
	 * @throws OdaException
	 */
	private void initDesignSessionFields( DesignSessionResponse response )
	{
		sessionStatus = response.getSessionStatus( );
		designerState = response.getDesignerState( );
	}

	/**
	 * check the status of current session
	 * 
	 * @throws OdaException
	 */
	private void isSessionOk( ) throws OdaException
	{
		assert sessionStatus != null;

		if ( sessionStatus.getValue( ) != SessionStatus.OK )
			throw new OdaException( sessionStatus.getLiteral( ) );
	}

	/**
	 * update ROMDesignerState
	 * 
	 * @param obj
	 * @throws SemanticException
	 */
	private void updateROMDesignerState( Object obj ) throws SemanticException
	{
		if ( designerState == null || obj == null )
			return;

		if ( obj instanceof OdaDataSourceHandle )
			modelOdaAdapter.updateROMDesignerState( designerState,
					(OdaDataSourceHandle) obj );
		else if ( obj instanceof OdaDataSetHandle )
			modelOdaAdapter.updateROMDesignerState( designerState,
					(OdaDataSetHandle) obj );
	}

}
