/**
   * Generates the variable function ptg for the formula.
   *
   * <p>For IF Formulas, additional PTGs are added to the tokens
   *
   * @param name a {@link NamePtg} or {@link NameXPtg} or <code>null</code>
   * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is
   *     handled in this function
   */
  private ParseNode getFunction(String name, Ptg namePtg, ParseNode[] args) {

    FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByName(name.toUpperCase());
    int numArgs = args.length;
    if (fm == null) {
      if (namePtg == null) {
        throw new IllegalStateException("NamePtg must be supplied for external functions");
      }
      // must be external function
      ParseNode[] allArgs = new ParseNode[numArgs + 1];
      allArgs[0] = new ParseNode(namePtg);
      System.arraycopy(args, 0, allArgs, 1, numArgs);
      return new ParseNode(FuncVarPtg.create(name, numArgs + 1), allArgs);
    }

    if (namePtg != null) {
      throw new IllegalStateException("NamePtg no applicable to internal functions");
    }
    boolean isVarArgs = !fm.hasFixedArgsLength();
    int funcIx = fm.getIndex();
    if (funcIx == FunctionMetadataRegistry.FUNCTION_INDEX_SUM && args.length == 1) {
      // Excel encodes the sum of a single argument as tAttrSum
      // POI does the same for consistency, but this is not critical
      return new ParseNode(AttrPtg.getSumSingle(), args);
      // The code below would encode tFuncVar(SUM) which seems to do no harm
    }
    validateNumArgs(args.length, fm);

    AbstractFunctionPtg retval;
    if (isVarArgs) {
      retval = FuncVarPtg.create(name, numArgs);
    } else {
      retval = FuncPtg.create(funcIx);
    }
    return new ParseNode(retval, args);
  }