content: 
  package com.github.mikephil.charting.charts;
  
  import android.annotation.SuppressLint;
  import android.content.Context;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Matrix;
  import android.graphics.Paint;
  import android.graphics.Paint.Align;
  import android.graphics.Paint.Style;
  import android.graphics.PointF;
  import android.graphics.Rect;
  import android.util.AttributeSet;
  import android.util.Log;
  import android.view.MotionEvent;
  
  import com.github.mikephil.charting.data.BarDataSet;
  import com.github.mikephil.charting.data.BarLineScatterCandleData;
  import com.github.mikephil.charting.data.BarLineScatterCandleRadarDataSet;
  import com.github.mikephil.charting.data.Entry;
  import com.github.mikephil.charting.data.filter.Approximator;
  import com.github.mikephil.charting.interfaces.OnDrawListener;
  import com.github.mikephil.charting.listener.BarLineChartTouchListener;
  import com.github.mikephil.charting.utils.Highlight;
  import com.github.mikephil.charting.utils.Legend.LegendPosition;
  import com.github.mikephil.charting.utils.LimitLine;
  import com.github.mikephil.charting.utils.LimitLine.LimitLabelPosition;
  import com.github.mikephil.charting.utils.PointD;
  import com.github.mikephil.charting.utils.SelInfo;
  import com.github.mikephil.charting.utils.Utils;
  import com.github.mikephil.charting.utils.XLabels;
  import com.github.mikephil.charting.utils.XLabels.XLabelPosition;
  import com.github.mikephil.charting.utils.YLabels;
  import com.github.mikephil.charting.utils.YLabels.YLabelPosition;
  
  import java.util.ArrayList;
  
  /**
   * Base-class of LineChart, BarChart, ScatterChart and CandleStickChart.
   * 
   * @author Philipp Jahoda
   */
  @SuppressLint("RtlHardcoded")
  public abstract class BarLineChartBase<T extends BarLineScatterCandleData<? extends BarLineScatterCandleRadarDataSet<? extends Entry>>>
          extends Chart<T> {
  
      /** the maximum number of entried to which values will be drawn */
      protected int mMaxVisibleCount = 100;
  
      /** the width of the grid lines */
      protected float mGridWidth = 1f;
  
      /**
       * flag that indicates if pinch-zoom is enabled. if true, both x and y axis
       * can be scaled with 2 fingers, if false, x and y axis can be scaled
       * separately
       */
      protected boolean mPinchZoomEnabled = false;
  
      /** flat that indicates if double tap zoom is enabled or not */
      protected boolean mDoubleTapToZoomEnabled = true;
  
      /** if true, dragging is enabled for the chart */
      private boolean mDragEnabled = true;
  
      /** if true, scaling is enabled for the chart */
      private boolean mScaleEnabled = true;
  
      /** if true, the y range is predefined */
      protected boolean mFixedYValues = false;
  
      /** if true, the y-label entries will always start at zero */
      protected boolean mStartAtZero = true;
  
      /** if true, data filtering is enabled */
      protected boolean mFilterData = false;
  
      /** paint object for the grid lines */
      protected Paint mGridPaint;
  
      /** paint object for the (by default) lightgrey background of the grid */
      protected Paint mGridBackgroundPaint;
  
      /** paint for the line surrounding the chart */
      protected Paint mBorderPaint;
  
      /**
       * if set to true, the highlight indicator (lines for linechart, dark bar
       * for barchart) will be drawn upon selecting values.
       */
      protected boolean mHighLightIndicatorEnabled = true;
  
      /** flag indicating if the vertical grid should be drawn or not */
      protected boolean mDrawVerticalGrid = true;
  
      /** flag indicating if the horizontal grid should be drawn or not */
      protected boolean mDrawHorizontalGrid = true;
  
      /** flag indicating if the y-labels should be drawn or not */
      protected boolean mDrawYLabels = true;
  
      /** flag indicating if the x-labels should be drawn or not */
      protected boolean mDrawXLabels = true;
  
      /** flag indicating if the chart border rectangle should be drawn or not */
      protected boolean mDrawBorder = true;
  
      /** flag indicating if the grid background should be drawn or not */
      protected boolean mDrawGridBackground = true;
  
      /** the listener for user drawing on the chart */
      protected OnDrawListener mDrawListener;
  
      /**
       * the object representing the labels on the y-axis, this object is prepared
       * in the pepareYLabels() method
       */
      protected YLabels mYLabels = new YLabels();
  
      /** the object representing the labels on the x-axis */
      protected XLabels mXLabels = new XLabels();
  
      // /** the approximator object used for data filtering */
      // private Approximator mApproximator;
  
      public BarLineChartBase(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
      }
  
      public BarLineChartBase(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
  
      public BarLineChartBase(Context context) {
          super(context);
      }
  
      @Override
      protected void init() {
          super.init();
  
          mListener = new BarLineChartTouchListener(this, mTrans.getTouchMatrix());
  
          mGridPaint = new Paint();
          mGridPaint.setColor(Color.GRAY);
          mGridPaint.setStrokeWidth(mGridWidth);
          mGridPaint.setStyle(Style.STROKE);
          mGridPaint.setAlpha(90);
  
          mBorderPaint = new Paint();
          mBorderPaint.setColor(Color.BLACK);
          mBorderPaint.setStrokeWidth(mGridWidth * 2f);
          mBorderPaint.setStyle(Style.STROKE);
  
          mGridBackgroundPaint = new Paint();
          mGridBackgroundPaint.setStyle(Style.FILL);
          // mGridBackgroundPaint.setColor(Color.WHITE);
          mGridBackgroundPaint.setColor(Color.rgb(240, 240, 240)); // light
          // grey
      }
  
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
  
          if (mDataNotSet)
              return;
  
          long starttime = System.currentTimeMillis();
  
          // if data filtering is enabled
          if (mFilterData) {
              mData = getFilteredData();
  
              Log.i(LOG_TAG, "FilterTime: " + (System.currentTimeMillis() -
                      starttime) + " ms");
              starttime = System.currentTimeMillis();
          } else {
              mData = getData();
              // Log.i(LOG_TAG, "Filtering disabled.");
          }
  
          if (mXLabels.isAdjustXLabelsEnabled())
              calcModulus();
  
          // execute all drawing commands
          drawGridBackground();
  
          prepareYLabels();
  
          // make sure the graph values and grid cannot be drawn outside the
          // content-rect
          int clipRestoreCount = mDrawCanvas.save();
          mDrawCanvas.clipRect(mContentRect);
  
          drawHorizontalGrid();
  
          drawVerticalGrid();
  
          drawData();
  
          drawLimitLines();
  
          // if highlighting is enabled
          if (mHighlightEnabled && mHighLightIndicatorEnabled && valuesToHighlight())
              drawHighlights();
  
          // Removes clipping rectangle
          mDrawCanvas.restoreToCount(clipRestoreCount);
  
          drawAdditional();
  
          drawXLabels();
  
          drawYLabels();
  
          drawValues();
  
          drawLegend();
  
          drawBorder();
  
          drawMarkers();
  
          drawDescription();
  
          canvas.drawBitmap(mDrawBitmap, 0, 0, mDrawPaint);
  
          if (mLogEnabled)
              Log.i(LOG_TAG, "DrawTime: " + (System.currentTimeMillis() - starttime) + " ms");
      }
  
      /**
       * does all necessary preparations, needed when data is changed or flags
       * that effect the data are changed
       */
      @Override
      public void prepare() {
  
          if (mDataNotSet)
              return;
  
          calcMinMax(mFixedYValues);
  
          prepareYLabels();
  
          prepareXLabels();
  
          prepareLegend();
  
          calculateOffsets();
      }
  
      /**
       * Sets up all the matrices that will be used for scaling the coordinates to
       * the display. Offset and Value-px.
       */
      private void prepareMatrix() {
  
          mTrans.prepareMatrixValuePx(this);
  
          mTrans.prepareMatrixOffset(this);
  
          if (mLogEnabled)
              Log.i(LOG_TAG, "Matrices prepared.");
      }
  
      @Override
      public void notifyDataSetChanged() {
          if (!mFixedYValues) {
              prepare();
              // prepareContentRect();
              mTrans.prepareMatrixValuePx(this);
          } else {
              calcMinMax(mFixedYValues);
          }
      }
  
      @Override
      protected void calculateOffsets() {
  
          float legendRight = 0f, legendBottom = 0f;
  
          // setup offsets for legend
          if (mDrawLegend && mLegend != null && mLegend.getPosition() != LegendPosition.NONE) {
  
              if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART
                      || mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART_CENTER) {
  
                  // this is the space between the legend and the chart
                  float spacing = Utils.convertDpToPixel(12f);
  
                  legendRight = mLegend.getMaximumEntryLength(mLegendLabelPaint)
                          + mLegend.getFormSize() + mLegend.getFormToTextSpace() + spacing;
  
                  mLegendLabelPaint.setTextAlign(Align.LEFT);
  
              } else if (mLegend.getPosition() == LegendPosition.BELOW_CHART_LEFT
                      || mLegend.getPosition() == LegendPosition.BELOW_CHART_RIGHT
                      || mLegend.getPosition() == LegendPosition.BELOW_CHART_CENTER) {
  
                  if (mXLabels.getPosition() == XLabelPosition.TOP)
                      legendBottom = mLegendLabelPaint.getTextSize() * 3.5f;
                  else {
                      legendBottom = mLegendLabelPaint.getTextSize() * 2.5f;
                  }
              }
  
              mLegend.setOffsetBottom(legendBottom);
              mLegend.setOffsetRight(legendRight);
          }
  
          float yleft = 0f, yright = 0f;
  
          // String label = mYLabels.getFormattedLabel(mYLabels.mEntryCount - 1);
          String label = mYLabels.getLongestLabel();
  
          // calculate the maximum y-label width (including eventual offsets)
          float ylabelwidth = Utils.calcTextWidth(mYLabelPaint,
                  label + mUnit + (mYChartMin < 0 ? "----" : "+++")); // offsets
  
          if (mDrawYLabels) {
  
              // offsets for y-labels
              if (mYLabels.getPosition() == YLabelPosition.LEFT) {
  
                  yleft = ylabelwidth;
                  mYLabelPaint.setTextAlign(Align.RIGHT);
  
              } else if (mYLabels.getPosition() == YLabelPosition.RIGHT) {
  
                  yright = ylabelwidth;
                  mYLabelPaint.setTextAlign(Align.LEFT);
  
              } else if (mYLabels.getPosition() == YLabelPosition.BOTH_SIDED) {
  
                  yright = ylabelwidth;
                  yleft = ylabelwidth;
              }
          }
  
          float xtop = 0f, xbottom = 0f;
  
          float xlabelheight = Utils.calcTextHeight(mXLabelPaint, "Q") * 2f;
  
          if (mDrawXLabels) {
  
              // offsets for x-labels
              if (mXLabels.getPosition() == XLabelPosition.BOTTOM) {
  
                  xbottom = xlabelheight;
  
              } else if (mXLabels.getPosition() == XLabelPosition.TOP) {
  
                  xtop = xlabelheight;
  
              } else if (mXLabels.getPosition() == XLabelPosition.BOTH_SIDED) {
  
                  xbottom = xlabelheight;
                  xtop = xlabelheight;
              }
          }
  
          // all required offsets are calculated, now find largest and apply
          float min = Utils.convertDpToPixel(11f);
  
          mOffsetBottom = Math.max(min, xbottom + legendBottom);
          mOffsetTop = Math.max(min, xtop);
  
          mOffsetLeft = Math.max(min, yleft);
          mOffsetRight = Math.max(min, yright + legendRight);
  
          if (mLegend != null) {
  
              // those offsets are equal for legend and other chart, just apply
              // them
              mLegend.setOffsetTop(mOffsetTop + min / 3f);
              mLegend.setOffsetLeft(mOffsetLeft);
          }
  
          prepareContentRect();
  
          prepareMatrix();
      }
  
      /**
       * Calculates the offsets that belong to the legend, this method is only
       * relevant when drawing into the chart. It can be used to refresh the
       * legend.
       */
      public void calculateLegendOffsets() {
  
          // setup offsets for legend
          if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART) {
  
              mLegend.setOffsetRight(mLegend.getMaximumEntryLength(mLegendLabelPaint));
              mLegendLabelPaint.setTextAlign(Align.LEFT);
  
          } else if (mLegend.getPosition() == LegendPosition.BELOW_CHART_LEFT
                  || mLegend.getPosition() == LegendPosition.BELOW_CHART_RIGHT) {
  
              if (mXLabels.getPosition() == XLabelPosition.TOP)
                  mLegend.setOffsetBottom(mLegendLabelPaint.getTextSize() * 3.5f);
              else {
                  mLegend.setOffsetBottom(mLegendLabelPaint.getTextSize() * 2.5f);
              }
          }
      }
  
      /**
       * calculates the modulus for x-labels and grid
       */
      protected void calcModulus() {
  
          float[] values = new float[9];
          mTrans.getTouchMatrix().getValues(values);
  
          mXLabels.mXAxisLabelModulus = (int) Math
                  .ceil((mData.getXValCount() * mXLabels.mLabelWidth)
                          / (mContentRect.width() * values[Matrix.MSCALE_X]));
      }
  
      @Override
      protected void calcMinMax(boolean fixedValues) {
          super.calcMinMax(fixedValues); // calc min and max in the super class
  
          if (!fixedValues) {
  
              // additional handling for space (default 15% space)
              // float space = Math.abs(mDeltaY / 100f * 15f);
              float space = Math
                      .abs(Math.abs(Math.max(Math.abs(mYChartMax), Math.abs(mYChartMin))) / 100f * 20f);
  
              if (Math.abs(mYChartMax - mYChartMin) < 0.00001f) {
                  if (Math.abs(mYChartMax) < 10f)
                      space = 1f;
                  else
                      space = Math.abs(mYChartMax / 100f * 20f);
              }
  
              if (mStartAtZero) {
  
                  if (mYChartMax < 0) {
                      mYChartMax = 0;
                      // calc delta
                      mYChartMin = mYChartMin - space;
                  } else {
                      mYChartMin = 0;
                      // calc delta
                      mYChartMax = mYChartMax + space;
                  }
              } else {
  
                  mYChartMin = mYChartMin - space / 2f;
                  mYChartMax = mYChartMax + space / 2f;
              }
          }
  
          mDeltaY = Math.abs(mYChartMax - mYChartMin);
      }
  
      /**
       * setup the x-axis labels
       */
      protected void prepareXLabels() {
  
          StringBuffer a = new StringBuffer();
  
          int max = (int) Math.round(mData.getXValAverageLength()
                  + mXLabels.getSpaceBetweenLabels());
  
          for (int i = 0; i < max; i++) {
              a.append("h");
          }
  
          mXLabels.mLabelWidth = Utils.calcTextWidth(mXLabelPaint, a.toString());
          mXLabels.mLabelHeight = Utils.calcTextHeight(mXLabelPaint, "Q");
      }
  
      /**
       * Sets up the y-axis labels. Computes the desired number of labels between
       * the two given extremes. Unlike the papareXLabels() method, this method
       * needs to be called upon every refresh of the view.
       * 
       * @return
       */
      protected void prepareYLabels() {
  
          float yMin = 0f;
          float yMax = 0f;
  
          // calculate the starting and entry point of the y-labels (depending on
          // zoom / contentrect bounds)
          if (mContentRect.width() > 10 && !mTrans.isFullyZoomedOutY()) {
  
              PointD p1 = getValuesByTouchPoint(mContentRect.left, mContentRect.top);
              PointD p2 = getValuesByTouchPoint(mContentRect.left, mContentRect.bottom);
  
              if (!mTrans.isInvertYAxisEnabled()) {
                  yMin = (float) p2.y;
                  yMax = (float) p1.y;
              } else {
  
                  if (!mStartAtZero)
                      yMin = (float) Math.min(p1.y, p2.y);
                  else
                      yMin = 0;
                  yMax = (float) Math.max(p1.y, p2.y);
              }
  
          } else {
  
              if (!mTrans.isInvertYAxisEnabled()) {
                  yMin = mYChartMin;
                  yMax = mYChartMax;
              } else {
  
                  if (!mStartAtZero)
                      yMin = (float) Math.min(mYChartMax, mYChartMin);
                  else
                      yMin = 0;
                  yMax = (float) Math.max(mYChartMax, mYChartMin);
              }
          }
  
          int labelCount = mYLabels.getLabelCount();
          double range = Math.abs(yMax - yMin);
  
          if (labelCount == 0 || range <= 0) {
              mYLabels.mEntries = new float[] {};
              mYLabels.mEntryCount = 0;
              return;
          }
  
          double rawInterval = range / labelCount;
          double interval = Utils.roundToNextSignificant(rawInterval);
          double intervalMagnitude = Math.pow(10, (int) Math.log10(interval));
          int intervalSigDigit = (int) (interval / intervalMagnitude);
          if (intervalSigDigit > 5) {
              // Use one order of magnitude higher, to avoid intervals like 0.9 or
              // 90
              interval = Math.floor(10 * intervalMagnitude);
          }
  
          // if the labels should only show min and max
          if (mYLabels.isShowOnlyMinMaxEnabled()) {
  
              mYLabels.mEntryCount = 2;
              mYLabels.mEntries = new float[2];
              mYLabels.mEntries[0] = mYChartMin;
              mYLabels.mEntries[1] = mYChartMax;
  
          } else {
  
              double first = Math.ceil(yMin / interval) * interval;
              double last = Utils.nextUp(Math.floor(yMax / interval) * interval);
  
              double f;
              int i;
              int n = 0;
              for (f = first; f <= last; f += interval) {
                  ++n;
              }
  
              mYLabels.mEntryCount = n;
  
              if (mYLabels.mEntries.length < n) {
                  // Ensure stops contains at least numStops elements.
                  mYLabels.mEntries = new float[n];
              }
  
              for (f = first, i = 0; i < n; f += interval, ++i) {
                  mYLabels.mEntries[i] = (float) f;
              }
          }
  
          if (interval < 1) {
              mYLabels.mDecimals = (int) Math.ceil(-Math.log10(interval));
          } else {
              mYLabels.mDecimals = 0;
          }
      }
  
      /**
       * draws the x-axis labels to the screen depending on their position
       */
      private void drawXLabels() {
  
          if (!mDrawXLabels)
              return;
  
          float yoffset = Utils.convertDpToPixel(4f);
  
          mXLabelPaint.setTypeface(mXLabels.getTypeface());
          mXLabelPaint.setTextSize(mXLabels.getTextSize());
          mXLabelPaint.setColor(mXLabels.getTextColor());
  
          if (mXLabels.getPosition() == XLabelPosition.TOP) {
  
              drawXLabels(getOffsetTop() - yoffset);
  
          } else if (mXLabels.getPosition() == XLabelPosition.BOTTOM) {
  
              drawXLabels(getHeight() - mOffsetBottom + mXLabels.mLabelHeight + yoffset * 1.5f);
  
          } else if (mXLabels.getPosition() == XLabelPosition.BOTTOM_INSIDE) {
  
              drawXLabels(getHeight() - getOffsetBottom() - yoffset);
  
          } else if (mXLabels.getPosition() == XLabelPosition.TOP_INSIDE) {
  
              drawXLabels(getOffsetTop() + yoffset + mXLabels.mLabelHeight);
  
          } else { // BOTH SIDED
  
              drawXLabels(getOffsetTop() - 7);
              drawXLabels(getHeight() - mOffsetBottom + mXLabels.mLabelHeight + yoffset * 1.6f);
          }
      }
  
      /**
       * draws the x-labels on the specified y-position
       * 
       * @param yPos
       */
      protected void drawXLabels(float yPos) {
  
          // pre allocate to save performance (dont allocate in loop)
          float[] position = new float[] {
                  0f, 0f
          };
  
          for (int i = 0; i < mData.getXValCount(); i += mXLabels.mXAxisLabelModulus) {
  
              position[0] = i;
  
              // center the text
              if (mXLabels.isCenterXLabelsEnabled())
                  position[0] += 0.5f;
  
              mTrans.pointValuesToPixel(position);
  
              if (position[0] >= mOffsetLeft && position[0] <= getWidth() - mOffsetRight) {
  
                  String label = mData.getXVals().get(i);
  
                  if (mXLabels.isAvoidFirstLastClippingEnabled()) {
  
                      // avoid clipping of the last
                      if (i == mData.getXValCount() - 1) {
                          float width = Utils.calcTextWidth(mXLabelPaint, label);
  
                          if (width > getOffsetRight() * 2 && position[0] + width > getWidth())
                              position[0] -= width / 2;
  
                          // avoid clipping of the first
                      } else if (i == 0) {
  
                          float width = Utils.calcTextWidth(mXLabelPaint, label);
                          position[0] += width / 2;
                      }
                  }
  
                  mDrawCanvas.drawText(label, position[0],
                          yPos,
                          mXLabelPaint);
              }
          }
      }
  
      /**
       * draws the y-axis labels to the screen
       */
      private void drawYLabels() {
  
          if (!mDrawYLabels)
              return;
  
          float[] positions = new float[mYLabels.mEntryCount * 2];
  
          for (int i = 0; i < positions.length; i += 2) {
              // only fill y values, x values are not needed since the y-labels
              // are
              // static on the x-axis
              positions[i + 1] = mYLabels.mEntries[i / 2];
          }
  
          mTrans.pointValuesToPixel(positions);
  
          mYLabelPaint.setTypeface(mYLabels.getTypeface());
          mYLabelPaint.setTextSize(mYLabels.getTextSize());
          mYLabelPaint.setColor(mYLabels.getTextColor());
  
          float xoffset = Utils.convertDpToPixel(5f);
          float yoffset = Utils.calcTextHeight(mYLabelPaint, "A") / 2.5f;
  
          // determine position and draw adequately
          if (mYLabels.getPosition() == YLabelPosition.LEFT) {
  
              mYLabelPaint.setTextAlign(Align.RIGHT);
              drawYLabels(mOffsetLeft - xoffset, positions, yoffset);
  
          } else if (mYLabels.getPosition() == YLabelPosition.RIGHT) {
  
              mYLabelPaint.setTextAlign(Align.LEFT);
              drawYLabels(getWidth() - mOffsetRight + xoffset, positions, yoffset);
  
          } else if (mYLabels.getPosition() == YLabelPosition.RIGHT_INSIDE) {
  
              mYLabelPaint.setTextAlign(Align.RIGHT);
              drawYLabels(getWidth() - mOffsetRight - xoffset, positions, yoffset);
  
          } else if (mYLabels.getPosition() == YLabelPosition.LEFT_INSIDE) {
  
              mYLabelPaint.setTextAlign(Align.LEFT);
              drawYLabels(mOffsetLeft + xoffset, positions, yoffset);
  
          } else { // BOTH SIDED Y-AXIS LABELS
  
              // draw left legend
              mYLabelPaint.setTextAlign(Align.RIGHT);
              drawYLabels(mOffsetLeft - xoffset, positions, yoffset);
  
              // draw right legend
              mYLabelPaint.setTextAlign(Align.LEFT);
              drawYLabels(getWidth() - mOffsetRight + xoffset, positions, yoffset);
          }
      }
  
      /**
       * draws the y-labels on the specified x-position
       * 
       * @param xPos
       * @param positions
       */
      private void drawYLabels(float xPos, float[] positions, float yOffset) {
  
          // draw
          for (int i = 0; i < mYLabels.mEntryCount; i++) {
  
              String text = mYLabels.getFormattedLabel(i);
  
              if (!mYLabels.isDrawTopYLabelEntryEnabled() && i >= mYLabels.mEntryCount - 1)
                  return;
  
              if (mYLabels.isDrawUnitsInYLabelEnabled()) {
                  mDrawCanvas.drawText(text + mUnit, xPos, positions[i * 2 + 1] + yOffset,
                          mYLabelPaint);
              } else {
                  mDrawCanvas.drawText(text, xPos, positions[i * 2 + 1] + yOffset, mYLabelPaint);
              }
          }
      }
  
      /** enums for all different border styles */
      public enum BorderPosition {
          LEFT, RIGHT, TOP, BOTTOM
      }
  
      /**
       * array that holds positions where to draw the chart border lines
       */
      private BorderPosition[] mBorderPositions = new BorderPosition[] {
              BorderPosition.BOTTOM
      };
  
      /**
       * draws a line that surrounds the chart
       */
      protected void drawBorder() {
  
          if (!mDrawBorder || mBorderPositions == null)
              return;
  
          for (int i = 0; i < mBorderPositions.length; i++) {
  
              if (mBorderPositions[i] == null)
                  continue;
  
              switch (mBorderPositions[i]) {
                  case LEFT:
                      mDrawCanvas.drawLine(mOffsetLeft, mOffsetTop, mOffsetLeft, getHeight()
                              - mOffsetBottom, mBorderPaint);
                      break;
                  case RIGHT:
                      mDrawCanvas.drawLine(getWidth() - mOffsetRight, mOffsetTop, getWidth()
                              - mOffsetRight, getHeight()
                              - mOffsetBottom, mBorderPaint);
                      break;
                  case TOP:
                      mDrawCanvas.drawLine(mOffsetLeft, mOffsetTop, getWidth() - mOffsetRight,
                              mOffsetTop, mBorderPaint);
                      break;
                  case BOTTOM:
                      mDrawCanvas.drawLine(mOffsetLeft, getHeight()
                              - mOffsetBottom, getWidth() - mOffsetRight, getHeight()
                              - mOffsetBottom, mBorderPaint);
                      break;
              }
          }
      }
  
      /**
       * draws the grid background
       */
      protected void drawGridBackground() {
  
          if (!mDrawGridBackground)
              return;
  
          Rect gridBackground = new Rect((int) mOffsetLeft + 1, (int) mOffsetTop + 1, getWidth()
                  - (int) mOffsetRight,
                  getHeight() - (int) mOffsetBottom);
  
          // draw the grid background
          mDrawCanvas.drawRect(gridBackground, mGridBackgroundPaint);
      }
  
      /**
       * draws the horizontal grid
       */
      protected void drawHorizontalGrid() {
  
          if (!mDrawHorizontalGrid)
              return;
  
          // pre alloc
          float[] position = new float[2];
  
          // draw the horizontal grid
          for (int i = 0; i < mYLabels.mEntryCount; i++) {
  
              position[1] = mYLabels.mEntries[i];
              mTrans.pointValuesToPixel(position);
  
              mDrawCanvas.drawLine(mOffsetLeft, position[1], getWidth() - mOffsetRight, position[1],
                      mGridPaint);
          }
      }
  
      /**
       * draws the vertical grid
       */
      protected void drawVerticalGrid() {
  
          if (!mDrawVerticalGrid || mData == null)
              return;
  
          float[] position = new float[] {
                  0f, 0f
          };
  
          for (int i = 0; i < mData.getXValCount(); i += mXLabels.mXAxisLabelModulus) {
  
              position[0] = i;
  
              mTrans.pointValuesToPixel(position);
  
              if (position[0] >= mOffsetLeft && position[0] <= getWidth()) {
  
                  mDrawCanvas.drawLine(position[0], mOffsetTop, position[0], getHeight()
                          - mOffsetBottom, mGridPaint);
              }
          }
      }
  
      /**
       * Draws the limit lines if there are one.
       */
      private void drawLimitLines() {
  
          ArrayList<LimitLine> limitLines = mData.getLimitLines();
  
          if (limitLines == null)
              return;
  
          float[] pts = new float[4];
  
          for (int i = 0; i < limitLines.size(); i++) {
  
              LimitLine l = limitLines.get(i);
  
              pts[1] = l.getLimit();
              pts[3] = l.getLimit();
  
              mTrans.pointValuesToPixel(pts);
  
              pts[0] = 0;
              pts[2] = getWidth();
  
              mLimitLinePaint.setColor(l.getLineColor());
              mLimitLinePaint.setPathEffect(l.getDashPathEffect());
              mLimitLinePaint.setStrokeWidth(l.getLineWidth());
  
              mDrawCanvas.drawLines(pts, mLimitLinePaint);
  
              // if drawing the limit-value is enabled
              if (l.isDrawValueEnabled()) {
  
                  PointF pos = getPosition(new Entry(l.getLimit(), 0));
  
                  // save text align
                  Align align = mValuePaint.getTextAlign();
  
                  float xOffset = Utils.convertDpToPixel(4f);
                  float yOffset = l.getLineWidth() + xOffset;
                  String label = mValueFormatter.getFormattedValue(l.getLimit());
  
                  if (mDrawUnitInChart)
                      label += mUnit;
  
                  if (l.getLabelPosition() == LimitLabelPosition.RIGHT) {
  
                      mValuePaint.setTextAlign(Align.RIGHT);
                      mDrawCanvas.drawText(label, getWidth() - mOffsetRight
                              - xOffset,
                              pos.y - yOffset, mValuePaint);
  
                  } else {
                      mValuePaint.setTextAlign(Align.LEFT);
                      mDrawCanvas.drawText(label, mOffsetLeft
                              + xOffset,
                              pos.y - yOffset, mValuePaint);
                  }
  
                  mValuePaint.setTextAlign(align);
              }
          }
      }
  
      /**
       * returns true if the specified point (x-axis) exceeds the limits of what
       * is visible to the right side
       * 
       * @param v
       * @return
       */
      protected boolean isOffContentRight(float p) {
          if (p > mContentRect.right)
              return true;
          else
              return false;
      }
  
      /**
       * returns true if the specified point (x-axis) exceeds the limits of what
       * is visible to the left side
       * 
       * @param v
       * @return
       */
      protected boolean isOffContentLeft(float p) {
          if (p < mContentRect.left)
              return true;
          else
              return false;
      }
  
      /**
       * returns true if the specified point (y-axis) exceeds the limits of what
       * is visible on the top
       * 
       * @param v
       * @return
       */
      protected boolean isOffContentTop(float p) {
          if (p < mContentRect.top)
              return true;
          else
              return false;
      }
  
      /**
       * returns true if the specified point (y-axis) exceeds the limits of what
       * is visible on the bottom
       * 
       * @param v
       * @return
       */
      protected boolean isOffContentBottom(float p) {
          if (p > mContentRect.bottom)
              return true;
          else
              return false;
      }
  
      /** touchlistener that handles touches and gestures on the chart */
      protected OnTouchListener mListener;
  
      @Override
      public boolean onTouchEvent(MotionEvent event) {
          super.onTouchEvent(event);
  
          if (mListener == null || mDataNotSet)
              return false;
  
          // check if touch gestures are enabled
          if (!mTouchEnabled)
              return false;
          else
              return mListener.onTouch(this, event);
      }
  
      /**
       * ################ ################ ################ ################
       */
      /** CODE BELOW THIS RELATED TO SCALING AND GESTURES */
  
      /**
       * Zooms in by 1.4f, into the charts center. center.
       */
      public void zoomIn() {
          Matrix save = mTrans.zoomIn(getWidth() / 2f, -(getHeight() / 2f));
          mTrans.refresh(save, this);
      }
  
      /**
       * Zooms out by 0.7f, from the charts center. center.
       */
      public void zoomOut() {
          Matrix save = mTrans.zoomOut(getWidth() / 2f, -(getHeight() / 2f));
          mTrans.refresh(save, this);
      }
  
      /**
       * Zooms in or out by the given scale factor. x and y are the coordinates
       * (in pixels) of the zoom center.
       * 
       * @param scaleX if < 1f --> zoom out, if > 1f --> zoom in
       * @param scaleY if < 1f --> zoom out, if > 1f --> zoom in
       * @param x
       * @param y
       */
      public void zoom(float scaleX, float scaleY, float x, float y) {
          Matrix save = mTrans.zoom(scaleX, scaleY, x, -y);
          mTrans.refresh(save, this);
      }
  
      /**
       * Resets all zooming and dragging and makes the chart fit exactly it's
       * bounds.
       */
      public void fitScreen() {
          Matrix save = mTrans.fitScreen();
          mTrans.refresh(save, this);
      }
  
      /**
       * If this is set to true, the y-axis is inverted which means that low
       * values are on top of the chart, high values on bottom.
       * 
       * @param enabled
       */
      public void setInvertYAxisEnabled(boolean enabled) {
          mTrans.setInvertYAxisEnabled(enabled);
      }
  
      /**
       * If this returns true, the y-axis is inverted.
       * 
       * @return
       */
      public boolean isInvertYAxisEnabled() {
          return mTrans.isInvertYAxisEnabled();
      }
  
      /**
       * Centers the viewport around the specified x-index and the specified
       * y-value in the chart. Centering the viewport outside the bounds of the
       * chart is not possible. Makes most sense in combination with the
       * setScaleMinima(...) method. First set the scale minima, then center the
       * viewport. SHOULD BE CALLED AFTER setting data for the chart.
       * 
       * @param xIndex the index on the x-axis to center to
       * @param yVal the value ont he y-axis to center to
       */
      public synchronized void centerViewPort(final int xIndex, final float yVal) {
  
          float indicesInView = mDeltaX / mTrans.getScaleX();
          float valsInView = mDeltaY / mTrans.getScaleY();
  
          Log.i(LOG_TAG, "indices: " + indicesInView + ", vals: " +
                  valsInView);
  
          float[] pts = new float[] {
                  xIndex - indicesInView / 2f, yVal + valsInView / 2f
          };
  
          mTrans.centerViewPort(pts, this);
      }
  
      /**
       * ################ ################ ################ ################
       */
      /** CODE BELOW IS GETTERS AND SETTERS */
  
      /**
       * set a new (e.g. custom) charttouchlistener NOTE: make sure to
       * setTouchEnabled(true); if you need touch gestures on the chart
       * 
       * @param l
       */
      public void setOnTouchListener(OnTouchListener l) {
          this.mListener = l;
      }
  
      /**
       * Sets the OnDrawListener
       * 
       * @param drawListener
       */
      public void setOnDrawListener(OnDrawListener drawListener) {
          this.mDrawListener = drawListener;
      }
  
      /**
       * Gets the OnDrawListener. May be null.
       * 
       * @return
       */
      public OnDrawListener getDrawListener() {
          return mDrawListener;
      }
  
      /**
       * Sets the minimum scale values for both axes. This limits the extent to
       * which the user can zoom-out. Scale 2f means the user cannot zoom out
       * further than 2x zoom, ... Min = 1f
       * 
       * @param scaleXmin
       * @param scaleYmin
       */
      public void setScaleMinima(float scaleXmin, float scaleYmin) {
          mTrans.setScaleMinima(scaleXmin, scaleYmin, this);
      }
  
      /**
       * Sets the effective range of y-values the chart can display. If this is
       * set, the y-range is fixed and cannot be changed. This means, no
       * recalculation of the bounds of the chart concerning the y-axis will be
       * done when adding new data. To disable this, provide Float.NaN as a
       * parameter or call resetYRange();
       * 
       * @param minY
       * @param maxY
       * @param invalidate if set to true, the chart will redraw itself after
       *            calling this method
       */
      public void setYRange(float minY, float maxY, boolean invalidate) {
  
          if (Float.isNaN(minY) || Float.isNaN(maxY)) {
              resetYRange(invalidate);
              return;
          }
  
          mFixedYValues = true;
  
          mYChartMin = minY;
          mYChartMax = maxY;
          if (minY < 0) {
              mStartAtZero = false;
          }
          mDeltaY = mYChartMax - mYChartMin;
  
          calcFormats();
          prepareMatrix();
          if (invalidate)
              invalidate();
      }
  
      /**
       * Resets the previously set y range. If new data is added, the y-range will
       * be recalculated.
       * 
       * @param invalidate if set to true, the chart will redraw itself after
       *            calling this method
       */
      public void resetYRange(boolean invalidate) {
          mFixedYValues = false;
          calcMinMax(mFixedYValues);
  
          prepareMatrix();
          if (invalidate)
              invalidate();
      }
  
      /**
       * if this returns true, the chart has a fixed range on the y-axis that is
       * not dependant on the actual data in the chart
       * 
       * @return
       */
      public boolean hasFixedYValues() {
          return mFixedYValues;
      }
  
      /**
       * Returns the position (in pixels) the provided Entry has inside the chart
       * view or null, if the provided Entry is null.
       * 
       * @param e
       * @return
       */
      public PointF getPosition(Entry e) {
  
          if (e == null)
              return null;
  
          float[] vals = new float[] {
                  e.getXIndex(), e.getVal()
          };
  
          if (this instanceof BarChart) {
  
              BarDataSet set = (BarDataSet) mData.getDataSetForEntry(e);
              if (set != null)
                  vals[0] += set.getBarSpace() / 2f;
          }
  
          mTrans.pointValuesToPixel(vals);
  
          return new PointF(vals[0], vals[1]);
      }
  
      /**
       * sets the color for the grid lines
       * 
       * @param color
       */
      public void setGridColor(int color) {
          mGridPaint.setColor(color);
      }
  
      /**
       * sets the number of maximum visible drawn values on the chart only active
       * when setDrawValues() is enabled
       * 
       * @param count
       */
      public void setMaxVisibleValueCount(int count) {
          this.mMaxVisibleCount = count;
      }
  
      /**
       * If set to true, the highlight indicators (cross of two lines for
       * LineChart and ScatterChart, dark bar overlay for BarChart) that give
       * visual indication that an Entry has been selected will be drawn upon
       * selecting values. This does not depend on the MarkerView. Default: true
       * 
       * @param enabled
       */
      public void setHighlightIndicatorEnabled(boolean enabled) {
          mHighLightIndicatorEnabled = enabled;
      }
  
      /**
       * enable this to force the y-axis labels to always start at zero
       * 
       * @param enabled
       */
      public void setStartAtZero(boolean enabled) {
          this.mStartAtZero = enabled;
          prepare();
          prepareMatrix();
      }
  
      /**
       * returns true if the chart is set to start at zero, false otherwise
       * 
       * @return
       */
      public boolean isStartAtZeroEnabled() {
          return mStartAtZero;
      }
  
      /**
       * sets the width of the grid lines (min 0.1f, max = 3f)
       * 
       * @param width
       */
      public void setGridWidth(float width) {
  
          if (width < 0.1f)
              width = 0.1f;
          if (width > 3.0f)
              width = 3.0f;
          mGridWidth = width;
      }
  
      /**
       * Set this to true to enable dragging (moving the chart with the finger)
       * for the chart (this does not effect scaling).
       * 
       * @param enabled
       */
      public void setDragEnabled(boolean enabled) {
          this.mDragEnabled = enabled;
      }
  
      /**
       * Returns true if dragging is enabled for the chart, false if not.
       * 
       * @return
       */
      public boolean isDragEnabled() {
          return mDragEnabled;
      }
  
      /**
       * Set this to true to enable scaling (zooming in and out by gesture) for
       * the chart (this does not effect dragging).
       * 
       * @param enabled
       */
      public void setScaleEnabled(boolean enabled) {
          this.mScaleEnabled = enabled;
      }
  
      /**
       * Returns true if scaling (zooming in and out by gesture) is enabled for
       * the chart, false if not.
       * 
       * @return
       */
      public boolean isScaleEnabled() {
          return mScaleEnabled;
      }
  
      /**
       * Set this to true to enable zooming in by double-tap on the chart.
       * Default: enabled
       * 
       * @param enabled
       */
      public void setDoubleTapToZoomEnabled(boolean enabled) {
          mDoubleTapToZoomEnabled = enabled;
      }
  
      /**
       * Returns true if zooming via double-tap is enabled false if not.
       * 
       * @return
       */
      public boolean isDoubleTapToZoomEnabled() {
          return mDoubleTapToZoomEnabled;
      }
  
      /**
       * if set to true, the vertical grid will be drawn, default: true
       * 
       * @param enabled
       */
      public void setDrawVerticalGrid(boolean enabled) {
          mDrawVerticalGrid = enabled;
      }
  
      /**
       * if set to true, the horizontal grid will be drawn, default: true
       * 
       * @param enabled
       */
      public void setDrawHorizontalGrid(boolean enabled) {
          mDrawHorizontalGrid = enabled;
      }
  
      /**
       * returns true if drawing the vertical grid is enabled, false if not
       * 
       * @return
       */
      public boolean isDrawVerticalGridEnabled() {
          return mDrawVerticalGrid;
      }
  
      /**
       * returns true if drawing the horizontal grid is enabled, false if not
       * 
       * @return
       */
      public boolean isDrawHorizontalGridEnabled() {
          return mDrawHorizontalGrid;
      }
  
      /**
       * set this to true to draw the border surrounding the chart, default: true
       * 
       * @param enabled
       */
      public void setDrawBorder(boolean enabled) {
          mDrawBorder = enabled;
      }
  
      /**
       * set this to true to draw the grid background, false if not
       * 
       * @param enabled
       */
      public void setDrawGridBackground(boolean enabled) {
          mDrawGridBackground = enabled;
      }
  
      /**
       * set this to true to enable drawing the x-labels, false if not
       * 
       * @param enabled
       */
      public void setDrawXLabels(boolean enabled) {
          mDrawXLabels = enabled;
      }
  
      /**
       * set this to true to enable drawing the y-labels, false if not
       * 
       * @param enabled
       */
      public void setDrawYLabels(boolean enabled) {
          mDrawYLabels = enabled;
      }
  
      /**
       * Returns true if drawing y-labels is enabled, false if not.
       * 
       * @return
       */
      public boolean isDrawYLabelsEnabled() {
          return mDrawYLabels;
      }
  
      /**
       * Returns true if drawing x-labels is enabled, false if not.
       * 
       * @return
       */
      public boolean isDrawXLabelsEnabled() {
          return mDrawXLabels;
      }
  
      /**
       * Sets an array of positions where to draw the chart border lines (e.g. new
       * BorderStyle[] { BorderStyle.BOTTOM })
       * 
       * @param styles
       */
      public void setBorderPositions(BorderPosition[] styles) {
          mBorderPositions = styles;
      }
  
      /**
       * Returns the array of positions where the chart-border is drawn.
       * 
       * @return
       */
      public BorderPosition[] getBorderPositions() {
          return mBorderPositions;
      }
  
      /**
       * Sets the width of the border surrounding the chart in dp.
       * 
       * @param width
       */
      public void setBorderWidth(int width) {
          mBorderPaint.setStrokeWidth(Utils.convertDpToPixel(width));
      }
  
      /**
       * Sets the color of the border surrounding the chart.
       * 
       * @param color
       */
      public void setBorderColor(int color) {
          mBorderPaint.setColor(color);
      }
  
      /**
       * Returns the Highlight object (contains x-index and DataSet index) of the
       * selected value at the given touch point inside the Line-, Scatter-, or
       * CandleStick-Chart.
       * 
       * @param x
       * @param y
       * @return
       */
      public Highlight getHighlightByTouchPoint(float x, float y) {
  
          if (mDataNotSet || mData == null) {
              Log.e(LOG_TAG, "Can't select by touch. No data set.");
              return null;
          }
  
          // create an array of the touch-point
          float[] pts = new float[2];
          pts[0] = x;
          pts[1] = y;
  
          mTrans.pixelsToValue(pts);
  
          double xTouchVal = pts[0];
          double yTouchVal = pts[1];
          double base = Math.floor(xTouchVal);
  
          double touchOffset = mDeltaX * 0.025;
          // Log.i(LOG_TAG, "touchindex x: " + xTouchVal + ", touchindex y: " +
          // yTouchVal + ", offset: "
          // + touchOffset);
          // Toast.makeText(getContext(), "touchindex x: " + xTouchVal +
          // ", touchindex y: " + yTouchVal + ", offset: " + touchOffset,
          // Toast.LENGTH_SHORT).show();
  
          // touch out of chart
          if (xTouchVal < -touchOffset || xTouchVal > mDeltaX + touchOffset)
              return null;
  
          if (this instanceof CandleStickChart)
              base -= 0.5;
  
          if (base < 0)
              base = 0;
          if (base >= mDeltaX)
              base = mDeltaX - 1;
  
          int xIndex = (int) base;
  
          int dataSetIndex = 0; // index of the DataSet inside the ChartData
                                // object
  
          // check if we are more than half of a x-value or not
          if (xTouchVal - base > 0.5) {
              xIndex = (int) base + 1;
          }
  
          ArrayList<SelInfo> valsAtIndex = getYValsAtIndex(xIndex);
  
          dataSetIndex = Utils.getClosestDataSetIndex(valsAtIndex, (float) yTouchVal);
  
          if (dataSetIndex == -1)
              return null;
  
          // Toast.makeText(getContext(), "xindex: " + xIndex + ", dataSetIndex: "
          // + dataSetIndex,
          // Toast.LENGTH_SHORT).show();
  
          return new Highlight(xIndex, dataSetIndex);
      }
  
      /**
       * Returns the x and y values in the chart at the given touch point
       * (encapsulated in a PointD). This method transforms pixel coordinates to
       * coordinates / values in the chart. This is the opposite method to
       * getPixelsForValues(...).
       * 
       * @param x
       * @param y
       * @return
       */
      public PointD getValuesByTouchPoint(float x, float y) {
  
          // create an array of the touch-point
          float[] pts = new float[2];
          pts[0] = x;
          pts[1] = y;
  
          mTrans.pixelsToValue(pts);
  
          double xTouchVal = pts[0];
          double yTouchVal = pts[1];
  
          return new PointD(xTouchVal, yTouchVal);
      }
  
      /**
       * Transforms the given chart values into pixels. This is the opposite
       * method to getValuesByTouchPoint(...).
       * 
       * @param x
       * @param y
       * @return
       */
      public PointD getPixelsForValues(float x, float y) {
  
          float[] pts = new float[] {
                  x, y
          };
  
          mTrans.pointValuesToPixel(pts);
  
          return new PointD(pts[0], pts[1]);
      }
  
      /**
       * returns the y-value at the given touch position (must not necessarily be
       * a value contained in one of the datasets)
       * 
       * @param x
       * @param y
       * @return
       */
      public float getYValueByTouchPoint(float x, float y) {
          return (float) getValuesByTouchPoint(x, y).y;
      }
  
      /**
       * returns the Entry object displayed at the touched position of the chart
       * 
       * @param x
       * @param y
       * @return
       */
      public Entry getEntryByTouchPoint(float x, float y) {
          Highlight h = getHighlightByTouchPoint(x, y);
          if (h != null) {
              return mData.getEntryForHighlight(h);
          }
          return null;
      }
  
      /**
       * returns the current x-scale factor
       */
      public float getScaleX() {
          return mTrans.getScaleX();
      }
  
      /**
       * returns the current y-scale factor
       */
      public float getScaleY() {
          return mTrans.getScaleY();
      }
  
      /**
       * if the chart is fully zoomed out, return true
       * 
       * @return
       */
      public boolean isFullyZoomedOut() {
          return mTrans.isFullyZoomedOut();
      }
  
      /**
       * returns the object representing all y-labels, this method can be used to
       * acquire the YLabels object and modify it (e.g. change the position of the
       * labels)
       * 
       * @return
       */
      public YLabels getYLabels() {
          return mYLabels;
      }
  
      /**
       * returns the object representing all x-labels, this method can be used to
       * acquire the XLabels object and modify it (e.g. change the position of the
       * labels)
       * 
       * @return
       */
      public XLabels getXLabels() {
          return mXLabels;
      }
  
      /**
       * Enables data filtering for the chart data, filtering will use the user
       * customized Approximator handed over to this method.
       * 
       * @param a
       */
      public void enableFiltering(Approximator a) {
          mFilterData = true;
          // mApproximator = a;
      }
  
      /**
       * Disables data filtering for the chart.
       */
      public void disableFiltering() {
          mFilterData = false;
      }
  
      /**
       * returns true if data filtering is enabled, false if not
       * 
       * @return
       */
      public boolean isFilteringEnabled() {
          return mFilterData;
      }
  
      /**
       * if set to true, both x and y axis can be scaled with 2 fingers, if false,
       * x and y axis can be scaled separately. default: false
       * 
       * @param enabled
       */
      public void setPinchZoom(boolean enabled) {
          mPinchZoomEnabled = enabled;
      }
  
      /**
       * returns true if pinch-zoom is enabled, false if not
       * 
       * @return
       */
      public boolean isPinchZoomEnabled() {
          return mPinchZoomEnabled;
      }
  
      /**
       * Set an offset in dp that allows the user to drag the chart over it's
       * bounds on the x-axis.
       * 
       * @param offset
       */
      public void setDragOffsetX(float offset) {
          mTrans.setDragOffsetX(offset);
      }
  
      /**
       * Set an offset in dp that allows the user to drag the chart over it's
       * bounds on the y-axis.
       * 
       * @param offset
       */
      public void setDragOffsetY(float offset) {
          mTrans.setDragOffsetY(offset);
      }
  
      /**
       * Returns true if both drag offsets (x and y) are zero or smaller.
       * 
       * @return
       */
      public boolean hasNoDragOffset() {
          return mTrans.hasNoDragOffset();
      }
  
      /**
       * returns the filtered ChartData object depending on approximator settings,
       * current scale level and x- and y-axis ratio
       * 
       * @return
       */
      private T getFilteredData() {
          //
          // float deltaRatio = mDeltaY / mDeltaX;
          // float scaleRatio = mScaleY / mScaleX;
          //
          // // set the determined ratios
          // mApproximator.setRatios(deltaRatio, scaleRatio);
          //
          // // Log.i("Approximator", "DeltaRatio: " + deltaRatio +
          // ", ScaleRatio: "
          // // + scaleRatio);
          //
          // ArrayList<DataSet> dataSets = new ArrayList<DataSet>();
          //
          // for (int j = 0; j < mOriginalData.getDataSetCount(); j++) {
          //
          // DataSet old = mOriginalData.getDataSetByIndex(j);
          //
          // // do the filtering
          // ArrayList<Entry> approximated = mApproximator.filter(old.getYVals());
          //
          // DataSet set = new DataSet(approximated, old.getLabel());
          // dataSets.add(set);
          // }
          //
          // ChartData d = new ChartData(mOriginalData.getXVals(), dataSets);
          // return d;
  
          return null;
      }
  
      @Override
      public void setPaint(Paint p, int which) {
          super.setPaint(p, which);
  
          switch (which) {
              case PAINT_GRID:
                  mGridPaint = p;
                  break;
              case PAINT_GRID_BACKGROUND:
                  mGridBackgroundPaint = p;
                  break;
              case PAINT_BORDER:
                  mBorderPaint = p;
                  break;
          }
      }
  
      @Override
      public Paint getPaint(int which) {
          Paint p = super.getPaint(which);
          if (p != null)
              return p;
  
          switch (which) {
              case PAINT_GRID:
                  return mGridPaint;
              case PAINT_GRID_BACKGROUND:
                  return mGridBackgroundPaint;
              case PAINT_BORDER:
                  return mBorderPaint;
          }
  
          return null;
      }
  }
  