/**
  * 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);
     }
 }
 /**
  * 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 = "";
 }
 /**
  * Constructor - creates free argument.
  *
  * @param      argumentName   the argument name
  * @param      argumentValue  the argument value
  */
 public Argument(String argumentName, double argumentValue)
     : base(Argument.TYPE_ID)
 {
     argumentExpression = new Expression();
     if (mXparser.regexMatch(argumentName, ParserSymbol.nameOnlyTokenRegExp)) {
         this.argumentName = String.Copy(argumentName);
         this.argumentValue = argumentValue;
         argumentType = FREE_ARGUMENT;
     }
     else {
         this.argumentValue = ARGUMENT_INITIAL_VALUE;
         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 = "";
 }