/*******************************************************************************
 * 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.data.engine.impl;

import java.util.Collection;

import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.data.engine.api.DataEngineContext;
import org.eclipse.birt.data.engine.api.IQueryDefinition;
import org.eclipse.birt.data.engine.api.ISubqueryDefinition;
import org.eclipse.birt.data.engine.core.DataException;
import org.eclipse.birt.data.engine.executor.cache.ResultSetCache;
import org.eclipse.birt.data.engine.impl.aggregation.AggregateTable;
import org.eclipse.birt.data.engine.impl.document.QueryResultInfo;
import org.eclipse.birt.data.engine.impl.document.RDGroupUtil;
import org.eclipse.birt.data.engine.impl.document.RDLoadUtil;
import org.eclipse.birt.data.engine.impl.document.StreamWrapper;
import org.eclipse.birt.data.engine.impl.document.SubQueryIndexUtil;
import org.eclipse.birt.data.engine.impl.document.stream.StreamManager;
import org.eclipse.birt.data.engine.impl.document.viewing.CachedSubExprResultSet;
import org.eclipse.birt.data.engine.impl.document.viewing.JSIVRowObject;
import org.eclipse.birt.data.engine.impl.document.viewing.NewInstanceHelper;
import org.eclipse.birt.data.engine.odi.IDataSource;
import org.eclipse.birt.data.engine.odi.IEventHandler;
import org.eclipse.birt.data.engine.odi.IQuery;
import org.eclipse.birt.data.engine.odi.IResultClass;
import org.eclipse.birt.data.engine.odi.IResultIterator;
import org.eclipse.birt.data.engine.odi.IResultObject;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

/**
 * 
 */
public class PreparedIVSubQuery extends PreparedDataSourceQuery
		implements
			IPreparedQueryService
{
	private String subQueryName;
	
	private String basedQueryResultID;
	
	//
	private Scriptable sharedScope;	
	private DataEngineContext dataEngineContext;
	private DataEngineSession session;
	
	private int parentIndex;
	
	private SubQueryIndexUtil subQueryManager;
	
	private int groupLevel;
	
	/**
	 * @param dataEngine
	 * @param queryDefn
	 * @param dataSetDesign
	 * @param appContext
	 * @throws DataException
	 */
	PreparedIVSubQuery( DataEngineImpl dataEngine, Scriptable scope,
			IQueryDefinition queryDefn, String basedQueryResultID,
			ISubqueryDefinition subQueryDefn, int groupLevel, int parentIndex,
			SubQueryIndexUtil subQueryManager ) throws DataException
	{
		super( dataEngine, subQueryDefn, queryDefn, null, null );

		this.dataEngineContext = dataEngine.getContext( );
		this.session = dataEngine.getSession( );
		this.basedQueryResultID = basedQueryResultID;
		this.subQueryName = subQueryDefn.getName( );
		this.parentIndex = parentIndex;

		this.sharedScope = scope;
		this.subQueryManager = subQueryManager;
		
		this.groupLevel = groupLevel;
	}

	/**
	 * @return
	 */
	public int getGroupLevel( )
	{
		return this.groupLevel;
	}
	
	/*
	 * @see org.eclipse.birt.data.engine.api.IPreparedQuery#getParameterMetaData()
	 */
	public Collection getParameterMetaData( ) throws BirtException
	{
		return null;
	}
	
	/*
	 * @see org.eclipse.birt.data.engine.impl.PreparedDataSourceQuery#newExecutor()
	 */
	protected QueryExecutor newExecutor( )
	{
		Scriptable queryScope;
		Context cx = Context.enter( );
		try
		{
			queryScope = cx.newObject( sharedScope );
			queryScope.setParentScope( sharedScope );
			queryScope.setPrototype( sharedScope );
		}
		finally
		{
			Context.exit( );
		}
		return new IVExecutor( queryScope );
	}
	
	/**
	 * Excutor for viewing
	 */
	private class IVExecutor extends QueryExecutor
	{
		/** */
		private Scriptable queryScope;		
		private JSIVRowObject ivRowObject;
		
		public IVExecutor( Scriptable queryScope )
		{
			super( queryScope, queryDefn, new AggregateTable( ), session );
			this.queryScope = queryScope;
		}
		
		/*
		 * @see org.eclipse.birt.data.engine.impl.PreparedQuery.Executor#createOdiDataSource()
		 */
		protected IDataSource createOdiDataSource( ) throws DataException
		{
			return NewInstanceHelper.newDataSource( );
		}

		/*
		 * @see org.eclipse.birt.data.engine.impl.PreparedQuery.Executor#findDataSource()
		 */
		protected DataSourceRuntime findDataSource( ) throws DataException
		{			
			return NewInstanceHelper.newDataSourceRuntime( queryScope );
		}

		/*
		 * @see org.eclipse.birt.data.engine.impl.PreparedQuery.Executor#newDataSetRuntime()
		 */
		protected DataSetRuntime newDataSetRuntime( ) throws DataException
		{
			return new DataSetRuntime( NewInstanceHelper.newDataSetDesign( ),
					this ) {
				/*
				 * @see org.eclipse.birt.data.engine.impl.DataSetRuntime#getScriptScope()
				 */
				public Scriptable getScriptScope( )
				{
					return queryScope;
				}
			};
		}

		/*
		 * @see org.eclipse.birt.data.engine.impl.PreparedQuery.Executor#createOdiQuery()
		 */
		protected IQuery createOdiQuery( ) throws DataException
		{
			return NewInstanceHelper.newOdiQuery( );
		}
		
		/*
		 * @see org.eclipse.birt.data.engine.impl.PreparedQuery.Executor#populateOdiQuery()
		 */
		protected void populateOdiQuery( )
		{
		}
		
		/*
		 * @see org.eclipse.birt.data.engine.impl.QueryExecutor#getQueryScope()
		 */
		public Scriptable getQueryScope( )
		{
			return queryScope;
		}
		
		/*
		 * @see org.eclipse.birt.data.engine.impl.PreparedQuery.Executor#executeOdiQuery()
		 */
		protected IResultIterator executeOdiQuery( IEventHandler eventHandler )
				throws DataException
		{					
			if( parentIndex == -1 )
				return new IResultIterator(){

					public void close( )
					{
						// TODO Auto-generated method stub
						
					}

					public void doSave( StreamWrapper streamsWrapper, boolean isSubQuery ) throws DataException
					{
						// TODO Auto-generated method stub
						
					}

					public void first( int groupingLevel ) throws DataException
					{
						// TODO Auto-generated method stub
						
					}

					public int getCurrentGroupIndex( int groupLevel ) throws DataException
					{
						// TODO Auto-generated method stub
						return 0;
					}

					public IResultObject getCurrentResult( ) throws DataException
					{
						// TODO Auto-generated method stub
						return null;
					}

					public int getCurrentResultIndex( ) throws DataException
					{
						// TODO Auto-generated method stub
						return -1;
					}

					public int getEndingGroupLevel( ) throws DataException
					{
						// TODO Auto-generated method stub
						return 0;
					}

					public IExecutorHelper getExecutorHelper( )
					{
						// TODO Auto-generated method stub
						return null;
					}

					public int[] getGroupStartAndEndIndex( int groupLevel ) throws DataException
					{
						// TODO Auto-generated method stub
						return null;
					}

					public IResultClass getResultClass( ) throws DataException
					{
						// TODO Auto-generated method stub
						return null;
					}

					public ResultSetCache getResultSetCache( )
					{
						// TODO Auto-generated method stub
						return null;
					}

					public int getRowCount( ) throws DataException
					{
						// TODO Auto-generated method stub
						return 0;
					}

					public int getStartingGroupLevel( ) throws DataException
					{
						// TODO Auto-generated method stub
						return 0;
					}

					public void last( int groupingLevel ) throws DataException
					{
						// TODO Auto-generated method stub
						
					}

					public boolean next( ) throws DataException
					{
						// TODO Auto-generated method stub
						return false;
					}};
			StreamManager streamManager = new StreamManager( dataEngineContext,
					new QueryResultInfo( basedQueryResultID,
							subQueryName,
							subQueryManager.getOldGroupInstanceIndex( parentIndex ) ) );
			
			RDGroupUtil rdGroupUtil = RDLoadUtil.loadGroupUtil( streamManager,
					StreamManager.SUB_QUERY_STREAM,
					StreamManager.ROOT_STREAM );	
			CachedSubExprResultSet resultIterator = new CachedSubExprResultSet( streamManager,
					subQueryManager,
					parentIndex,
					rdGroupUtil, session );
			
			ivRowObject = new JSIVRowObject( );
			this.queryScope.put( "row", this.queryScope, ivRowObject );
			ivRowObject.setResultSetIterator( resultIterator );
			
			return resultIterator;
		}
	}
	
}
