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

import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.eclipse.birt.data.engine.api.IGroupDefinition;
import org.eclipse.birt.data.engine.api.ISortDefinition;
import org.eclipse.birt.data.engine.core.DataException;
import org.eclipse.birt.data.engine.executor.cache.SortSpec;
import org.eclipse.birt.data.engine.i18n.ResourceConstants;
import org.eclipse.birt.data.engine.impl.ColumnInfo;
import org.eclipse.birt.data.engine.impl.QueryExecutorUtil;
import org.eclipse.birt.data.engine.odi.IQuery;
import org.eclipse.birt.data.engine.odi.IResultClass;
import org.eclipse.birt.data.engine.odi.IQuery.GroupSpec;
import org.mozilla.javascript.Context;

import com.ibm.icu.text.Collator;

/**
 * Some util methods used in viewing
 */
public class ViewingUtil
{
	/**
	 * @param sorts
	 * @return
	 */
	public static List getSortList( List sorts, Context cx )
	{
		IQuery.SortSpec[] sortSpecs = null;
		if ( sorts != null && sorts.size( ) > 0 )
		{
			sortSpecs = new IQuery.SortSpec[sorts.size( )];
			Iterator it = sorts.iterator( );
			for ( int i = 0; it.hasNext( ); i++ )
			{
				ISortDefinition src = (ISortDefinition) it.next( );
				int sortIndex = -1;
				String sortKey = src.getColumn( );
				if ( sortKey == null || sortKey.length( ) == 0 )
				{
					// Firstly try to treat sort key as a column reference
					// expression
					ColumnInfo columnInfo = QueryExecutorUtil.getColInfoFromJSExpr( cx,
							src.getExpression( ).getText( ) );

					sortIndex = columnInfo.getColumnIndex( );
					sortKey = columnInfo.getColumnName( );
				}
				IQuery.SortSpec dest = new IQuery.SortSpec( sortIndex,
						sortKey,
						src.getSortDirection( ) == ISortDefinition.SORT_ASC,
						src.getSortStrength( ) == -1 ? null
								: Collator.getInstance( ) );
				sortSpecs[i] = dest;
			}
		}
		if ( sortSpecs == null )
			return null;
		else
			return Arrays.asList( sortSpecs );
		
	}
	
	/**
	 * @param groupDefs
	 * @param sortDefns
	 * @param rsMeta
	 * @return
	 * @throws DataException
	 */
	public static SortSpec getSortSpec( GroupSpec[] groupDefns,
			IQuery.SortSpec[] sortDefns, IResultClass rsMeta )
			throws DataException
	{
		// Create an array of column indexes. We first sort by Group keys, then
		// sort keys
		int groupCount = 0;
		int sortCount = 0;
		
		if ( groupDefns != null )
		{
			for ( int i = 0; i < groupDefns.length; i++ )
			{
				// When group column is rowid, sort on it should not
				// take effect.
				if ( groupDefns[i].getKeyIndex( ) >= 0 )
				{
					groupCount++;
				}
			}
		}

		if ( sortDefns != null )
		{
			sortCount = sortDefns.length;
		}

		boolean doGroupSort = false;
		for( int i = 0; i < groupCount; i++ )
		{
			if( groupDefns[i].getSortDirection( ) != IQuery.NO_SORT_BEFORE_GROUPING )
			{
				doGroupSort = true;
				break;
			}
		}
		
		if( !doGroupSort )
			groupCount = 0;
		
		int[] sortKeyIndexes = new int[groupCount + sortCount];
		String[] sortKeyNames = new String[groupCount + sortCount];
		boolean[] sortAscending = new boolean[groupCount + sortCount];
		Comparator[] comparator = new Comparator[groupCount + sortCount];
		for ( int i = 0; i < groupCount; i++ )
		{
			int index = groupDefns[i].getKeyIndex( );
			if ( index >= 0 )
			{
				sortKeyIndexes[i] = groupDefns[i].getKeyIndex( );
				sortKeyNames[i] = groupDefns[i].getKeyColumn( );
				sortAscending[i] = groupDefns[i].getSortDirection( ) != IGroupDefinition.SORT_DESC;
			}
		}
		for ( int i = 0; i < sortCount; i++ )
		{
			int keyIndex = sortDefns[i].getIndex( );
			String keyName = sortDefns[i].getField( );

			// If sort key name exist (not null) then depend on key name, else
			// depend on key index
			if ( keyName != null )
				keyIndex = rsMeta.getFieldIndex( keyName );

			if ( keyIndex < 1 || keyIndex > rsMeta.getFieldCount( ) )
				// Invalid sort key name
				throw new DataException( ResourceConstants.INVALID_KEY_COLUMN,
						keyName );
			
			sortKeyIndexes[groupCount + i] = keyIndex;
			sortKeyNames[groupCount + i] = sortDefns[i].getField( );
			sortAscending[groupCount + i] = sortDefns[i].isAscendingOrder( );
			comparator[groupCount + i] = sortDefns[i].getComparator( );
		}

		return new SortSpec( sortKeyIndexes, sortKeyNames, sortAscending, comparator );
	}

}
