context: /*
  * Licensed to the Apache Software Foundation (ASF) Under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for Additional information regarding copyright ownership.
  * The ASF licenses this file to You Under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed Under the License is distributed on an "AS Is" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations Under the License.
  */
  
  namespace AL.Utils.NPOI.SS.Formula.Functions
  {
      using System;
      using System.Collections.Generic;
      using AL.Utils.NPOI.SS.Formula.Eval;
      using AL.Utils.NPOI.SS.Formula;
  
      /**
       * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
       * This Is the base class for all excel function evaluator
       * classes that take variable number of operands, and
       * where the order of operands does not matter
       */
      public abstract class MultiOperandNumericFunction : Function
      {
          static double[] EMPTY_DOUBLE_ARRAY = { };
          private bool _isReferenceBoolCounted;
          private bool _isBlankCounted;
  
          protected MultiOperandNumericFunction(bool isReferenceBoolCounted, bool isBlankCounted)
          {
              _isReferenceBoolCounted = isReferenceBoolCounted;
              _isBlankCounted = isBlankCounted;
          }
          protected internal abstract double Evaluate(double[] values);
  
          public ValueEval Evaluate(ValueEval[] args, int srcCellRow, int srcCellCol)
          {
  
              double d;
              try
              {
                  double[] values = GetNumberArray(args);
                  d = Evaluate(values);
              }
              catch (EvaluationException e)
              {
                  return e.GetErrorEval();
              }
  
              if (Double.IsNaN(d) || Double.IsInfinity(d))
                  return ErrorEval.NUM_ERROR;
  
              return new NumberEval(d);
          }
  
          private class DoubleList
          {
              private double[] _array;
              private int _Count;
  
              public DoubleList()
              {
                  _array = new double[8];
                  _Count = 0;
              }
  
              public double[] ToArray()
              {
                  if (_Count < 1)
                  {
                      return EMPTY_DOUBLE_ARRAY;
                  }
                  double[] result = new double[_Count];
                  Array.Copy(_array, 0, result, 0, _Count);
                  return result;
              }
  
              public void Add(double[] values)
              {
                  int AddLen = values.Length;
                  EnsureCapacity(_Count + AddLen);
                  Array.Copy(values, 0, _array, _Count, AddLen);
                  _Count += AddLen;
              }
  
              private void EnsureCapacity(int reqSize)
              {
                  if (reqSize > _array.Length)
                  {
                      int newSize = reqSize * 3 / 2; // grow with 50% extra
                      double[] newArr = new double[newSize];
                      Array.Copy(_array, 0, newArr, 0, _Count);
                      _array = newArr;
                  }
              }
  
              public void Add(double value)
              {
                  EnsureCapacity(_Count + 1);
                  _array[_Count] = value;
                  _Count++;
              }
          }
  
          private static int DEFAULT_MAX_NUM_OPERANDS = 30;
  
          /**
           * Maximum number of operands accepted by this function.
           * Subclasses may override to Change default value.
           */
          protected int MaxNumOperands
          {
              get
              {
                  return DEFAULT_MAX_NUM_OPERANDS;
              }
          }
          /**
       *  Whether to count nested subtotals.
       */
          public virtual bool IsSubtotalCounted
          {
              get
              {
                  return true;
              }
          }
          /**
   * Collects values from a single argument
   */
          private void CollectValues(ValueEval operand, DoubleList temp)
          {
  
              if (operand is TwoDEval)
              {
                  TwoDEval ae = (TwoDEval)operand;
                  int width = ae.Width;
                  int height = ae.Height;
                  for (int rrIx = 0; rrIx < height; rrIx++)
                  {
                      for (int rcIx = 0; rcIx < width; rcIx++)
                      {
                          ValueEval ve = ae.GetValue(rrIx, rcIx);
                          if (!IsSubtotalCounted && ae.IsSubTotal(rrIx, rcIx)) continue;
                          CollectValue(ve, true, temp);
                      }
                  }
                  return;
              }
              if (operand is RefEval)
              {
                  RefEval re = (RefEval)operand;
                  CollectValue(re.InnerValueEval, true, temp);
                  return;
              }
              CollectValue((ValueEval)operand, false, temp);
          }
          private void CollectValue(ValueEval ve, bool isViaReference, DoubleList temp)
          {
              if (ve == null)
              {
                  throw new ArgumentException("ve must not be null");
              }
              if (ve is NumberEval)
              {
                  NumberEval ne = (NumberEval)ve;
                  temp.Add(ne.NumberValue);
                  return;
              }
              if (ve is ErrorEval)
              {
                  throw new EvaluationException((ErrorEval)ve);
              }
              if (ve is StringEval)
              {
                  if (isViaReference)
                  {
                      // ignore all ref strings
                      return;
                  }
                  String s = ((StringEval)ve).StringValue;
                  Double d = OperandResolver.ParseDouble(s);
                  if (double.IsNaN(d))
                  {
                      throw new EvaluationException(ErrorEval.VALUE_INVALID);
                  }
                  temp.Add(d);
                  return;
              }
              if (ve is BoolEval)
              {
                  if (!isViaReference || _isReferenceBoolCounted)
                  {
  
gt:                     BoolEval boolEval = (BoolEval)ve;