/**
   * Draws the visual representation of a single data item, second pass. In the second pass, the
   * renderer draws the lines and shapes for the individual points in the two series.
   *
   * @param x_graphics the graphics device.
   * @param x_dataArea the area within which the data is being drawn.
   * @param x_info collects information about the drawing.
   * @param x_plot the plot (can be used to obtain standard color information etc).
   * @param x_domainAxis the domain (horizontal) axis.
   * @param x_rangeAxis the range (vertical) axis.
   * @param x_dataset the dataset.
   * @param x_series the series index (zero-based).
   * @param x_item the item index (zero-based).
   * @param x_crosshairState crosshair information for the plot (<code>null</code> permitted).
   */
  protected void drawItemPass1(
      Graphics2D x_graphics,
      Rectangle2D x_dataArea,
      PlotRenderingInfo x_info,
      XYPlot x_plot,
      ValueAxis x_domainAxis,
      ValueAxis x_rangeAxis,
      XYDataset x_dataset,
      int x_series,
      int x_item,
      CrosshairState x_crosshairState) {

    Shape l_entityArea = null;
    EntityCollection l_entities = null;
    if (null != x_info) {
      l_entities = x_info.getOwner().getEntityCollection();
    }

    Paint l_seriesPaint = getItemPaint(x_series, x_item);
    Stroke l_seriesStroke = getItemStroke(x_series, x_item);
    x_graphics.setPaint(l_seriesPaint);
    x_graphics.setStroke(l_seriesStroke);

    PlotOrientation l_orientation = x_plot.getOrientation();
    RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge();
    RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge();

    double l_x0 = x_dataset.getXValue(x_series, x_item);
    double l_y0 = x_dataset.getYValue(x_series, x_item);
    double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea, l_domainAxisLocation);
    double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea, l_rangeAxisLocation);

    if (getShapesVisible()) {
      Shape l_shape = getItemShape(x_series, x_item);
      if (l_orientation == PlotOrientation.HORIZONTAL) {
        l_shape = ShapeUtilities.createTranslatedShape(l_shape, l_y1, l_x1);
      } else {
        l_shape = ShapeUtilities.createTranslatedShape(l_shape, l_x1, l_y1);
      }
      if (l_shape.intersects(x_dataArea)) {
        x_graphics.setPaint(getItemPaint(x_series, x_item));
        x_graphics.fill(l_shape);
      }
      l_entityArea = l_shape;
    }

    // add an entity for the item...
    if (null != l_entities) {
      if (null == l_entityArea) {
        l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2), 4, 4);
      }
      String l_tip = null;
      XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series, x_item);
      if (null != l_tipGenerator) {
        l_tip = l_tipGenerator.generateToolTip(x_dataset, x_series, x_item);
      }
      String l_url = null;
      XYURLGenerator l_urlGenerator = getURLGenerator();
      if (null != l_urlGenerator) {
        l_url = l_urlGenerator.generateURL(x_dataset, x_series, x_item);
      }
      XYItemEntity l_entity =
          new XYItemEntity(l_entityArea, x_dataset, x_series, x_item, l_tip, l_url);
      l_entities.add(l_entity);
    }

    // draw the item label if there is one...
    if (isItemLabelVisible(x_series, x_item)) {
      drawItemLabel(
          x_graphics, l_orientation, x_dataset, x_series, x_item, l_x1, l_y1, (l_y1 < 0.0));
    }

    int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis);
    int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis);
    updateCrosshairValues(
        x_crosshairState,
        l_x0,
        l_y0,
        l_domainAxisIndex,
        l_rangeAxisIndex,
        l_x1,
        l_y1,
        l_orientation);

    if (0 == x_item) {
      return;
    }

    double l_x2 =
        x_domainAxis.valueToJava2D(
            x_dataset.getXValue(x_series, (x_item - 1)), x_dataArea, l_domainAxisLocation);
    double l_y2 =
        x_rangeAxis.valueToJava2D(
            x_dataset.getYValue(x_series, (x_item - 1)), x_dataArea, l_rangeAxisLocation);

    Line2D l_line = null;
    if (PlotOrientation.HORIZONTAL == l_orientation) {
      l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2);
    } else if (PlotOrientation.VERTICAL == l_orientation) {
      l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2);
    }

    if ((null != l_line) && l_line.intersects(x_dataArea)) {
      x_graphics.setPaint(getItemPaint(x_series, x_item));
      x_graphics.setStroke(getItemStroke(x_series, x_item));
      x_graphics.draw(l_line);
    }
  }
  /**
   * Draws the visual representation of a single data item.
   *
   * @param g2 the graphics device.
   * @param state the renderer state.
   * @param dataArea the area within which the data is being drawn.
   * @param info collects information about the drawing.
   * @param plot the plot (can be used to obtain standard color information etc).
   * @param domainAxis the domain axis.
   * @param rangeAxis the range axis.
   * @param dataset the dataset.
   * @param series the series index (zero-based).
   * @param item the item index (zero-based).
   * @param crosshairState crosshair information for the plot (<code>null</code> permitted).
   * @param pass the pass index.
   */
  public void drawItem(
      Graphics2D g2,
      XYItemRendererState state,
      Rectangle2D dataArea,
      PlotRenderingInfo info,
      XYPlot plot,
      ValueAxis domainAxis,
      ValueAxis rangeAxis,
      XYDataset dataset,
      int series,
      int item,
      CrosshairState crosshairState,
      int pass) {

    if (!getItemVisible(series, item)) {
      return;
    }
    XYAreaRendererState areaState = (XYAreaRendererState) state;

    // get the data point...
    double x1 = dataset.getXValue(series, item);
    double y1 = dataset.getYValue(series, item);
    if (Double.isNaN(y1)) {
      y1 = 0.0;
    }
    double transX1 = domainAxis.valueToJava2D(x1, dataArea, plot.getDomainAxisEdge());
    double transY1 = rangeAxis.valueToJava2D(y1, dataArea, plot.getRangeAxisEdge());

    // get the previous point and the next point so we can calculate a
    // "hot spot" for the area (used by the chart entity)...
    int itemCount = dataset.getItemCount(series);
    double x0 = dataset.getXValue(series, Math.max(item - 1, 0));
    double y0 = dataset.getYValue(series, Math.max(item - 1, 0));
    if (Double.isNaN(y0)) {
      y0 = 0.0;
    }
    double transX0 = domainAxis.valueToJava2D(x0, dataArea, plot.getDomainAxisEdge());
    double transY0 = rangeAxis.valueToJava2D(y0, dataArea, plot.getRangeAxisEdge());

    double x2 = dataset.getXValue(series, Math.min(item + 1, itemCount - 1));
    double y2 = dataset.getYValue(series, Math.min(item + 1, itemCount - 1));
    if (Double.isNaN(y2)) {
      y2 = 0.0;
    }
    double transX2 = domainAxis.valueToJava2D(x2, dataArea, plot.getDomainAxisEdge());
    double transY2 = rangeAxis.valueToJava2D(y2, dataArea, plot.getRangeAxisEdge());

    double transZero = rangeAxis.valueToJava2D(0.0, dataArea, plot.getRangeAxisEdge());
    Polygon hotspot = null;
    if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
      hotspot = new Polygon();
      hotspot.addPoint((int) transZero, (int) ((transX0 + transX1) / 2.0));
      hotspot.addPoint((int) ((transY0 + transY1) / 2.0), (int) ((transX0 + transX1) / 2.0));
      hotspot.addPoint((int) transY1, (int) transX1);
      hotspot.addPoint((int) ((transY1 + transY2) / 2.0), (int) ((transX1 + transX2) / 2.0));
      hotspot.addPoint((int) transZero, (int) ((transX1 + transX2) / 2.0));
    } else { // vertical orientation
      hotspot = new Polygon();
      hotspot.addPoint((int) ((transX0 + transX1) / 2.0), (int) transZero);
      hotspot.addPoint((int) ((transX0 + transX1) / 2.0), (int) ((transY0 + transY1) / 2.0));
      hotspot.addPoint((int) transX1, (int) transY1);
      hotspot.addPoint((int) ((transX1 + transX2) / 2.0), (int) ((transY1 + transY2) / 2.0));
      hotspot.addPoint((int) ((transX1 + transX2) / 2.0), (int) transZero);
    }

    if (item == 0) { // create a new area polygon for the series
      areaState.area = new Polygon();
      // the first point is (x, 0)
      double zero = rangeAxis.valueToJava2D(0.0, dataArea, plot.getRangeAxisEdge());
      if (plot.getOrientation() == PlotOrientation.VERTICAL) {
        areaState.area.addPoint((int) transX1, (int) zero);
      } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
        areaState.area.addPoint((int) zero, (int) transX1);
      }
    }

    // Add each point to Area (x, y)
    if (plot.getOrientation() == PlotOrientation.VERTICAL) {
      areaState.area.addPoint((int) transX1, (int) transY1);
    } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
      areaState.area.addPoint((int) transY1, (int) transX1);
    }

    PlotOrientation orientation = plot.getOrientation();
    Paint paint = getItemPaint(series, item);
    Stroke stroke = getItemStroke(series, item);
    g2.setPaint(paint);
    g2.setStroke(stroke);

    Shape shape = null;
    if (getPlotShapes()) {
      shape = getItemShape(series, item);
      if (orientation == PlotOrientation.VERTICAL) {
        shape = ShapeUtilities.createTranslatedShape(shape, transX1, transY1);
      } else if (orientation == PlotOrientation.HORIZONTAL) {
        shape = ShapeUtilities.createTranslatedShape(shape, transY1, transX1);
      }
      g2.draw(shape);
    }

    if (getPlotLines()) {
      if (item > 0) {
        if (plot.getOrientation() == PlotOrientation.VERTICAL) {
          areaState.line.setLine(transX0, transY0, transX1, transY1);
        } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
          areaState.line.setLine(transY0, transX0, transY1, transX1);
        }
        g2.draw(areaState.line);
      }
    }

    // Check if the item is the last item for the series.
    // and number of items > 0.  We can't draw an area for a single point.
    if (getPlotArea() && item > 0 && item == (itemCount - 1)) {

      if (orientation == PlotOrientation.VERTICAL) {
        // Add the last point (x,0)
        areaState.area.addPoint((int) transX1, (int) transZero);
      } else if (orientation == PlotOrientation.HORIZONTAL) {
        // Add the last point (x,0)
        areaState.area.addPoint((int) transZero, (int) transX1);
      }

      g2.fill(areaState.area);

      // draw an outline around the Area.
      if (isOutline()) {
        g2.setStroke(getItemOutlineStroke(series, item));
        g2.setPaint(getItemOutlinePaint(series, item));
        g2.draw(areaState.area);
      }
    }

    updateCrosshairValues(crosshairState, x1, y1, transX1, transY1, orientation);

    // collect entity and tool tip information...
    if (state.getInfo() != null) {
      EntityCollection entities = state.getEntityCollection();
      if (entities != null && hotspot != null) {
        String tip = null;
        XYToolTipGenerator generator = getToolTipGenerator(series, item);
        if (generator != null) {
          tip = generator.generateToolTip(dataset, series, item);
        }
        String url = null;
        if (getURLGenerator() != null) {
          url = getURLGenerator().generateURL(dataset, series, item);
        }
        XYItemEntity entity = new XYItemEntity(hotspot, dataset, series, item, tip, url);
        entities.add(entity);
      }
    }
  }