/** Overrides <code>Graphics.drawChars</code>. */
  public void drawChars(char data[], int offset, int length, int x, int y) {
    DebugGraphicsInfo info = info();

    Font font = graphics.getFont();

    if (debugLog()) {
      info().log(toShortString() + " Drawing chars at " + new Point(x, y));
    }

    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.drawChars(data, offset, length, x, y);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.drawChars(data, offset, length, x, y);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.drawChars(data, offset, length, x, y);
  }
  /** Overrides <code>Graphics.drawImage</code>. */
  public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info.log(toShortString() + " Drawing image: " + img + " at: " + new Point(x, y));
    }

    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.drawImage(img, x, y, observer);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      int i, count = (info.flashCount * 2) - 1;
      ImageProducer oldProducer = img.getSource();
      ImageProducer newProducer =
          new FilteredImageSource(oldProducer, new DebugGraphicsFilter(info.flashColor));
      Image newImage = Toolkit.getDefaultToolkit().createImage(newProducer);
      DebugGraphicsObserver imageObserver = new DebugGraphicsObserver();

      Image imageToDraw;
      for (i = 0; i < count; i++) {
        imageToDraw = (i % 2) == 0 ? newImage : img;
        loadImage(imageToDraw);
        graphics.drawImage(imageToDraw, x, y, imageObserver);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
    }
    return graphics.drawImage(img, x, y, observer);
  }
  /** Overrides <code>Graphics.fillArc</code>. */
  public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info()
          .log(
              toShortString()
                  + " Filling arc: "
                  + new Rectangle(x, y, width, height)
                  + " startAngle: "
                  + startAngle
                  + " arcAngle: "
                  + arcAngle);
    }
    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.fillArc(x, y, width, height, startAngle, arcAngle);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.fillArc(x, y, width, height, startAngle, arcAngle);
  }
  /** Overrides <code>Graphics.drawString</code>. */
  public void drawString(AttributedCharacterIterator iterator, int x, int y) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info().log(toShortString() + " Drawing text: \"" + iterator + "\" at: " + new Point(x, y));
    }

    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.drawString(iterator, x, y);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.drawString(iterator, x, y);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.drawString(iterator, x, y);
  }
  /** Overrides <code>Graphics.drawOval</code>. */
  public void drawOval(int x, int y, int width, int height) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info().log(toShortString() + " Drawing oval: " + new Rectangle(x, y, width, height));
    }
    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.drawOval(x, y, width, height);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.drawOval(x, y, width, height);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.drawOval(x, y, width, height);
  }
  /** Overrides <code>Graphics.fill3DRect</code>. */
  public void fill3DRect(int x, int y, int width, int height, boolean raised) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info()
          .log(
              toShortString()
                  + " Filling 3D rect: "
                  + new Rectangle(x, y, width, height)
                  + " Raised bezel: "
                  + raised);
    }
    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.fill3DRect(x, y, width, height, raised);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.fill3DRect(x, y, width, height, raised);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.fill3DRect(x, y, width, height, raised);
  }
  /** Overrides <code>Graphics.drawLine</code>. */
  public void drawLine(int x1, int y1, int x2, int y2) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info()
          .log(
              toShortString()
                  + " Drawing line: from "
                  + pointToString(x1, y1)
                  + " to "
                  + pointToString(x2, y2));
    }

    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.drawLine(x1, y1, x2, y2);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.drawLine(x1, y1, x2, y2);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.drawLine(x1, y1, x2, y2);
  }
  /** Overrides <code>Graphics.drawImage</code>. */
  public boolean drawImage(
      Image img,
      int dx1,
      int dy1,
      int dx2,
      int dy2,
      int sx1,
      int sy1,
      int sx2,
      int sy2,
      Color bgcolor,
      ImageObserver observer) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info.log(
          toShortString()
              + " Drawing image: "
              + img
              + " destination: "
              + new Rectangle(dx1, dy1, dx2, dy2)
              + " source: "
              + new Rectangle(sx1, sy1, sx2, sy2)
              + ", bgcolor: "
              + bgcolor);
    }

    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      int i, count = (info.flashCount * 2) - 1;
      ImageProducer oldProducer = img.getSource();
      ImageProducer newProducer =
          new FilteredImageSource(oldProducer, new DebugGraphicsFilter(info.flashColor));
      Image newImage = Toolkit.getDefaultToolkit().createImage(newProducer);
      DebugGraphicsObserver imageObserver = new DebugGraphicsObserver();

      Image imageToDraw;
      for (i = 0; i < count; i++) {
        imageToDraw = (i % 2) == 0 ? newImage : img;
        loadImage(imageToDraw);
        graphics.drawImage(
            imageToDraw, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, imageObserver);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
    }
    return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
  }
  /** Overrides <code>Graphics.fillPolygon</code>. */
  public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
    DebugGraphicsInfo info = info();

    if (debugLog()) {
      info()
          .log(
              toShortString()
                  + " Filling polygon: "
                  + " nPoints: "
                  + nPoints
                  + " X's: "
                  + xPoints
                  + " Y's: "
                  + yPoints);
    }
    if (isDrawingBuffer()) {
      if (debugBuffered()) {
        Graphics debugGraphics = debugGraphics();

        debugGraphics.fillPolygon(xPoints, yPoints, nPoints);
        debugGraphics.dispose();
      }
    } else if (debugFlash()) {
      Color oldColor = getColor();
      int i, count = (info.flashCount * 2) - 1;

      for (i = 0; i < count; i++) {
        graphics.setColor((i % 2) == 0 ? info.flashColor : oldColor);
        graphics.fillPolygon(xPoints, yPoints, nPoints);
        Toolkit.getDefaultToolkit().sync();
        sleep(info.flashTime);
      }
      graphics.setColor(oldColor);
    }
    graphics.fillPolygon(xPoints, yPoints, nPoints);
  }