/** Creates a function based on a user function */
  public Function(UserFunction f) {
    String[] names = f.getVarNames();

    this.function = f;
    this.argsNumber = names.length;
    this.args = new Argument[argsNumber];
    this.values = new double[argsNumber];

    for (int i = 0; i < argsNumber; i++) {
      String name = names[i];
      args[i] = new Argument(name, f.getVarIndex(name));
    }
  }
  /** Evaluates the function */
  public double evaluate(DataRow data) throws Exception {
    for (int i = 0; i < argsNumber; i++) {
      Argument arg = args[i];
      values[arg.index] = data.getVarDoubleValue(arg.varName);
    }

    return function.evaluate(values);
  }
  /**
   * Adds a chart information to the existing chart panel
   *
   * @param node
   */
  public void addSeries(Node node) {
    // TODO: everything could be done with expressions only

    String varNames = XmlDocUtils.getValue(node, "variable", null);
    String label = XmlDocUtils.getValue(node, "label", "");

    String expressions = XmlDocUtils.getValue(node, "expressions", null);
    String exprLabels = XmlDocUtils.getValue(node, "expr-labels", "");

    // Single variables
    if (varNames != null) {
      String[] names = varNames.split(";");
      String[] labels = label.split(";");
      int i = 0;

      for (String name : names) {
        if (name == null || name.length() == 0) continue;

        label = labels[i];
        name = name.trim();

        addSeries(name, label);
        if (i < labels.length - 1) i += 1;
      }
    }

    // Expressions
    if (expressions != null) {
      String[] exprs = expressions.split(";");
      String[] labels = exprLabels.split(";");
      int i = 0;

      for (String expr : exprs) {
        if (expr == null || expr.length() == 0) continue;

        label = labels[i];
        UserFunction f;

        try {
          f = UserFunction.create(expr);
        } catch (Exception ex) {
          ex.printStackTrace();
          continue;
        }

        addSeries(f, label);
        if (i < labels.length - 1) i += 1;
      }
    }
  }
 @Override
 public String toString() {
   return function.toString();
 }