package graphics.charts;


/**
 * DoubleData is the base class which is required in order to draw any graphs.
 * It contains all the utility methods to calculate the necessary graphics.graph
 * data for drawing.
 *  Constants include:
 *  <UL>
 *  <LI> BIGNUM: an upper bound used in calculating the minimum value in passed data
 *  <LI> LITTLENUM: a lower bound used in calculating the maximum value in passed data
 *  <LI> X_OFFSET: a constant used to correct for the portion of the image frame taken
 *  up by the GUI elements
 *  <LI> Y_OFFSET: a constant used to correct for the portion of the image frame taken up
 *  by the GUI elements (with offsets set to 0, the axes are drawn off-screen)
 *  </UL>
 *  Passed parameters set with defaults include:
 *  <UL>
 *  <LI> width: the width of the drawn image
 *  <LI> height: the height of the drawn image
 *  <LI> xVals: the X data to be graphed; the primary data for the pie graphics.graph
 *  <LI> yVals: the Y data to be graphed; the primary data for the bar graphics.graph
 *  <LI> labels: the labels for the pie graphics.graph data elements
 *  <LI> isGridOn: whether or not a grid should be drawn
 *  <LI> isTicksOn: whether or not ticks should be drawn along the axes
 *  <LI> xLabel: title for the X axis
 *  <LI> yLabel: title for the Y axis
 *  <LI> title: title for the graphics.graph
 *  </UL>
 *
 * @author  Allison McHenry
 * @author  Douglas Lyon, PhD
 * @since   JDK 1.3
 */

public class DoubleData {

//BEGIN GLOBAL VARIABLE DECLARATIONS

  private static final double BIGNUM = 32768;
  private static final double LITTLENUM = -32768;
  protected static final int X_OFFSET = 10;
  protected static final int Y_OFFSET = 10;

  private int width = 300;
  private int height = 300;

  private double xVals[] = {1, 2, 3, 4};
  private double yVals[] = {10, -20, -40, 80};


  private boolean isGridOn = true;
  private boolean isTicksOn = true;
  private String xLabel = "This is the X axis";
  private String yLabel = "This is the Y axis";
  private String title = "This is the Title";

  /**
   *    Default constructor, used particularly to instantiate an instance of DoubleData by
   *    the LineGraph, PieGraph and BarGraph classes
   */
  public DoubleData(int w, int h) {
    setWidth(w);
    setHeight(h);
  }

  /**
   *    Sets image width.
   *
   *    @param _width   image width (not frame width)
   */
  public void setWidth(int _width) {
    width = _width;
  }

  /**
   *    Sets image height.
   *
   *    @param _height  image height (not frame height)
   */
  public void setHeight(int _height) {
    height = _height;
  }

  /**
   *    Sets x-axis label on bar graphs and line graphs.
   *
   *    @param _xLabel  x-axis label
   */
  public void setXLabel(String _xLabel) {
    xLabel = _xLabel;
  }

  /**
   *    Sets y-axis label on bar graphs and line graphs.
   *
   *    @param _yLabel  y-axis label
   */
  public void setYLabel(String _yLabel) {
    yLabel = _yLabel;
  }

  /**
   *    Sets title of all graphs.
   *
   *    @param _title   Graph title
   */
  public void setTitle(String _title) {
    title = _title;
  }


  /**
   *    Sets whether or not a grid (lines the height and breadth of the image indicating
   *    increment size) should be drawn on line graphs and bar graphs.
   *
   *    @param _isGridOn    whether a grid should be drawn
   */
  public void setGrid(boolean _isGridOn) {
    isGridOn = _isGridOn;
  }

  /**
   *    Sets whether ticks (small marks on the x and y axis to indicate increment size)
   *    should be drawn on line graphs and bar graphs.
   *
   *    @param _isTicksOn   whether ticks should be drawn
   */
  public void setTicks(boolean _isTicksOn) {
    isTicksOn = _isTicksOn;

  }

  /**
   *
   *    @param _xVals   array of x data values
   */
  public void setXVals(double _xVals[]) {
    xVals = _xVals;
  }

  /**
   *    Sets Y data values - indicate height of bars for bar graphics.graph. Not set for pie.
   *
   *    @param _yVals   array of y data values
   */
  public void setYVals(double _yVals[]) {
    yVals = _yVals;
  }




  //BEGIN GETTER METHODS

  /**
   *    Gets image width.
   *
   *    @return width   image width (not frame width)
   */

  public int getWidth() {
    return width;
  }

  /**
   *    Gets image height.
   *
   *    @return height  image height (not frame height)
   */
  public int getHeight() {
    return height;
  }


  /**
   *    Gets x-axis label on bar graphs and line graphs.
   *
   *    @return xLabel  x-axis label
   */
  public String getXLabel() {
    return xLabel;
  }

  /**
   *    Gets y-axis label on bar graphs and line graphs.
   *
   *    @return yLabel  y-axis label
   */
  public String getYLabel() {
    return yLabel;
  }

  /**
   *    Gets title of all graphs.
   *
   *    @return title   Graph title
   */
  public String getTitle() {
    return title;
  }

  /**
   *    Gets whether or not a grid (lines the height and breadth of the image indicating
   *    increment size) should be drawn on line graphs and bar graphs.
   *
   *    @return isGridOn    whether a grid should be drawn
   */
  public boolean isGridOn() {
    return isGridOn;
  }

  /**
   *    Gets whether ticks (small marks on the x and y axis to indicate increment size)
   *    should be drawn on line graphs and bar graphs.
   *
   *    @return isTicksOn   whether ticks should be drawn
   */
  public boolean isTicksOn() {
    return isTicksOn;
  }

  /**
   *    Gets X data values - the only values which are set for pie graphs.
   *
   *    @return xVals   array of x data values
   */
  public double[] getXVals() {
    return xVals;
  }

  /**
   *    Gets Y data values - indicate height of bars for bar graphics.graph. Not set for pie.
   *
   *    @return yVals   array of y data values
   */
  public double[] getYVals() {
    return yVals;
  }


//BEGIN UTILITY METHODS

  /**
   *    Calculates the maximum value in a given array.
   *
   *    @param _vals        The array to find the maximum number of
   *    @return largestVal  The maximum value contained in the array
   *    @see                #getYAxisCoord
   *    @see                #getXAxisCoord
   */
  protected double getMax(double vals[]) {
    double largestVal = LITTLENUM;
    for (int i = 0; i < vals.length; i++) {
      if (vals[i] > largestVal) {
        largestVal = vals[i];
      }
    }
    return largestVal;
  }


  /**
   *    Calculates the maximum absolute value contained in a given array.
   *
   *    @param vals         The array whose absolute value maximum should be found
   *    @return largestVal  The maximum absolute value contained in the array
   *    @see                #getIncrementNew
   */
  protected double getAbsMax(double vals[]) {
    double largestVal = LITTLENUM;
    for (int i = 0; i < vals.length; i++) {
      if (Math.abs(vals[i]) > largestVal) {
        largestVal = Math.abs(vals[i]);
      }
    }

    return largestVal;
  }

  /**
   *    Calculates the minimum value in a given array.
   *
   *    @param _vals        The array to find the minimum number of
   *    @return smallestVal The minimum value contained in the array
   *    @see                #getYAxisCoord
   *    @see                #getXAxisCoord
   */
  protected double getMin(double vals[]) {
    double smallestVal = BIGNUM;
    for (int i = 0; i < vals.length; i++) {
      if (vals[i] < smallestVal) {
        smallestVal = vals[i];
      }
    }
    return smallestVal;
  }

  /**
   *    Calculates the minimum absolute value contained in a given array.
   *
   *    @param vals         The array whose absolute value minimum should be found
   *    @return smallestVal The minimum absolute value contained in the array
   *    @see                #getYAxisCoord
   */
  protected double getAbsMin(double vals[]) {
    double smallestVal = BIGNUM;
    for (int i = 0; i < vals.length; i++) {
      if (Math.abs(vals[i]) < smallestVal) {
        smallestVal = vals[i];
      }
    }
    return smallestVal;
  }

  /**
   *    Calculates the difference between the two numbers passed to the function.
   *
   *    @param min          The number to subtract
   *    @param max          The number to subtract from
   *    @return delta       The difference between the two numbers
   *    @see                #getIncrementNew
   *    @see                #getNumTicks
   *    @see                #getDeltaY
   *    @see                #getDeltaX
   */
  protected double getDelta(double min, double max) {
    double delta;
    delta = max - min;
    return delta;
  }

  /**
   *    Calculates the difference between the smallest and largest values in the
   *    array initialized as xVals
   *
   *    @return deltaX      The difference between the smallest X value and the largest
   *    @see                #getXOrigin
   *    @see                LineGraph.#getXScreenCoords2
   */
  protected double getDeltaX() {
    double deltaX = getDelta(getMin(getXVals()), getMax(getXVals()));
    return deltaX;
  }


  /**
   *    Calculates the difference between the smallest and largest values in the
   *    array initialized as yVals
   *
   *    @return deltaY      The difference between the smallest Y value and the largest

   *    @see                LineGraph.#getYScreenCoords2
   *    @see                #getYOrigin
   */
  protected double getDeltaY() {
    double deltaY = getDelta(getMin(yVals), getMax(yVals));
    return deltaY;
  }

  /**
   *    Calculates the increment (building block) size for a given image size and delta
   *
   *    @param size         The available image size in this direction (width OR height)
   *    @param delta        Distance between largest and smallest values along this axis
   *    @return increment   The "building block" size

   *    @see                #getXIncrement
   *    @see                #getYIncrement
   *    @see                #getNumTicks
   */

  protected double getIncrement(int size, double delta) {
    double increment;
    if (delta == 0) {
      increment = 0;
    } else {
      increment = (size / delta);
    }
    return increment;
  }

  /**
   *    Calculates the increment (building block) size for a given image size and delta
   *    Overridden with an int delta for convenience' sake in drawing bar graphics.graph
   *
   *    @param size         The available image size in this direction (width OR height)
   *    @param delta        Distance between largest and smallest values along this axis
   *    @return increment   The "building block" size
   *    @see                BarGraph.#drawGraph
   */

  protected int getIncrement(int size, int delta) {
    int increment;
    if (delta == 0) {
      increment = 0;
    } else {
      increment = (size / delta);
    }
    return increment;
  }


  /**
   *    Calculates the increment (building block) size for a given image size and array of values
   *
   *    @param vals         The values to find the increment for
   *    @param size         Image size in this direction
   *    @return increment   The "building block" size
   *    @see                LineGraph.#getXScreenCoords2
   */

  protected double getIncrementNew(double[] vals, int size) {
    double absMax = getAbsMax(vals);
    double max = getMax(vals);
    double minNum = getMin(vals);
    double increment;

    if (absMax == 0) {
      increment = 0;
    } else if (minNum < 0 && max > 0) {
      double delta = getDelta(minNum, getMax(vals));
      increment = getIncrement(size, delta);
    } else if (max < 0) {
      increment = -(size / absMax);
    } else {
      increment = (size / absMax);
    }
    return increment;

  }

  /**
   *    Calculates the Y increment (building block) size, given the
   *    values for Y held in yVals and the image size held in height
   *
   *    @return yIncrement  The "building block" size
   *    @see                LineGraph.#getYScreenCoords2
   *    @see                #getYAxisCoord
   *    @see                BarGraph.#drawGraph
   *    @see                DrawUtil.#drawTicks
   */
  protected double getYIncrement() {
    double yIncrement = getIncrement(getHeight(), getDeltaY());
    return yIncrement;
  }

  /**
   *    Calculates the X increment (building block) size, given the
   *    values for X held in xVals and the image size held in width
   *
   *    @return xIncrement  The "building block" size
   *    @see                LineGraph.#getYScreenCoords2
   *    @see                #getXAxisCoord
   */
  protected double getXIncrement() {
    double xIncrement = getIncrement(getWidth(), getDeltaX());
    return xIncrement;
  }


  /**
   *    Calculates the x value of the x axis, correcting for the
   *    GUI offset. If the smallest X value is greater than zero, the X axis is simply
   *    placed at zero plus the offset. If the smallest X value is less than zero,
   *    x axis is placed to the right the amount of the smallest value.
   *
   *    @param xVals        The data which should be used to calculate the origin
   *    @return xOrigin     The x-axis location
   *    @see                LineGraph.#getXScreenCoords2
   *    @see                #getXOrigin
   *    @see                BarGraph.#drawGraph
   *    @see                DrawUtil.#drawTicks
   *    @see                DrawUtil.#drawAxes2
   *    @see                DrawUtil.#drawYLabel
   */

  protected double getXAxisCoord() {
    double deltaX = getDeltaX();
    double xIncrement = getXIncrement();
    double getMinX = getMin(xVals);
    double getMaxX = getMax(xVals);

    double xAxisCoord = (getMin(xVals) * xIncrement);
    if (xAxisCoord >= 0) {
      xAxisCoord = 0 + X_OFFSET;
    } else if (getMinX < 0 && getMaxX > 0) {
      xAxisCoord = Math.abs(xAxisCoord); //+X_OFFSET
    } else {
      xAxisCoord = width - X_OFFSET;
    }
    return xAxisCoord;

  }


  /**
   *    Calculates the y value of the y axis, correcting for the
   *    GUI offset. If the smallest Y value is greater than zero, the Y axis is simply
   *    placed at the height of the maximum data point times the increment (which
   *    works out to approximately the image height). If the smallest Y value is
   *    less than zero, the y axis is placed towards the center of the image
   *    the amount of the smallest value.
   *
   *    @param yVals        The data which should be used to calculate the origin
   *    @return yOrigin     The y-axis location
   *    @see                LineGraph.#getYScreenCoords2
   *    @see                BarGraph.#getYCoord
   *    @see                BarGraph.#drawGraph
   *    @see                DrawUtil.#drawXLabel
   */

  protected double getYAxisCoord() {
    double deltaY = getDeltaY();
    double yIncrement = getYIncrement();
    double minY = getMin(yVals);
    double absMaxY = getAbsMax(yVals);
    double maxY = getMax(yVals);

    double yAxisCoord = (absMaxY * yIncrement);
    if (minY < 0 && maxY > 0) {
      yAxisCoord = yAxisCoord - getAbsMin(yVals);
    } else if (minY < 0 && maxY < 0) {
      yAxisCoord = 30;
    }
    return yAxisCoord;
  }


  /**
   *    Integer version of the getXOrigin method; used in draw methods which take
   *    integer arguments
   *    @return xOrigin     the value of the x-axis x coordinate
   *    @see                #getXOrigin(double)
   *    @see                DrawUtil.#drawTicks
   *    @see                DrawUtil.#drawAxes2
   */
  protected int getXOrigin() {
    double xOrigin = getXAxisCoord();
    return (int) xOrigin;
  }

  /**
   *    Integer version of the getYOrigin method; used in draw methods which take
   *    integer arguments
   *    @return yOrigin     the value of the y-axis y coordinate
   *    @see                #getYOrigin(double)
   *    @see                DrawUtil.#drawTicks
   *    @see                DrawUtil.#drawAxes2
   */
  protected int getYOrigin() {
    double yOrigin = getYAxisCoord();
    return (int) yOrigin;
  }

  /**
   *    Method used to calculate how many increments there are altogether, used
   *    for drawing ticks and grid
   *    @param vals                 The data that is being measured
   *    @param size                 The size (avaialble height OR width) of the image
   *    @return numIncrements       The number of increments in this data in this size image
   *    @see                        DrawUtil.#drawTicks
   *    @see                        DrawUtil.#drawGrid
   */

  protected int getNumTicks(double[] vals, int size) {
    double delta = getDelta(getMin(vals), getMax(vals));
    double increment = getIncrement(size, delta);
    int numIncrements = (int) (size / increment);

    return numIncrements;

  }


}