/**
     * Draws the plot on a Java 2D graphics device (such as the screen or a
     * printer).  Will perform all the placement calculations for each
     * sub-plots and then tell these to draw themselves.
     *
     * @param g2  the graphics device.
     * @param area  the area within which the plot (including axis labels)
     *              should be drawn.
     * @param anchor  the anchor point (<code>null</code> permitted).
     * @param parentState  the parent state.
     * @param info  collects information about the drawing (<code>null</code>
     *              permitted).
     */
    public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
                     PlotState parentState,
                     PlotRenderingInfo info) {

        // set up info collection...
        if (info != null) {
            info.setPlotArea(area);
        }

        // adjust the drawing area for plot insets (if any)...
        RectangleInsets insets = getInsets();
        insets.trim(area);

        // calculate the data area...
        AxisSpace space = calculateAxisSpace(g2, area);
        Rectangle2D dataArea = space.shrink(area, null);

        // set the width and height of non-shared axis of all sub-plots
        setFixedDomainAxisSpaceForSubplots(space);

        // draw the shared axis
        ValueAxis axis = getRangeAxis();
        RectangleEdge rangeEdge = getRangeAxisEdge();
        double cursor = RectangleEdge.coordinate(dataArea, rangeEdge);
        AxisState state = axis.draw(g2, cursor, area, dataArea, rangeEdge,
                info);
        if (parentState == null) {
            parentState = new PlotState();
        }
        parentState.getSharedAxisStates().put(axis, state);

        // draw all the charts
        for (int i = 0; i < this.subplots.size(); i++) {
            CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
            PlotRenderingInfo subplotInfo = null;
            if (info != null) {
                subplotInfo = new PlotRenderingInfo(info.getOwner());
                info.addSubplotInfo(subplotInfo);
            }
            Point2D subAnchor = null;
            if (anchor != null && this.subplotArea[i].contains(anchor)) {
                subAnchor = anchor;
            }
            plot.draw(g2, this.subplotArea[i], subAnchor, parentState,
                    subplotInfo);
        }

        if (info != null) {
            info.setDataArea(dataArea);
        }

    }
  /**
   * Returns the content size for the title. This will reflect the fact that a text title positioned
   * on the left or right of a chart will be rotated 90 degrees.
   *
   * @param g2 the graphics device.
   * @param widthRange the width range.
   * @param heightRange the height range.
   * @return The content size.
   */
  protected Size2D arrangeRR(Graphics2D g2, Range widthRange, Range heightRange) {

    RectangleEdge position = getPosition();
    if (position == RectangleEdge.TOP || position == RectangleEdge.BOTTOM) {

      float maxWidth = (float) widthRange.getUpperBound();

      // determine the space required for the axis
      AxisSpace space =
          this.axis.reserveSpace(
              g2, null, new Rectangle2D.Double(0, 0, maxWidth, 100), RectangleEdge.BOTTOM, null);

      return new Size2D(
          maxWidth, this.stripWidth + this.axisOffset + space.getTop() + space.getBottom());
    } else if (position == RectangleEdge.LEFT || position == RectangleEdge.RIGHT) {
      float maxHeight = (float) heightRange.getUpperBound();
      AxisSpace space =
          this.axis.reserveSpace(
              g2, null, new Rectangle2D.Double(0, 0, 100, maxHeight), RectangleEdge.RIGHT, null);
      return new Size2D(
          this.stripWidth + this.axisOffset + space.getLeft() + space.getRight(), maxHeight);
    } else {
      throw new RuntimeException("Unrecognised position.");
    }
  }
  /**
   * Calculates the space required for the axes.
   *
   * @param g2 the graphics device.
   * @param plotArea the plot area.
   * @return The space required for the axes.
   */
  @Override
  protected AxisSpace calculateAxisSpace(Graphics2D g2, Rectangle2D plotArea) {

    AxisSpace space = new AxisSpace();
    PlotOrientation orientation = getOrientation();

    // work out the space required by the domain axis...
    AxisSpace fixed = getFixedRangeAxisSpace();
    if (fixed != null) {
      if (orientation == PlotOrientation.VERTICAL) {
        space.setLeft(fixed.getLeft());
        space.setRight(fixed.getRight());
      } else if (orientation == PlotOrientation.HORIZONTAL) {
        space.setTop(fixed.getTop());
        space.setBottom(fixed.getBottom());
      }
    } else {
      ValueAxis valueAxis = getRangeAxis();
      RectangleEdge valueEdge = Plot.resolveRangeAxisLocation(getRangeAxisLocation(), orientation);
      if (valueAxis != null) {
        space = valueAxis.reserveSpace(g2, this, plotArea, valueEdge, space);
      }
    }

    Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
    // work out the maximum height or width of the non-shared axes...
    int n = this.subplots.size();
    int totalWeight = 0;
    for (int i = 0; i < n; i++) {
      XYPlot sub = (XYPlot) this.subplots.get(i);
      totalWeight += sub.getWeight();
    }

    // calculate plotAreas of all sub-plots, maximum vertical/horizontal
    // axis width/height
    this.subplotAreas = new Rectangle2D[n];
    double x = adjustedPlotArea.getX();
    double y = adjustedPlotArea.getY();
    double usableSize = 0.0;
    if (orientation == PlotOrientation.VERTICAL) {
      usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
    } else if (orientation == PlotOrientation.HORIZONTAL) {
      usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
    }

    for (int i = 0; i < n; i++) {
      XYPlot plot = (XYPlot) this.subplots.get(i);

      // calculate sub-plot area
      if (orientation == PlotOrientation.VERTICAL) {
        double w = usableSize * plot.getWeight() / totalWeight;
        this.subplotAreas[i] = new Rectangle2D.Double(x, y, w, adjustedPlotArea.getHeight());
        x = x + w + this.gap;
      } else if (orientation == PlotOrientation.HORIZONTAL) {
        double h = usableSize * plot.getWeight() / totalWeight;
        this.subplotAreas[i] = new Rectangle2D.Double(x, y, adjustedPlotArea.getWidth(), h);
        y = y + h + this.gap;
      }

      AxisSpace subSpace = plot.calculateDomainAxisSpace(g2, this.subplotAreas[i], null);
      space.ensureAtLeast(subSpace);
    }

    return space;
  }