import java.awt.*;
import java.awt.print.*;

public class PrinterProblemMain {

    static boolean withCompositeGraphics = false;

    public static void main(String[] args) {
        try {
            VirtualPageable virtualPageable = new VirtualPageable();
            PrinterJob job = PrinterJob.getPrinterJob();
            job.setPageable(virtualPageable);
            if (job.printDialog()) {
                job.print();
                withCompositeGraphics = true;
                job.print();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class VirtualPageable implements Pageable {
        private final Printable printable = new VirtualPrintable();

        @Override
        public int getNumberOfPages() {
            return 1;
        }

        @Override
        public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException {
            PageFormat returnValue = new PageFormat();
            returnValue.setOrientation(PageFormat.REVERSE_LANDSCAPE);
            return returnValue;
        }

        @Override
        public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException {
            return pageIndex == 0 ? printable : null;
        }
    }

    static class VirtualPrintable implements Printable {


        @Override
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
            // Only a single page should be printed
            if (pageIndex > 0 || graphics == null) {
                return NO_SUCH_PAGE;
            }

            Graphics2D g2 = (Graphics2D) graphics;

            double ix = pageFormat.getImageableX();
            double iy = pageFormat.getImageableY();
            double iw = pageFormat.getImageableWidth();
            double ih = pageFormat.getImageableHeight();
            double offset = 1.0;
            double d = 20.0;

            // Draw circles and numbers 1..4 centered in each circle
            Point[] centersOfCornerCircles = new Point[]{
                    new Point((int) Math.round(ix + offset + d / 2.0), (int) Math.round(iy + offset + d / 2.0)), // top-left
                    new Point((int) Math.round(ix + iw - offset - d / 2.0), (int) Math.round(iy + offset + d / 2.0)), // top-right
                    new Point((int) Math.round(ix + offset + d / 2.0), (int) Math.round(iy + ih - offset - d / 2.0)), // bottom-left
                    new Point((int) Math.round(ix + iw - offset - d / 2.0), (int) Math.round(iy + ih - offset - d / 2.0)) // bottom-right
            };
            Font originalFont = g2.getFont();
            Font font = originalFont.deriveFont(12f);
            g2.setFont(font);
            g2.setStroke(new BasicStroke(1.0f));
            g2.setColor(Color.BLACK);

            for (int i = 0; i < centersOfCornerCircles.length; i++) {
                Point c = centersOfCornerCircles[i];
                int x = (int) Math.round(c.x - d / 2.0);
                int y = (int) Math.round(c.y - d / 2.0);

                // Circle
                g2.drawOval(x, y, (int) Math.round(d), (int) Math.round(d));

                // Number centered
                String text = String.valueOf(i + 1);
                FontMetrics fm = g2.getFontMetrics();
                int textWidth = fm.stringWidth(text);
                int textAscent = fm.getAscent();
                int textDescent = fm.getDescent();
                int tx = (int) Math.round(c.x - textWidth / 2.0);
                int ty = (int) Math.round(c.y + (textAscent - textDescent) / 2.0);
                g2.drawString(text, tx, ty);
            }

            // The bug happens, when a composite graphics element is rendered
            if (withCompositeGraphics) {
                Graphics2D gAlpha = (Graphics2D) g2.create();
                try {
                    gAlpha.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                    gAlpha.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f));

                    String centerText = "Composite Graphics - "+System.getProperty("java.version");
                    int baseSize = 48;
                    Font centerFont = originalFont.deriveFont(Font.BOLD, baseSize);
                    gAlpha.setFont(centerFont);
                    FontMetrics cfm = gAlpha.getFontMetrics();
                    int textWidth = cfm.stringWidth(centerText);
                    double maxWidth = iw * 0.8;
                    if (textWidth > maxWidth && textWidth > 0) {
                        float scaledSize = (float) (baseSize * (maxWidth / textWidth));
                        scaledSize = Math.max(18f, scaledSize);
                        centerFont = originalFont.deriveFont(Font.BOLD, scaledSize);
                        gAlpha.setFont(centerFont);
                        cfm = gAlpha.getFontMetrics();
                        textWidth = cfm.stringWidth(centerText);
                    }

                    int textAscent = cfm.getAscent();
                    int textDescent = cfm.getDescent();

                    int cx = (int) Math.round(ix + iw / 2.0);
                    int cy = (int) Math.round(iy + ih / 2.0);
                    int tx = (int) Math.round(cx - textWidth / 2.0);
                    int ty = (int) Math.round(cy + (textAscent - textDescent) / 2.0);

                    gAlpha.setColor(Color.BLACK);
                    gAlpha.drawString(centerText, tx, ty);
                } finally {
                    gAlpha.dispose();
                }
            }
            return PAGE_EXISTS;
        }
    }
} 