package org.gnu.grub.fonttool;

import java.awt.*;
import java.util.Formatter;
import javax.swing.*;

public class CharView extends JComponent {
    private Font charFont = null;
    private Glyph glyph = null;
    private int zoom = 1;

    public Font getCharFont() {
        return charFont;
    }

    public void setCharFont(Font charFont) {
        this.charFont = charFont;
    }

    public Glyph getGlyph() {
        return glyph;
    }

    public void setGlyph(Glyph glyph) {
        this.glyph = glyph;
        repaint();
    }

    public void setZoom(int zoom) {
        this.zoom = zoom;
    }

    public Dimension getPreferredSize() {
        if (glyph == null)
            return new Dimension(1, 1);
        return new Dimension(glyph.getWidth() * zoom, glyph.getHeight() * zoom);
    }

    protected void paintComponent(Graphics g) {
        if (glyph == null) {
            // Draw a gray 'X' indicating no character selected.
            g.setColor(Color.gray);
            g.drawLine(0, 0, getWidth() - 1, getHeight() - 1);
            g.drawLine(getWidth(), 0, 0, getHeight() - 1);
            return;
        }

        final int x0 = (getWidth() - glyph.getWidth() * zoom) / 2;
        final int y0 = getHeight() / 2;
        drawGlyph(g, charFont, glyph, x0, y0, zoom, getForeground());

        g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));
        FontMetrics fm = g.getFontMetrics();
        Formatter f = new Formatter();
        f.format("U+%04X", glyph.getCodePoint());
        String str = f.toString();
        g.drawString(str,
                     (getWidth() - fm.stringWidth(str)) / 2,
                     getHeight() - fm.getHeight());
    }

    /**
     * Draw the specified glyph with its baseline at y0 and the horizontal
     * start at x0.
     */
    static Rectangle drawGlyph(Graphics g, Font font, Glyph glyph, int startX, int baselineY, int zoom, Color fg) {
        // Adjust (x0, y0) so that it puts the bitmap at the right location.
        final int offsetX = zoom * glyph.getBbox();
        final int offsetY = zoom * glyph.getBboy();
        final int bitmapLeft = startX + offsetX;
        final int bitmapBottom = baselineY - offsetY;
        final int bitmapTop = bitmapBottom - zoom * glyph.getHeight();

        // Draw a gray box around the glyph bounds.
        g.setColor(Color.lightGray);
        g.drawRect(bitmapLeft - 1, bitmapTop - 1,
                   glyph.getWidth() * zoom + 1, zoom * glyph.getHeight() + 1);

        // Draw the baseline
        g.setColor(new Color(110, 110, 255));
        g.drawLine(startX, baselineY, startX + zoom * glyph.getDeviceWidth(), baselineY);

        // Draw the glyph.
        g.setColor(fg);
        byte[] bitmap = glyph.getBitmap();
        int bitIndex = 0;
        for (int y = 0; y < glyph.getHeight(); y++) {
            for (int x = 0; x < glyph.getWidth(); x++, bitIndex++) {
                int byteIndex = bitIndex / 8;
                int bitShift = bitIndex % 8;
                byte b = bitmap[byteIndex];
                boolean bitValue = (b & (0x80 >>> bitShift)) != 0;
                if (bitValue) {
                    g.fillRect(bitmapLeft + x * zoom, bitmapTop + y * zoom, zoom, zoom);
                }
            }
        }

        return new Rectangle(bitmapLeft, bitmapTop, zoom * glyph.getWidth(), zoom * glyph.getHeight());
    }
}
