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

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

import org.eclipse.birt.data.engine.aggregation.RunningAccumulator;
import org.eclipse.birt.data.engine.core.DataException;

/**
 * The most common part of all Top and Bottom accumulator.
 * 
 */
public abstract class BaseTopBottomAccumulator extends RunningAccumulator {

	//
	protected List cachedValues;
	 
	private double N;
	private int passNo = 0;
	private int[] targetValue = new int[0];
	private int currentIndex = -1;
	private Object value = null;
	private static Boolean trueValue = new Boolean(true);
	private static Boolean falseValue = new Boolean(false);
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.data.engine.api.aggregation.Accumulator#start()
	 */
	public void start( ) throws DataException
	{
		super.start( );
		passNo++;
		
		if (passNo == 1) {
			cachedValues = new ArrayList();
			N = -1;
		}
		else
		{
			this.targetValue = this.getTargetValueIndex();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.data.engine.aggregation.SummaryAccumulator#getSummaryValue()
	 */
	private int[] getTargetValueIndex( ) throws DataException
	{
		int n = adjustNValue( N );
		int[] result = new int[(int) (n < cachedValues.size()?n:cachedValues.size())];
	
		
		for ( int i = 0; i < n && i < cachedValues.size( ); i++ )
		{
			int ind = getNextIndex( );
			if ( ind == -1 )
				return result;

			result[i] = ind;
		}
		this.cachedValues = null;
		return result;
	}
	
	public Object getValue( ) throws DataException
	{
		return value;
	}
	

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.data.engine.aggregation.Accumulator#onRow(java.lang.Object[])
	 */
	public void onRow( Object[] args ) throws DataException
	{
		assert ( args.length == 2 );
		if( passNo == 1)
		{	
			if ( args[0] != null )
			{
				cachedValues.add( args[0] );
			}else
			{
				cachedValues.add( RankAggregationUtil.getNullObject( ) );
			}
			if ( N == -1 )
			{
				N = populateNValue( args[1] );
			}
		}else
		{
			this.currentIndex ++;
			this.value = populateValue();
		}
	}
	
	/**
	 * Populate the return value.
	 * @return
	 */
	private Boolean populateValue( )
	{
		for( int i = 0; i < this.targetValue.length; i++ )
		{
			if( this.currentIndex == this.targetValue[i] )
				return trueValue;
		}
		
		return falseValue;
	}
	
	/**
	 * Get index of next topmost or bottommost value in cachedValues.
	 * @return
	 * @throws DataException
	 */
	protected abstract int getNextIndex( ) throws DataException;
	
	/**
	 * Populate the N value get from argument.
	 * 
	 * @param N
	 * @return
	 * @throws DataException
	 */
	protected abstract double populateNValue( Object N ) throws DataException;
	
	/**
	 * Adjust the N value.
	 * 
	 * @param N
	 * @return
	 */
	protected abstract int adjustNValue( double N );
}
