/**
 * This is the FofX class.  It harvests data from the input object
 * and transforms it to a set of raw x,y coordinates (raw in the sense that they
 * are not yet translated to the actual graph on the screen).
 */
PrtFofX.prototype = new Equation(); // Attach to the superclass.
/**
 * This is the prototype constructor for the FofX class. 
 */ 
function PrtFofX() { 
  // Properties:
  this.strEquationType = "FofX";
  this.booIsFunction = false; 
  // Methods:
  this.getRawResults     = FofX_getRawResults;
  this.priEquationEngine = FofX_priEquationEngine;
}

FofX.prototype = new PrtFofX(); // Attach to superclass.

/**
 * This is the constructor for the FofX class.
 * @objGraph      The graph that the equation is to be drawn on.
 * @objInputForm  The input form widget, source of the data needed to evaluate an equation.
 * @objTextDisplay The widget that displays the solution set in non-graphical (text) form.
 */

function FofX(objGraph, objInputForm, objTextDisplay) {
  this.Equation(objGraph, objInputForm, objTextDisplay);
}


/**
 * This method returns the set of raw results for the graph,
 * and displays them in the "Results" widget.  The raw results 
 * are not pixel coordinates, but the actual results of evaluating
 * the equation over the X range specified.
 * @param   intEquationNumber   The index number of the equation to be evaluated.
 * @return  this.arrRawResults  The array containing all the x,y result pairs of the solution set.
 */
function FofX_getRawResults(intEquationNumber) {
  var strDisplay = null;
  var intXstep = null;
  var intMinX = null;
  var intCurrentX = null;
  var intNumXpixelsToSolve = this.objGraph.getWidth();
  this.arrRawResults = new Array();
  var funResultPair = function(intX, hshY) { 
    this.intX = intX;
    this.hshY = hshY; 
  }
  // Initialize arrMatrix: (This is a feature provided for the use of graphing equation/function writers). 
  for (var intI=0; intI<500; intI++) {
    GloScope.arrMatrix[0][intI] = 0;
  }
  // Get the parameters:
  var hshVisibleXYranges = this.objInputForm.getData();
  this.hshRangeToSolveFor = new Object();
  intMinX = this.hshRangeToSolveFor[Grapher.MINX] = hshVisibleXYranges[Grapher.MINX];
  this.hshRangeToSolveFor[Grapher.MAXX] = hshVisibleXYranges[Grapher.MAXX];
  this.strFofX = this.objInputForm.getData(intEquationNumber);
  // alert("debug: this.strFofX = "+this.strFofX);
  if (this.strFofX.match(/^function/) != null) {
    this.booIsFunction = true;
  } else {
    this.booIsFunction = false;
    this.strFofX = "\"" + this.strFofX +  "\"";
    this.strFofX = this.strFofX.replace(/x/g, "\"+intX+\"");
  }

  // Compute the solution set:
  intXstep = ( 
              (this.hshRangeToSolveFor[Grapher.MAXX] - this.hshRangeToSolveFor[Grapher.MINX])
              / intNumXpixelsToSolve
              );
  for (var intI=0; intI < intNumXpixelsToSolve; intI++) {
    intCurrentX = intMinX + (intI*intXstep);
    /*-
     * Debug: 
      if (intI==10) {
      for (anyI in this.priEquationEngine(intCurrentX)) {
        alert("key: "+anyI);
        alert("value: "+this.priEquationEngine(intCurrentX)[anyI]);
      }
    }
    */
    this.arrRawResults[intI] = new funResultPair( intCurrentX, this.priEquationEngine(intCurrentX) );
  }

  // Compose and display the non-graphical output (the solution set):
  strDisplay = "<br><hr><h3>Solving Equation #" + intEquationNumber 
    + " for this range:</h3>*  Minimum x: " + this.hshRangeToSolveFor[Grapher.MINX]
    + "<br>*  Maximum x: " + this.hshRangeToSolveFor[Grapher.MAXX] 
    + "<br><hr><br>Solving for f(x) = "+this.strFofX+"<br>";         
  this.objTextDisplay.display(strDisplay+this.priFormatResults());
  
  return this.arrRawResults; // Pass the raw results to the Grapher class.
}


/* ----- Private Methods: */
/**
 * This method computes the value of 'y' for 'x' in a FofX of degree 5.
 * @intX  The x value to plug into the FofX.
 */
function FofX_priEquationEngine(intX) {
  var intX = intX;
  var anyResult;
  var hshResult;
  if (this.booIsFunction) {
    // alert("eval(this.strFofX) : "+eval(this.strFofX));
    rxpFuncBodyWithLastCurlyBr = /^[^\{]*\{/;
    rxpFuncBodyChopLastCurlyBr = /\}[^\}a-zA-Z0-9]*$/;
    var strBody = this.strFofX.replace(rxpFuncBodyWithLastCurlyBr, "");
    strBody = strBody.replace(rxpFuncBodyChopLastCurlyBr, "");
    
    // alert("strBody:"+strBody);
    /*- 
     * We depart from our coding convention here to honor the mathematical convention of naming a function f, 
     * so that the user can type in "f(x)" and get recursion with that.
     */
    f = new Function("x", strBody); 
    anyResult = f(intX);
  } else { // Evaluate plain mathematical expression (instead of a JavaScript function):
    anyResult = eval(eval("var intX=" + intX + "; " + this.strFofX));
  }
  if (typeof anyResult != "object") {
    hshResult = new Object;
    hshResult["y"] = anyResult; // If not an Object, 'anyResult' is a number.
  } else {
    hshResult = anyResult; // This holds a set of results for 'y' (for drawing a circle, etc.).
  }
  return hshResult;
} 



