/**
 * 
 * kingdee software corporation.ltd.2005. 
 * create date：2005-11-4 
 * author:ST 
 * version:1.0
 */

package com.kingdee.bos.streamwork.cuba.mdx.func;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.kingdee.bos.streamwork.cuba.Cube;
import com.kingdee.bos.streamwork.cuba.Dimension;
import com.kingdee.bos.streamwork.cuba.Hierarchy;
import com.kingdee.bos.streamwork.cuba.Level;
import com.kingdee.bos.streamwork.cuba.Member;
import com.kingdee.bos.streamwork.cuba.OLAPException;
import com.kingdee.bos.streamwork.cuba.base.EvaluatorImpl;
import com.kingdee.bos.streamwork.cuba.exception.TooManyMemberException;
import com.kingdee.bos.streamwork.cuba.mdx.Category;
import com.kingdee.bos.streamwork.cuba.mdx.Evaluator;
import com.kingdee.bos.streamwork.cuba.mdx.Exp;
import com.kingdee.bos.streamwork.cuba.mdx.Literal;
import com.kingdee.bos.streamwork.cuba.mdx.SchemaLookup;
import com.kingdee.bos.streamwork.cuba.mdx.SchemaReader;
import com.kingdee.bos.streamwork.cuba.mdx.Syntax;
import com.kingdee.bos.streamwork.cuba.mdx.calc.Calc;
import com.kingdee.bos.streamwork.cuba.mdx.type.ScalarType;
import com.kingdee.bos.streamwork.cuba.mdx.type.Type;
import com.kingdee.bos.streamwork.cuba.mdx.type.TypeUtil;
import com.kingdee.bos.streamwork.cuba.mem.Aggregator;
import com.kingdee.bos.streamwork.cuba.rel.FactMemberTupleReader;
import com.kingdee.bos.streamwork.cuba.rel.RelAggregator;
import com.kingdee.bos.streamwork.cuba.rel.RelConnectionImpl;
import com.kingdee.bos.streamwork.cuba.rel.RelCubeImpl;
import com.kingdee.bos.streamwork.cuba.rel.RelHierarchyImpl;
import com.kingdee.bos.streamwork.cuba.util.ArrayHolder;
import com.kingdee.bos.streamwork.cuba.util.BreakArrayCalcComparator;
import com.kingdee.bos.streamwork.cuba.util.BreakMemberComparator;
import com.kingdee.bos.streamwork.cuba.util.EnumeratedValues;
import com.kingdee.bos.streamwork.cuba.util.HierarchicalArrayCalcComparator;
import com.kingdee.bos.streamwork.cuba.util.HierarchicalMemberComparator;
import com.kingdee.bos.streamwork.cuba.util.HierarchizeArrayComparator;
import com.kingdee.bos.streamwork.cuba.util.HierarchizeComparator;
import com.kingdee.bos.streamwork.cuba.util.ObjectComparator;
import com.kingdee.bos.streamwork.cuba.util.ReverseComparator;
import com.kingdee.bos.streamwork.cuba.util.Sort;
import com.kingdee.bos.streamwork.cuba.util.Util;
import com.kingdee.bos.streamwork.cuba.util.ValueNotReadyException;

public class FuncUtil_bak extends Util
{

	static final String nl = System.getProperty("line.separator");

	static String getLiteralArg(Exp[] args, int i, String defaultValue, String[] allowedValues)
			throws OLAPException
	{
		if (i >= args.length)
		{
			return defaultValue;
		}
		Exp arg = args[i];
		if (!(arg instanceof Literal) || arg.getCategory() != Category.Symbol)
		{
			throw new OLAPException("Expected a symbol, found '" + arg + "'");
		}
		String s = (String) ((Literal) arg).getValueObject();
		StringBuffer sb = new StringBuffer(64);
		for (int j = 0; j < allowedValues.length; j++)
		{
			String allowedValue = allowedValues[j];
			if (allowedValue.equalsIgnoreCase(s))
			{
				return allowedValue;
			}
			if (j > 0)
			{
				sb.append(", ");
			}
			sb.append(allowedValue);
		}
		throw new OLAPException("Allowed values are: {" + sb + "}");
	}

	static int getLiteralArg(Exp[] args, int i, int defaultValue, EnumeratedValues allowedValues)
			throws OLAPException
	{
		final String literal = getLiteralArg(args, i, allowedValues.getName(defaultValue),
				allowedValues.getNames());
		return (literal == null) ? -1 : allowedValues.getOrdinal(literal);
	}

	/**
	static boolean getBooleanArg(Evaluator evaluator, Exp[] args, int index, boolean defaultValue)
			throws OLAPException
	{
		Object o = getArg(evaluator, args, index);
		return (o == null) ? defaultValue : ((Boolean) o).booleanValue();
	}

	static Object getBooleanArg(Evaluator evaluator, Exp[] args, int index) throws OLAPException
	{
		Object o = getArg(evaluator, args, index);
		return o;
	}
	*/
	/**
	// 保证该方法不可以返回ValueNotReadyException
	static int getIntArg(Evaluator evaluator, Exp[] args, int index) throws OLAPException
	{
		Object o = getScalarArg(evaluator, args, index);
		if (o instanceof Number)
		{
			return ((Number) o).intValue();
		}
		else if (o instanceof RuntimeException)
		{
			return 0;
		}
		else
		{
			String s = o.toString();
			double d = Double.valueOf(s).doubleValue();
			return (int) d;
		}
	}
	 */
	/**
	static Object getScalarArg(Evaluator evaluator, Exp[] args, int index) throws OLAPException
	{
		Object o = args[index].evaluateScalar(evaluator);

		return o;
	}
	 */
	
	/**
	static Object getDecimalArg(Evaluator evaluator, Exp[] args, int index, BigDecimal nullValue)
			throws OLAPException
	{
		Object o = getScalarArg(evaluator, args, index);
		if (o == null || o == Util.nullValue)
			return nullValue;
		else if (o instanceof ValueNotReadyException)
			return o;

		if (o instanceof BigDecimal)
		{
			return o;
		}
		else if (o instanceof Double)
		{
			Double d = (Double) o;
			if (d.isNaN() || d.isInfinite())
				return new BigDecimal(d.doubleValue());
			else
				return new BigDecimal(d.toString());
		}
		else if (o instanceof Float)
		{
			Float d = (Float) o;
			if (d.isNaN() || d.isInfinite())
				return new BigDecimal(d.doubleValue());
			else
				return new BigDecimal(d.toString());
		}
		else if (o instanceof Integer)
		{
			return new BigDecimal(o.toString());
		}
		else if (o instanceof BigInteger)
		{
			return new BigDecimal((BigInteger) o);
		}
		else if (o instanceof Number)
		{
			return new BigDecimal(((Number) o).doubleValue());
		}
		else if (o instanceof Throwable)
		{
			return nullValue;
		}
		else
		{
			StringBuffer err = new StringBuffer();
			err.append("Value").append(o).append(
					" cannot be converted to Number(BigDecimal).The value is executed by context:");
			Member[] context = evaluator.getCurrentMembers();
			err.append("\n");
			for (int i = 0; i < context.length; i++)
			{
				err.append(context[i].getUniqueName());
				err.append("\n");
			}

			throw Util.newInternal(err.toString());
		}
	}
	 */

	/**
	static Member getMemberArg(Evaluator evaluator, Exp[] args, int index, boolean fail)
			throws OLAPException
	{
		if (index >= args.length)
		{
			if (fail)
			{
				throw Util.newInternal("missing member argument");
			}
			else
			{
				return null;
			}
		}
		Exp arg = args[index];
		Object o = arg.evaluate(evaluator);

		if (o == null)
			return null;

		if (o instanceof Member)
		{
			return (Member) o;
		}
		else if (o instanceof Hierarchy)
		{
			return evaluator.getContext(((Hierarchy) o).getDimension());
		}
		else if (o instanceof Dimension)
		{
			return evaluator.getContext((Dimension) o);
		}
		else if (o == null && arg instanceof Literal && ((Literal) arg).isNull)
		{
			return null;
		}

		else
		{
			throw Util.newInternal("expecting a member, got " + o);
		}
	}
	
	public static Member[] getTupleArg(Evaluator evaluator, Exp[] args, int index)
			throws OLAPException
	{
		Exp arg = args[index];
		Object o = arg.evaluate(evaluator);
		return (Member[]) o;
	}

	public static Member[] getTupleOrMemberArg(Evaluator evaluator, Exp[] args, int index)
			throws OLAPException
	{
		Exp arg = args[index];
		Object o0 = arg.evaluate(evaluator);
		if (o0 instanceof Member[])
		{
			return (Member[]) o0;
		}
		else if (o0 instanceof Member)
		{
			return new Member[]{(Member) o0};
		}
		else
		{
			throw Util.newInternal("Expected tuple or member, got " + o0);
		}
	}

	static Level getLevelArg(Evaluator evaluator, Exp[] args, int index, boolean fail)
			throws OLAPException
	{
		if (index >= args.length)
		{
			if (fail)
			{
				throw Util.newInternal("missing level argument");
			}
			else
			{
				return null;
			}
		}
		Exp arg = args[index];
		Object o = arg.evaluate(evaluator);
		return (Level) o;
	}

	static Hierarchy getHierarchyArg(Evaluator evaluator, Exp[] args, int index, boolean fail)
			throws OLAPException
	{
		if (index >= args.length)
		{
			if (fail)
			{
				throw Util.newInternal("missing hierarchy argument");
			}
			else
			{
				return null;
			}
		}
		Exp arg = args[index];
		Object o = arg.evaluate(evaluator);
		if (o instanceof Hierarchy)
		{
			return (Hierarchy) o;
		}
		if (o instanceof Member)
		{
			return ((Member) o).getHierarchy();
		}
		else if (o instanceof Level)
		{
			return ((Level) o).getHierarchy();
		}
		else if (o instanceof Hierarchy)
		{
			return (Hierarchy) o;
		}
		else if (o instanceof Dimension)
		{
			return ((Dimension) o).getHierarchies()[0];
		}
		else
		{
			throw Util.newInternal("expecting a hierarchy, got " + o);
		}
	}

	static Dimension getDimensionArg(Evaluator evaluator, Exp[] args, int index, boolean fail)
			throws OLAPException
	{
		if (index >= args.length)
		{
			if (fail)
			{
				throw Util.newInternal("missing dimension argument");
			}
			else
			{
				return null;
			}
		}
		Exp arg = args[index];
		Object o = arg.evaluate(evaluator);
		if (true)
		{
			return (Dimension) o;
		}
		if (o instanceof Member)
		{
			return ((Member) o).getDimension();
		}
		else if (o instanceof Level)
		{
			return ((Level) o).getHierarchy().getDimension();
		}
		else if (o instanceof Hierarchy)
		{
			return ((Hierarchy) o).getDimension();
		}
		else if (o instanceof Dimension)
		{
			return (Dimension) o;
		}
		else
		{
			throw Util.newInternal("expecting a dimension, got " + o);
		}
	}
	*/
	public static boolean hasData(Member[] position)
	{
		for (int i = 0; i < position.length; i++)
		{
			if (!position[i].hasData())
				return false;
		}
		return true;
	}

	// if query has
	// 1."non fact empty" or
	// 2. "non empty" and the query has no calculated member
	public static Member[] nonFactEmptyMembers(Evaluator evaluator, Member[] members)
	{
		if (members == null || members.length == 0)
			return members;

		if (evaluator.isRolap())
		{
			if (evaluator.getAxisFactConstraint() != null)
			{
				return evaluator.getAxisFactConstraint().constraint(evaluator, members);
			}
		}
		else if (evaluator.isNonFactEmpty()
				|| (evaluator.isNonEmpty() && !evaluator.getQuery().hasFormulas()))
		{
			ArrayList list = new ArrayList();
			for (int i = 0; i < members.length; i++)
				if (members[i].hasData())
					list.add(members[i]);
			members = new Member[list.size()];
			list.toArray(members);
		}
		return members;
	}

	public static List nonFactEmptyMembers(Evaluator evaluator, List members)
	{
		if (members == null || members.size() == 0)
			return members;

		if (evaluator.isRolap())
		{
			if (evaluator.getAxisFactConstraint() != null)
			{
				return evaluator.getAxisFactConstraint().constraint(evaluator, members);
			}
		}
		else if (evaluator.isNonFactEmpty()
				|| (evaluator.isNonEmpty() && !evaluator.getQuery().hasFormulas()))
		{
			Object o = members.get(0);
			if (o instanceof Member)
			{
				for (Iterator iter = members.iterator(); iter.hasNext();)
				{
					Member m = (Member) iter.next();
					if (!m.hasData())
						iter.remove();
				}
			}
			else if (o instanceof Member[])
			{
				for (Iterator iter = members.iterator(); iter.hasNext();)
				{
					Member[] ms = (Member[]) iter.next();
					for (int i = 0; i < ms.length; i++)
					{
						if (!ms[i].hasData())
						{
							iter.remove();
							break;
						}
					}
				}
			}
		}
		return members;
	}

	static void checkCompatible(Exp left, Exp right, String funName) throws OLAPException
	{
		final Type leftType = TypeUtil.stripSetType(left.getType());
		final Type rightType = TypeUtil.stripSetType(right.getType());
		if (!TypeUtil.isUnionCompatible(leftType, rightType))
		{
			throw new OLAPException("Expressions " + funName + " must have the same hierarchy");
		}
	}


	public static boolean checkFlag(int value, int mask, boolean strict)
	{
		return (strict) ? ((value & mask) == mask) : ((value & mask) != 0);
	}

	// 保持深度优先,用于<Dimension>.members,<Hierarchy>.members
	public static List getHierarchizeMembers(SchemaReader schemaReader, Hierarchy hierarchy)
			throws OLAPException
	{
		return schemaReader.getHierarchyMembers(hierarchy, true);
		// ArrayList members = new ArrayList();
		//
		// Member[] ms = schemaReader.getHierarchyRootMembers(hierarchy);
		//
		// return getHierarchizeMembers(schemaReader, members, ms);
	}

	static List addMembers(SchemaReader schemaReader, List members, Hierarchy hierarchy)
			throws OLAPException
	{
		Level[] levels = schemaReader.getHierarchyLevels(hierarchy);

		for (Level level = levels[0]; level != null; level = level.getChildLevel())
		{
			addMembers(schemaReader, members, level);
		}

		return members;
	}

	static List addMembers(SchemaReader schemaReader, List members, Level level)
			throws OLAPException
	{
		Member[] levelMembers = schemaReader.getLevelMembers(level);
		addAll(members, levelMembers);
		return members;
	}

	static boolean isAncestorOf(Member m0, Member m1, boolean strict) throws OLAPException
	{
		if (strict)
		{
			if (m1 == null)
			{
				return false;
			}
			m1 = m1.getParentMember();
		}
		while (m1 != null)
		{
			if (Util.equals(m1, m0))
			{
				return true;
			}
			m1 = m1.getParentMember();
		}
		return false;
	}

	/**
	static Map evaluateMembers(Evaluator evaluator, ExpBase exp, List members, boolean parentsToo)
			throws OLAPException
	{
		Member[] constantTuple = exp.isConstantTuple();
		return (constantTuple == null) ? _evaluateMembers(evaluator.push(), exp, members,
				parentsToo)
		// exp is constant -- add it to the context before the loop, rather
				// than at every step
				: evaluateMembers(evaluator.push(constantTuple), members, parentsToo);
	}

	private static Map _evaluateMembers(Evaluator evaluator, ExpBase exp, List members,
			boolean parentsToo) throws OLAPException
	{
		Map mapMemberToValue = new HashMap();
		for (int i = 0, count = members.size(); i < count; i++)
		{
			Member member = (Member) members.get(i);
			while (true)
			{
				evaluator.setContext(member);
				Object result = exp.evaluateScalar(evaluator);
				mapMemberToValue.put(member, result);
				if (!parentsToo)
				{
					break;
				}
				member = member.getParentMember();
				if (member == null)
				{
					break;
				}
				if (mapMemberToValue.containsKey(member))
				{
					break;
				}
			}
		}
		return mapMemberToValue;
	}
	*/
	static Map evaluateMembers(Evaluator evaluator, List members, boolean parentsToo)
			throws OLAPException
	{
		Map mapMemberToValue = new HashMap();
		for (int i = 0, count = members.size(); i < count; i++)
		{
			Member member = (Member) members.get(i);
			while (true)
			{
				evaluator.setContext(member);
				Object result = evaluator.evaluateCurrent();
				mapMemberToValue.put(member, result);
				if (!parentsToo)
				{
					break;
				}
				member = member.getParentMember();
				if (member == null)
				{
					break;
				}
				if (mapMemberToValue.containsKey(member))
				{
					break;
				}
			}
		}
		return mapMemberToValue;
	}

	static Map evaluateTuples(Evaluator evaluator, Calc exp, List members) throws OLAPException
	{
		Map mapMemberToValue = new HashMap();
		for (int i = 0, count = members.size(); i < count; i++)
		{
			Member[] tuples = (Member[]) members.get(i);
			evaluator.setContext(tuples);
			Object result = exp.evaluate(evaluator);
			if (result == null)
			{
				result = Util.nullValue;
			}
			mapMemberToValue.put(tuples, result);
		}
		return mapMemberToValue;
	}

	static int sign(double d)
	{
		return (d == 0) ? 0 : (d < 0) ? -1 : 1;
	}

	static int compareValues(double d1, double d2)
	{
		return (d1 == d2) ? 0 : (d1 < d2) ? -1 : 1;
	}

	static int compareValues(int i, int j)
	{
		return (i == j) ? 0 : (i < j) ? -1 : 1;
	}

	static int compareValues(Object value0, Object value1)
	{
		if (value0 == value1)
		{
			return 0;
		}
		// null is less than anything else
		if (value0 == null)
		{
			return -1;
		}
		if (value1 == null)
		{
			return 1;
		}
		if (value0 instanceof RuntimeException || value1 instanceof RuntimeException)
		{
			// one of the values is not in cache; continue as best as we can
			return 0;
		}
		else if (value0 == Util.nullValue)
		{
			return -1; // null == -infinity
		}
		else if (value1 == Util.nullValue)
		{
			return 1; // null == -infinity
		}
		else if (value0 instanceof String)
		{
			return ((String) value0).compareTo((String) value1);
		}
		else if (value0 instanceof Number)
		{
			return FuncUtil_bak.compareValues(((Number) value0).doubleValue(), ((Number) value1)
					.doubleValue());
		}
		else
		{
			throw Util.newInternal("cannot compare " + value0);
		}
	}

	/**
	 * Turns the mapped values into relative values (percentages) for easy use by the general
	 * topOrBottom function. This might also be a useful function in itself.
	 */
	static void toPercent(List members, Map mapMemberToValue)
	{
		double total = 0;
		int numMembers = members.size();
		for (int i = 0; i < numMembers; i++)
		{
			Object o = mapMemberToValue.get(members.get(i));
			if (o instanceof Number)
			{
				total += ((Number) o).doubleValue();
			}
		}
		for (int i = 0; i < numMembers; i++)
		{
			Object member = members.get(i);
			Object o = mapMemberToValue.get(member);
			if (o instanceof Number)
			{
				double d = ((Number) o).doubleValue();
				mapMemberToValue.put(member, new Double(d / total * 100));
			}
		}

	}

	/**
	static Object topOrBottom(Evaluator evaluator, List members, ExpBase exp, boolean isTop,
			boolean isPercent, double target) throws OLAPException
	{
		Map mapMemberToValue = evaluateMembers(evaluator, exp, members, false);
		ObjectComparator comparator = new BreakMemberComparator(mapMemberToValue, isTop);
		Sort.sort(members, comparator);
		if (isPercent)
		{
			toPercent(members, mapMemberToValue);
		}
		double runningTotal = 0;
		int numMembers = members.size();
		int nullCount = 0;
		for (int i = 0; i < numMembers; i++)
		{
			if (runningTotal >= target)
			{
				members = members.subList(0, i);
				break;
			}
			Object o = mapMemberToValue.get(members.get(i));
			if (o instanceof Number)
			{
				runningTotal += ((Number) o).doubleValue();
			}
			else if (o instanceof Exception)
			{
				// ignore the error
			}
			else if (o == Util.nullValue)
			{
				nullCount++;
			}
			else
			{
				throw Util.newInternal("got " + o + " when expecting Number");
			}
		}

		// MSAS exhibits the following behavior. If the value of all members is
		// null, then the first (or last) member of the set is returned for percent
		// operations.
		if ((numMembers > 0) && isPercent && (nullCount == numMembers))
		{
			return (isTop) ? members.subList(0, 1) : members.subList(numMembers - 1, numMembers);
		}
		return members;
	}
	*/
	public static boolean hasMeasure(Member[] members)
	{
		if (members == null)
			return false;

		for (int i = 0; i < members.length; i++)
			if (members[i].isMeasure())
				return true;
		return false;
	}

	/**
	 * 智能处理Measure， 如果切片上有Measures，则用Context的， 如果list中有Measures,则用Context的， 否则，用Measures.members
	 * 
	 * @param evaluator
	 * @param list
	 * @return
	 * @throws OLAPException
	 */
	public static List nonEmptyListUsingIntelligenceMeasures(Evaluator evaluator, List list)
			throws OLAPException
	{
		if (list.isEmpty())
			return list;

		boolean b = false;
		if (list.get(0) instanceof Member)
			b = ((Member) list.get(0)).isMeasure();
		else
			b = hasMeasure((Member[]) list.get(0));
		
		if (!b)
			b = hasMeasure(evaluator.getSlicerMember());

		//mod by stone_zheng
		//自已发现的问题, 针对6.0作了以下修改,暂时未同步到6.0上.
		if (b)
			return nonEmptyList(evaluator, list, null);
		else
			return nonEmptyListUsingMeasures(evaluator, list);
//		if (!b)
//			return nonEmptyList(evaluator, list, null);
//		else
//			return nonEmptyListUsingMeasures(evaluator, list);
		//mod end...

	}

	/**
	 * 使用Measures作为操作集合来过滤空
	 * 
	 * @param evaluator
	 * @param list
	 * @return
	 * @throws OLAPException
	 */
	public static List nonEmptyListUsingMeasures(Evaluator evaluator, List list)
			throws OLAPException
	{
		ArrayList measureList = new ArrayList();
		Member[] measures = evaluator.getCube().getMeasures();
		for (int i = 0; i < measures.length; i++)
			measureList.add(measures[i]);
		//mod by stone_zheng
		//自已发现的问题, 未同步到6.0版本.
		return nonEmptyList(evaluator, list, measureList);
//		return measureList;
		//mod end...
	}

	/**
	 * 用operList计算list,非空依据为operList集合 如果operList为null，则直接用Context
	 */
	public static List nonEmptyList(Evaluator evaluator, List list, List operList)
			throws OLAPException
	{
		if (list.isEmpty())
		{
			return list;
		}
		List result = new ArrayList();

		evaluator = evaluator.push();
		evaluator.setNonEmpty(true);

		if (list.get(0) instanceof Member[])
		{
			for (Iterator it = list.iterator(); it.hasNext();)
			{
				Member[] m = (Member[]) it.next();
				evaluator.setContext(m);
				if (operList == null || operList.size() == 0)
				{
					Object value = evaluator.evaluateCurrent();
					if (value != null && value != Util.nullValue && !(value instanceof Throwable))
					{
						result.add(m);
					}
				}
				else
				{
					boolean istuple = false;
					if (operList.get(0) instanceof Member[])
						istuple = true;

					for (Iterator it2 = operList.iterator(); it2.hasNext();)
					{
						if (istuple)
							evaluator.setContext((Member[]) it2.next());
						else
							evaluator.setContext((Member) it2.next());

						Object value = evaluator.evaluateCurrent();
						if (value != null && value != Util.nullValue
								&& !(value instanceof Throwable))
						{
							result.add(m);
							break;
						}
					}
				}
			}
		}
		else
		{
			for (Iterator it = list.iterator(); it.hasNext();)
			{
				Member m = (Member) it.next();
				evaluator.setContext(m);
				if (operList == null || operList.size() == 0)
				{
					Object value = evaluator.evaluateCurrent();
					if (value != null && value != Util.nullValue && !(value instanceof Throwable))
					{
						result.add(m);
					}
				}
				else
				{
					boolean istuple = false;
					if (operList.get(0) instanceof Member[])
						istuple = true;

					for (Iterator it2 = operList.iterator(); it2.hasNext();)
					{
						if (istuple)
							evaluator.setContext((Member[]) it2.next());
						else
							evaluator.setContext((Member) it2.next());

						Object value = evaluator.evaluateCurrent();
						if (value != null && value != Util.nullValue
								&& !(value instanceof Throwable))
						{
							result.add(m);
							break;
						}
					}
				}
			}
		}
		return result;
	}

	public static Syntax decodeSyntacticType(String flags)
	{
		char c = flags.charAt(0);
		switch (c)
		{
			case 'p' :
				return Syntax.Property;
			case 'f' :
				return Syntax.Function;
			case 'm' :
				return Syntax.Method;
			case 'i' :
				return Syntax.Infix;
			case 'P' :
				return Syntax.Prefix;
			case 'I' :
				return Syntax.Internal;
			default :
				throw Util.newInternal("unknown syntax code '" + c + "' in string '" + flags + "'");
		}
	}

	public static int decodeReturnCategory(String flags)
	{
		final int returnCategory = decodeCategory(flags, 1);
		if ((returnCategory & Category.Mask) != returnCategory)
		{
			throw Util.newInternal("bad return code flag in flags '" + flags + "'");
		}
		return returnCategory;
	}

	public static int decodeCategory(String flags, int offset)
	{
		char c = flags.charAt(offset);
		switch (c)
		{
			case 'a' :
				return Category.Array;
			case 'd' :
				return Category.Dimension;
			case 'h' :
				return Category.Hierarchy;
			case 'l' :
				return Category.Level;
			case 'b' :
				return Category.Logical;
			case 'm' :
				return Category.Member;
			case 'N' :
				return Category.Numeric | Category.Constant;
			case 'n' :
				return Category.Numeric;
			case 'x' :
				return Category.Set;
			case '#' :
				return Category.String | Category.Constant;
			case 'S' :
				return Category.String;
			case 't' :
				return Category.Tuple;
			case 'v' :
				return Category.Value;
			case 'y' :
				return Category.Symbol;
			default :
				throw Util.newInternal("unknown type code '" + c + "' in string '" + flags + "'");
		}
	}

	public static int[] decodeArgCategory(String flags)
	{
		int[] argCategorys = new int[flags.length() - 2];
		for (int i = 0; i < argCategorys.length; i++)
		{
			argCategorys[i] = decodeCategory(flags, i + 2);
		}
		return argCategorys;
	}

	static class SetWrapper
	{
		List v = new ArrayList();
		public int errorCount = 0, nullCount = 0, notReadyCount = 0;
	}

	public static Object min(Evaluator evaluator, List members, Calc calc) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, calc);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;
		if (sw.errorCount > 0)
		{
			// return new Double(Double.NaN);
			return Util.nullValue;
		}
		else if (sw.v.size() == 0)
		{
			return Util.nullValue;
		}
		else
		{
			Number min = new Double(Double.MAX_VALUE);

			for (int i = 0; i < sw.v.size(); i++)
			{
				Number iValue = (Number) sw.v.get(i);

				if (iValue.doubleValue() < min.doubleValue())
				{
					min = iValue;
				}
			}
			return min;
		}
	}

	/**
	public static Object min(Evaluator evaluator, List members, Exp exp) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, (ExpBase) exp);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;
		if (sw.errorCount > 0)
		{
			// return new Double(Double.NaN);
			return Util.nullValue;
		}
		else if (sw.v.size() == 0)
		{
			return Util.nullValue;
		}
		else
		{
			Number min = new Double(Double.MAX_VALUE);

			for (int i = 0; i < sw.v.size(); i++)
			{
				Number iValue = (Number) sw.v.get(i);

				if (iValue.doubleValue() < min.doubleValue())
				{
					min = iValue;
				}
			}
			return min;
		}
	}
	*/
	
	public static Object max(Evaluator evaluator, List members, Calc calc) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, calc);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;
		if (sw.errorCount > 0)
		{
			return Util.nullValue;
		}
		else if (sw.v.size() == 0)
		{
			return Util.nullValue;
		}
		else
		{
			Number max = new Double(Double.MIN_VALUE);

			for (int i = 0; i < sw.v.size(); i++)
			{
				Number iValue = ((Number) sw.v.get(i));

				if (iValue.doubleValue() > max.doubleValue())
				{
					max = iValue;
				}
			}
			return max;
		}
	}

	/**
	public static Object max(Evaluator evaluator, List members, Exp exp) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, (ExpBase) exp);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;
		if (sw.errorCount > 0)
		{
			return Util.nullValue;
		}
		else if (sw.v.size() == 0)
		{
			return Util.nullValue;
		}
		else
		{
			Number max = new Double(Double.MIN_VALUE);

			for (int i = 0; i < sw.v.size(); i++)
			{
				Number iValue = ((Number) sw.v.get(i));

				if (iValue.doubleValue() > max.doubleValue())
				{
					max = iValue;
				}
			}
			return max;
		}
	}
	*/

	public static Object avg(Evaluator evaluator, List members, Calc calc) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, calc);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;

		return (sw.errorCount > 0) || (sw.v.size() == 0) ? Util.nullValue : _avg(sw);
	}

	private static Object _avg(SetWrapper sw) throws OLAPException
	{
		Object sum = sw.v.get(0);
		for (int i = 1; i < sw.v.size(); i++)
		{
			sum = Util.add(sum, sw.v.get(i));
		}

		BigDecimal bd = null;
		if (sum instanceof BigDecimal)
			bd = (BigDecimal) sum;
		else
			bd = new BigDecimal(((Number) sum).doubleValue());

		return bd.divide(new BigDecimal((double)sw.v.size()), BigDecimal.ROUND_HALF_UP);
	}

	public static Object sum(Evaluator evaluator, List members, Calc calc) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, calc);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;
		if (sw.errorCount > 0)
		{
			// return new Double(Double.NaN);
			return Util.nullValue;
		}
		else if (sw.v.size() == 0)
		{
			return Util.nullValue;
		}
		else
		{
			Object sum = sw.v.get(0);
			for (int i = 1; i < sw.v.size(); i++)
			{
				Object o = sw.v.get(i);
				sum = Util.add(sum, o);
			}
			return sum;
		}
	}

	public static Object aggregate(RelAggregator aggregator, Evaluator evaluator, List members,
			Calc calc) throws OLAPException
	{
		throw new OLAPException("todo");
		//return aggregator.aggregate(evaluator, members, calc); 
	}

	public static Object aggregate(Aggregator aggregator, Evaluator evaluator, List members,
			Calc calc) throws OLAPException
	{
		SetWrapper sw = evaluateSet(evaluator, members, calc);
		if (sw.notReadyCount > 0)
			return ValueNotReadyException.instance;
		else if (sw.errorCount > 0)
		{
			// return new Double(Double.NaN);
			return Util.nullValue;
		}
		else if (sw.v.size() == 0)
		{
			return Util.nullValue;
		}
		else
		{
			Object sum = sw.v.get(0);
			for (int i = 1; i < sw.v.size(); i++)
			{
				sum = aggregator.appendValue(sum, sw.v.get(i));
			}
			return sum;
		}
	}

	public static Object count(Evaluator evaluator, List members, boolean includeEmpty)
			throws OLAPException
	{
		if (includeEmpty)
		{
			return new Integer(members.size());
		}
		else
		{
			int retval = 0;
			for (int i = 0; i < members.size(); i++)
			{
				final Object member = members.get(i);
				if (member instanceof Member)
				{
					evaluator.setContext((Member) member);
				}
				else
				{
					evaluator.setContext((Member[]) member);
				}
				Object o = evaluator.evaluateCurrent();
				if (o != Util.nullValue && o != null)
				{
					retval++;
				}
			}
			return new Integer(retval);
		}
	}

	static SetWrapper evaluateSet(Evaluator evaluator, List members, Calc calc)
			throws OLAPException
	{

		SetWrapper retval = new SetWrapper();
		for (Iterator it = members.iterator(); it.hasNext();)
		{
			Object obj = it.next();
			if (obj instanceof Member[])
			{
				evaluator.setContext((Member[]) obj);
			}
			else
			{
				evaluator.setContext((Member) obj);
			}
			Object o = calc.evaluate(evaluator);

			if (o == null || o == Util.nullValue)
				retval.nullCount++;
			else if (o == ValueNotReadyException.instance)
				retval.notReadyCount++;

			else if (o instanceof Throwable)
			{
				retval.errorCount++;
			}
			else if ((o instanceof BigDecimal) || (o instanceof Integer))
			{
				retval.v.add(o);
			}
			else if (o instanceof Number)
			{
				retval.v.add(new BigDecimal(((Number) o).doubleValue()));
			}
			else
			{
				throw new OLAPException("try to evaluator the value which is not Number type.");
				// retval.v.add(o);
			}
		}
		return retval;
	}

	static Member cousin(SchemaReader schemaReader, Member member, Member ancestorMember)
			throws OLAPException
	{
		if (ancestorMember.isNull())
		{
			return ancestorMember;
		}
		if (member.getHierarchy() != ancestorMember.getHierarchy())
		{
			throw new OLAPException(
					"cousin must have same hierarchy between member and ancestor member.");
		}
		if (member.getLevel().getDepth() < ancestorMember.getLevel().getDepth())
		{
			return ancestorMember.getHierarchy().getNullMember();
		}

		Member cousin = cousin2(schemaReader, member, ancestorMember);
		if (cousin == null)
		{
			cousin = ancestorMember.getHierarchy().getNullMember();
		}

		return cousin;
	}

	static private Member cousin2(SchemaReader schemaReader, Member member1, Member member2)
			throws OLAPException
	{
		if (member1.getLevel() == member2.getLevel())
		{
			return member2;
		}
		Member uncle = cousin2(schemaReader, member1.getParentMember(), member2);
		if (uncle == null)
		{
			return null;
		}
		int ordinal = SchemaLookup.getMemberOrdinalInParent(schemaReader, member1);
		Member[] cousins = schemaReader.getMemberChildren(uncle);
		if (cousins.length <= ordinal)
		{
			return null;
		}
		return cousins[ordinal];
	}

	public static Member ancestor(Evaluator evaluator, Member member, int distance, Level targetLevel)
			throws OLAPException
	{
		if ((targetLevel != null) && (member.getHierarchy() != targetLevel.getHierarchy()))
		{
			throw new OLAPException(member.getUniqueName() + " is not in target Level "
					+ targetLevel.getUniqueName() + "'s hierarchy.");
		}

		if (distance == 0)
		{
			return member;
		}
		else if (distance < 0)
		{
			return member.getHierarchy().getNullMember();
		}

		Member[] ancestors = member.getAncestorMembers();

		Member result = member.getHierarchy().getNullMember();

		searchLoop : for (int i = 0; i < ancestors.length; i++)
		{
			final Member ancestorMember = ancestors[i];

			if (targetLevel != null)
			{
				if (ancestorMember.getLevel() == targetLevel)
				{
					result = ancestorMember;
					break searchLoop;

				}
			}
			else
			{
				distance--;

				if (distance == 0)
				{
					if (targetLevel == null || ancestorMember.getLevel() == targetLevel)
					{
						result = ancestorMember;
						break searchLoop;
					}
					else
					{
						result = member.getHierarchy().getNullMember();
						break searchLoop;
					}
				}

			}
		}

		return result;
	}
	
	public static List periodsToDate(Evaluator evaluator, Level level, Member member) throws OLAPException
	{
		if (member == null)
		{
			member = evaluator.getContext(level.getHierarchy().getDimension());
		}
		Member m = member;
		while (m != null)
		{
			if (m.getLevel() == level)
				break;
			m = m.getParentMember();
		}

		List members = new ArrayList();
		if (m != null)
		{
			SchemaReader reader = evaluator.getSchemaReader();
			m = SchemaLookup.getFirstDescendantOnLevel(reader, m, member.getLevel());
			reader.getMemberRange(level, m, member, members);
		}

		return members;
	}

	static List memberRange(Evaluator evaluator, Member startMember, Member endMember)
			throws OLAPException
	{
		final Level level = startMember.getLevel();
		Util.assertTrue(level == endMember.getLevel());
		List members = new ArrayList();
		evaluator.getSchemaReader().getMemberRange(level, startMember, endMember, members);

		if (members.isEmpty())
		{
			evaluator.getSchemaReader().getMemberRange(level, endMember, startMember, members);
		}
		return members;
	}

	/**
	static void sort(Evaluator evaluator, java.util.List members, ExpBase exp, boolean desc,
			boolean brk) throws OLAPException
	{
		if (members.isEmpty())
		{
			return;
		}
		Object first = members.get(0);
		ObjectComparator comparator;
		if (first instanceof Member)
		{
			final boolean parentsToo = !brk;
			Map mapMemberToValue = evaluateMembers(evaluator, exp, members, parentsToo);
			if (brk)
			{
				comparator = new BreakMemberComparator(mapMemberToValue, desc);
			}
			else
			{
				comparator = new HierarchicalMemberComparator(mapMemberToValue, desc);
			}
		}
		else
		{
			Util.assertTrue(first instanceof Member[]);
			final int arity = ((Member[]) first).length;
			if (brk)
			{
				comparator = new BreakArrayComparator(evaluator, exp, arity);
				if (desc)
				{
					comparator = new ReverseComparator(comparator);
				}
			}
			else
			{
				comparator = new HierarchicalArrayComparator(evaluator, exp, arity, desc);
			}
		}
		Sort.sort(members, comparator);
	}
	 */
	static void sort(Evaluator evaluator, List members, Calc exp, boolean desc, boolean brk)
			throws OLAPException
	{
		if (members.isEmpty())
		{
			return;
		}
		Object first = members.get(0);
		ObjectComparator comparator;
		Map mapMemberToValue = null;
		if (first instanceof Member)
		{
			final boolean parentsToo = !brk;
			mapMemberToValue = evaluateMembers(evaluator, exp, members, parentsToo);
			if (brk)
			{
				comparator = new BreakMemberComparator(mapMemberToValue, desc);
			}
			else
			{
				comparator = new HierarchicalMemberComparator(mapMemberToValue, desc);
			}
		}
		else
		{
			Util.assertTrue(first instanceof Member[]);
			final int arity = ((Member[]) first).length;
			if (brk)
			{
				comparator = new BreakArrayCalcComparator(evaluator, exp, arity);
				if (desc)
				{
					comparator = new ReverseComparator(comparator);
				}
			}
			else
			{
				comparator = new HierarchicalArrayCalcComparator(evaluator, exp, arity, desc);
			}
		}
		Sort.sort(members, comparator);
	}

	static Map evaluateMembers(Evaluator evaluator, Calc exp, List members, boolean parentsToo)
			throws OLAPException
	{
		assert exp.getType() instanceof ScalarType;
		Map mapMemberToValue = new HashMap();
		for (int i = 0, count = members.size(); i < count; i++)
		{
			Member member = (Member) members.get(i);
			while (true)
			{
				evaluator.setContext(member);
				Object result = exp.evaluate(evaluator);
				if (result == null)
				{
					result = Util.nullValue;
				}
				mapMemberToValue.put(member, result);
				if (!parentsToo)
				{
					break;
				}
				member = member.getParentMember();
				if (member == null)
				{
					break;
				}
				if (mapMemberToValue.containsKey(member))
				{
					break;
				}
			}
		}
		return mapMemberToValue;
	}

	/**
	 * Adds every element of <code>right</code> which is not in <code>set</code> to both
	 * <code>set</code> and <code>left</code>.
	 */
	static void addUnique(List left, List right, Set set)
	{
		if (right == null)
		{
			return;
		}
		for (int i = 0, n = right.size(); i < n; i++)
		{
			Object o = right.get(i), p = o;
			if (o instanceof Object[])
			{
				p = new ArrayHolder((Object[]) o);
			}
			if (set.add(p))
			{
				left.add(o);
			}
		}
	}

	public static int compareHierarchically(Member m1, Member m2, boolean post)
			throws OLAPException
	{
		if (equals(m1, m2))
		{
			return 0;
		}

		// 目前只有一个V$All
		if (m1.isInner())
			return -1;
		if (m2.isInner())
			return 1;
		// calculate member on last，for example '小计'...
		boolean cal1 = m1.isCalculated() || m1.isCalculatedInQuery();
		boolean cal2 = m2.isCalculated() || m2.isCalculatedInQuery();
		if (cal1 && !cal2)
			return 1;
		else if (!cal1 && cal2)
			return -1;
		else if (cal1 && cal2)
			return collator.compare(m1.getName(), m2.getName());

		while (true)
		{
			int depth1 = m1.getDepth();
			int depth2 = m2.getDepth();
			if (depth1 < depth2)
			{
				m2 = m2.getParentMember();
				if (equals(m1, m2))
				{
					return post ? 1 : -1;
				}
			}
			else if (depth1 > depth2)
			{
				m1 = m1.getParentMember();
				if (equals(m1, m2))
				{
					return post ? -1 : 1;
				}
			}
			else
			{
				Member prev1 = m1;
				Member prev2 = m2;
				m1 = m1.getParentMember();
				m2 = m2.getParentMember();
				if (equals(m1, m2))
				{
					return compareSiblingMembers(prev1, prev2);
				}
			}
		}
	}

	static int compareSiblingMembers(Member m1, Member m2)
	{
		final int ordinal1 = m1.getOrdinal();
		final int ordinal2 = m2.getOrdinal();
		return (ordinal1 == ordinal2)
				? collator.compare(m1.getName(), m2.getName())
				: (ordinal1 < ordinal2) ? -1 : 1;
	}

	public static void hierarchize(List members, boolean post) throws OLAPException
	{
		if (members.isEmpty())
		{
			return;
		}
		Object first = members.get(0);
		ObjectComparator comparator;
		if (first instanceof Member)
		{
			comparator = new HierarchizeComparator(post);
		}
		else
		{
			Util.assertTrue(first instanceof Member[]);
			final int arity = ((Member[]) first).length;
			comparator = new HierarchizeArrayComparator(arity, post);
		}
		Sort.sort(members, comparator);
	}

	public static Level getTimeLevel(Cube cube, byte levelType)
	{
		Dimension dimensions[] = cube.getDimensions();
		for (int i = 0; i < dimensions.length; i++)
		{
			Dimension dimension = dimensions[i];
			if (dimension.isTimeDimension())
			{
				Hierarchy[] hierarchies = dimension.getHierarchies();
				for (int j = 0; j < hierarchies.length; j++)
				{
					Hierarchy hierarchy = hierarchies[j];
					Level[] levels = hierarchy.getLevels();
					for (int k = 0; k < levels.length; k++)
					{
						Level level = levels[k];
						if (level.getLevelType() == levelType)
						{
							return level;
						}
					}
				}
			}
		}
		return null;
	}

	// only use in rolap
	public static List factMembers(Evaluator evaluator, Hierarchy[] hies, boolean withAll,
			boolean withAncestor) throws OLAPException
	{
		EvaluatorImpl e = (EvaluatorImpl) evaluator;
		RelCubeImpl cube = (RelCubeImpl) e.getCube();

		FactMemberTupleReader reader = new FactMemberTupleReader((RelConnectionImpl) e
				.getConnection(), cube.getStar());
		RelHierarchyImpl[] hs = new RelHierarchyImpl[hies.length];
		for (int i = 0; i < hs.length; i++)
			hs[i] = (RelHierarchyImpl) hies[i];

		//在reader.factMembers中判断,更为准确
		//judgeCrossJoinMembers(evaluator,hs);
		
		return reader.factMembers(hs, withAll, withAncestor);
	}
	
	
	public static void judgeCrossJoinMembers(Evaluator evaluator,RelHierarchyImpl[] hs)
		throws OLAPException
	{
		long size = 1;
		for (int i = 0; i < hs.length; i++)
		{
			size *= getHierarchizeMembers(evaluator.getSchemaReader(),hs[i]).size();
		}
		warmTooManyMember(size);
	}

	/*
	 * add by stone_zheng 
	 * 	暂时简单解决由于轴占用内存过大的问题.
	 *  按总体组指导,要求一次申请内存不能超过500M,按Member占用600字节进行
	 *  计算,限制用户不得使用超过80W的交叉数.
	 */
	public static void warmTooManyMember(long size)
		throws TooManyMemberException
	{
		if(size > 800000)
			throw new TooManyMemberException("分析数据量过大，行或列上的交叉成员超过80万，无法分析！\r\n (请适当调整过滤条件，减少分析数据量)");
	}
		
}


