/**
  * Constructor for function definition in natural math language,
  * for instance providing on string "f(x,y) = sin(x) + cos(x)"
  * is enough to define function "f" with parameters "x and y"
  * and function body "sin(x) + cos(x)".
  *
  * @param functionDefinitionString      Function definition in the form
  *                                      of one String, ie "f(x,y) = sin(x) + cos(x)"
  * @param elements                      Optional elements list (variadic - comma separated)
  *                                      of types: Argument, Constant, Function
  *
  * @see    PrimitiveElement
  *
  */
 public Function(String functionDefinitionString, params PrimitiveElement[] elements)
     : base(Function.TYPE_ID)
 {
     parametersNumber = 0;
     if (mXparser.regexMatch(functionDefinitionString, ParserSymbol.functionDefStrRegExp)) {
         HeadEqBody headEqBody = new HeadEqBody(functionDefinitionString);
         this.functionName = headEqBody.headTokens[0].tokenStr;
         functionExpression = new Expression(headEqBody.bodyStr, elements);
         functionExpression.setDescription(headEqBody.headStr);
         if (headEqBody.headTokens.Count > 1)
         {
             Token t;
             for (int i = 1; i < headEqBody.headTokens.Count; i++)
             {
                 t = headEqBody.headTokens[i];
                 if (t.tokenTypeId != ParserSymbol.TYPE_ID)
                     functionExpression.addArguments(new Argument(t.tokenStr));
             }
         }
         parametersNumber = functionExpression.getArgumentsNumber() - countRecursiveArguments();
         description = "";
         addFunctions(this);
     }
     else {
         functionExpression = new Expression();
         functionExpression.setDescription(functionDefinitionString);
         String errorMessage = ""; errorMessage = errorMessage + "\n [" + functionDefinitionString + "] " + "--> pattern not mathes: f(x1,...,xn) = ... reg exp: " + ParserSymbol.functionDefStrRegExp;
         functionExpression.setSyntaxStatus(Expression.SYNTAX_ERROR_OR_STATUS_UNKNOWN, errorMessage);
     }
 }
 /**
  * Constructor - creates function from function name,
  * function expression string and argument names.
  *
  * @param      functionName              the function name
  * @param      functionExpressionString  the function expression string
  * @param      argumentsNames            the arguments names (variadic parameters)
  *                                       comma separated list
  *
  * @see        Expression
  */
 public Function(String functionName
     ,String  functionExpressionString
     ,params String[] argumentsNames)
     : base(Function.TYPE_ID)
 {
     if (mXparser.regexMatch(functionName, ParserSymbol.nameOnlyTokenRegExp)) {
         this.functionName = functionName;
         functionExpression = new Expression(functionExpressionString);
         functionExpression.setDescription(functionName);
         foreach (String argName in argumentsNames)
             functionExpression.addArguments(new Argument(argName));
         parametersNumber = argumentsNames.Length - countRecursiveArguments();
         description = "";
         addFunctions(this);
     }
     else {
         parametersNumber = 0;
         description = "";
         functionExpression = new Expression("");
         functionExpression.setSyntaxStatus(SYNTAX_ERROR_OR_STATUS_UNKNOWN, "[" + functionName + "]" + "Invalid function name, pattern not matches: " + ParserSymbol.nameTokenRegExp);
     }
 }
 /*=================================================
  *
  * Constructors
  *
  *=================================================
  */
 /**
  * Constructor - creates function from function name
  * and function expression string.
  *
  * @param      functionName              the function name
  * @param      functionExpressionString  the function expression string
  * @param      elements                  Optional elements list (variadic - comma separated) of types: Argument, Constant, Function
  *
  * @see        PrimitiveElement
  * @see        Expression
  */
 public Function(String functionName
     ,String  functionExpressionString, params PrimitiveElement[] elements)
     : base(Function.TYPE_ID)
 {
     if (mXparser.regexMatch(functionName, ParserSymbol.nameOnlyTokenRegExp)) {
         this.functionName = functionName;
         functionExpression = new Expression(functionExpressionString, elements);
         functionExpression.setDescription(functionName);
         parametersNumber = 0;
         description = "";
         addFunctions(this);
     }
     else {
         parametersNumber = 0;
         description = "";
         functionExpression = new Expression("");
         functionExpression.setSyntaxStatus(SYNTAX_ERROR_OR_STATUS_UNKNOWN, "[" + functionName + "]" + "Invalid function name, pattern not matches: " + ParserSymbol.nameTokenRegExp);
     }
 }
 /**
  * Gets recursive argument value
  *
  * @param      index               the index
  *
  * @return     value as double
  */
 public double getArgumentValue(double index)
 {
     /*
      * Remember starting index
      */
     if (recursiveCounter == -1)
         startingIndex = (int)Math.Round(index);
     int recSize = baseValues.Count;
     int idx = (int)Math.Round(index);
     /*
      * Count recursive calls
      */
     recursiveCounter++;
     if ((recursiveCounter <= startingIndex) && (idx <= startingIndex)) {
         /*
          * if recursive counter is still lower than starting index
          * and current index is not increasing
          */
         if ((idx >= 0) && (idx < recSize) && (!Double.IsNaN( baseValues[idx] )) ) {
             /*
              * decrease recursive counter and return value
              * if recursive value for the current index was already
              * calculated and remembered in the base values table
              */
             recursiveCounter--;
             return baseValues[idx];
         }
         else if (idx >= 0) {
             /*
              * value is to be calculated by the recursive calls
              */
             /*
              * Set n to the current index
              */
             n.setArgumentValue(idx);
             /*
              * create new expression
              */
             Expression newExp = new Expression(
                     base.argumentExpression.expressionString
                     , base.argumentExpression.argumentsList
                     , base.argumentExpression.functionsList
                     , base.argumentExpression.constantsList
                     ,Expression.INTERNAL);
             newExp.setDescription(base.getArgumentName());
             //newExp.setRecursiveMode();
             if (base.getVerboseMode() == true)
             {
                 //System.out.println(super.getVerboseMode() + ", " +super.getArgumentName() + ", " + super.argumentExpression.expressionString + "," + "VERBOSE MODE for recurssion");
                 newExp.setVerboseMode();
             }
             /*
              * perform recursive call
              */
             double value = newExp.calculate();
             /*
              * remember calculated in the base values array
              */
             addBaseCase(idx, value);
             /*
              * decrease recursive counter and return value
              */
             recursiveCounter--;
             return value;
         } else {
             /*
              * decrease recursive counter and
              * return Double.NaN for negative index call
              */
             recursiveCounter--;
             return Double.NaN;
         }
     } else {
         /* stop never ending loop
          * decrease recursive counter and
          * return Double.NaN
          */
         recursiveCounter--;
         return Double.NaN;
     }
 }
 /**
  * Constructor - creates dependent argument(with hidden
  * argument expression).
  *
  * @param      argumentName                  the argument name
  * @param      argumentExpressionString      the argument expression string
  * @param      elements                      Optional parameters (comma separated)
  *                                           such as Arguments, Constants, Functions
  *
  * @see        Expression
  * @see        PrimitiveElement
  */
 public Argument(String argumentName, String argumentExpressionString, params PrimitiveElement[] elements)
     : base(Argument.TYPE_ID)
 {
     if (mXparser.regexMatch(argumentName, ParserSymbol.nameOnlyTokenRegExp)) {
         this.argumentName=String.Copy(argumentName);
         argumentValue=ARGUMENT_INITIAL_VALUE;
         argumentExpression = new Expression(argumentExpressionString, elements);
         argumentExpression.setDescription(argumentName);
         argumentType = DEPENDENT_ARGUMENT;
     }
     else {
         this.argumentValue = ARGUMENT_INITIAL_VALUE;
         argumentExpression = new Expression();
         argumentExpression.setSyntaxStatus(SYNTAX_ERROR_OR_STATUS_UNKNOWN, "[" + argumentName + "] " + "Invalid argument name, pattern not match: " + ParserSymbol.nameOnlyTokenRegExp);
     }
     setSilentMode();
     description = "";
 }
 /*=================================================
  *
  * Constructors
  *
  *=================================================
  */
 /**
  * Default constructor - creates argument based on the argument definition string.
  *
  * @param      argumentDefinitionString        Argument definition string, i.e.:
  *                                             <ul>
  *                                                <li>'x' - only argument name
  *                                                <li>'x=5' - argument name and argument value
  *                                                <li>'x=2*5' - argument name and argument value given as simple expression
  *                                                <li>'x=2*y' - argument name and argument expression (dependent argument 'x' on argument 'y')
  *                                             </ul>
  *
  * @param      elements   Optional parameters (comma separated) such as Arguments, Constants, Functions
  */
 public Argument(String argumentDefinitionString, params PrimitiveElement[] elements)
     : base(Argument.TYPE_ID)
 {
     if (mXparser.regexMatch(argumentDefinitionString, ParserSymbol.nameOnlyTokenRegExp)) {
         argumentName = argumentDefinitionString;
         argumentValue = ARGUMENT_INITIAL_VALUE;
         argumentType = FREE_ARGUMENT;
         argumentExpression = new Expression(elements);
     }
     else if (mXparser.regexMatch(argumentDefinitionString, ParserSymbol.constArgDefStrRegExp)) {
         HeadEqBody headEqBody = new HeadEqBody(argumentDefinitionString);
         argumentName = headEqBody.headTokens[0].tokenStr;
         Expression bodyExpr = new Expression(headEqBody.bodyStr);
         double bodyValue = bodyExpr.calculate();
         if ((bodyExpr.getSyntaxStatus() == Expression.NO_SYNTAX_ERRORS) && (bodyValue != Double.NaN)) {
             argumentExpression = new Expression();
             argumentValue = bodyValue;
             argumentType = FREE_ARGUMENT;
         }
         else {
             argumentExpression = bodyExpr;
             addDefinitions(elements);
             argumentType = DEPENDENT_ARGUMENT;
         }
     }
     else if (mXparser.regexMatch(argumentDefinitionString, ParserSymbol.functionDefStrRegExp)) {
         HeadEqBody headEqBody = new HeadEqBody(argumentDefinitionString);
         argumentName = headEqBody.headTokens[0].tokenStr;
         argumentExpression = new Expression(headEqBody.bodyStr, elements);
         argumentExpression.setDescription(headEqBody.headStr);
         argumentValue = ARGUMENT_INITIAL_VALUE;
         argumentType = DEPENDENT_ARGUMENT;
         n = new Argument(headEqBody.headTokens[2].tokenStr);
     }
     else {
         argumentValue = ARGUMENT_INITIAL_VALUE;
         argumentType = FREE_ARGUMENT;
         argumentExpression = new Expression();
         argumentExpression.setSyntaxStatus(SYNTAX_ERROR_OR_STATUS_UNKNOWN, "[" + argumentDefinitionString + "] " + "Invalid argument definition (patterns: 'x', 'x=5', 'x=5+3/2', 'x=2*y').");
     }
     setSilentMode();
     description = "";
 }