package com.srbenoit.font;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.io.File;
import java.io.FileInputStream;
import java.util.logging.Level;
import javax.swing.BorderFactory;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import com.srbenoit.log.LoggedObject;

/**
 * A simple application allowing the user to select a TrueType (.TTF) or Type-1 (.PFA/.PFB) font
 * file then displaying a sample of that font's symbols.
 */
public class FontBrowser extends LoggedObject implements ActionListener {

    /** the frame */
    private final transient JFrame frame;

    /** the content panel of the frame */
    private final transient JPanel content;

    /** the currently loaded (one-point) font */
    private transient Font font = null;

    /** the most recently opened font file's parent directory */
    private transient File dir = null;

    /**
     * Creates a new <code>FontBrowser</code>.
     */
    public FontBrowser() {

        JMenuBar bar;
        JMenu menu;
        JMenuItem item;
        FontPanel pnl;

        this.frame = new JFrame("Font Browser");

        bar = new JMenuBar();
        menu = new JMenu("File");
        item = new JMenuItem("Open");

        this.content = new JPanel(new BorderLayout());
        this.frame.setContentPane(this.content);

        item.addActionListener(this);
        item.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK));
        menu.add(item);
        bar.add(menu);
        this.frame.setJMenuBar(bar);

        this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pnl = new FontPanel(this.font);
        this.content.add(pnl, BorderLayout.CENTER);
        this.frame.pack();
        this.frame.setVisible(true);
    }

    /**
     * Gets the frame.
     *
     * @return  the frame
     */
    public JFrame getFrame() {

        return this.frame;
    }

    /**
     * Handles action events.
     *
     * @param  evt  the action event to be processed
     */
    public void actionPerformed(final ActionEvent evt) {

        String cmd;
        JFileChooser jfc;
        File file;
        FileInputStream fis;
        FontPanel pnl;
        String name;

        cmd = evt.getActionCommand();

        if ("Open".equals(cmd)) {
            jfc = new JFileChooser();

            if (this.dir != null) {
                jfc.setCurrentDirectory(this.dir);
            }

            if (jfc.showOpenDialog(this.frame) == JFileChooser.APPROVE_OPTION) {
                file = jfc.getSelectedFile();
                this.dir = file.getParentFile();
                name = file.getName().toLowerCase();

                try {
                    fis = new FileInputStream(file);

                    if ((name.endsWith(".ttf")) || (name.endsWith(".otf"))) {
                        this.font = Font.createFont(Font.TRUETYPE_FONT, fis);
                    } else {
                        this.font = Font.createFont(Font.TYPE1_FONT, fis);
                    }

                    fis.close();

                    this.content.removeAll();
                    pnl = new FontPanel(this.font);
                    this.content.add(pnl, BorderLayout.CENTER);
                    this.frame.pack();

                    this.frame.setTitle(file.getAbsolutePath());
                } catch (Exception exc) {
                    LOG.log(Level.WARNING, "Failed to open font {0}: {1}",
                        new Object[] { name, exc.getLocalizedMessage() });
                }
            }
        }
    }

    /**
     * Main method to execute the application.
     *
     * @param  args  command-line arguments
     */
    public static void main(final String... args) {

        new FontBrowser().getFrame();
    }

    /**
     * A panel that displays the selected font in varying sizes.
     */
    private static class FontPanel extends JPanel {

        /** version number for serialization */
        private static final long serialVersionUID = -4052269402511508396L;

        /**
         * Construct a new <code>FontPanel</code>.
         *
         * @param  fnt  the font to display in the panel
         */
        protected FontPanel(final Font fnt) {

            super(new BorderLayout(5, 5));

            JPanel grid;
            Font derived;
            JLabel lbl;
            JTextArea area;

            setPreferredSize(new Dimension(800, 800));

            if (fnt != null) {

                // Build the UI.
                grid = new JPanel(new GridLayout(16, 1, 0, 0));
                add(grid, BorderLayout.NORTH);

                derived = fnt.deriveFont(Font.PLAIN, 24);
                lbl = new JLabel(fnt.getFontName() + " in 24-point plain");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD, 24);
                lbl = new JLabel(fnt.getFontName() + " in 24-point bold");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.ITALIC, 24);
                lbl = new JLabel(fnt.getFontName() + " in 24-point italic");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 24);
                lbl = new JLabel(fnt.getFontName() + " in 24-point bold italic");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.PLAIN, 12);
                lbl = new JLabel(fnt.getFontName() + " in 12-point plain");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD, 12);
                lbl = new JLabel(fnt.getFontName() + " in 12-point bold");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.ITALIC, 12);
                lbl = new JLabel(fnt.getFontName() + " in 12-point italic");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 12);
                lbl = new JLabel(fnt.getFontName() + " in 12-point bold italic");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 12);
                lbl = new JLabel("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 12);
                lbl = new JLabel("1234567890`~!@#$%^&*()-_=+[{]}\\|;" + ":'\",<.>/?");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.PLAIN, 9);
                lbl = new JLabel(fnt.getFontName() + " in 9-point plain");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD, 9);
                lbl = new JLabel(fnt.getFontName() + " in 9-point bold");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.ITALIC, 9);
                lbl = new JLabel(fnt.getFontName() + " in 9-point italic");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 9);
                lbl = new JLabel(fnt.getFontName() + " in 9-point bold italic");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 9);
                lbl = new JLabel("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.BOLD | Font.ITALIC, 9);
                lbl = new JLabel("1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?");
                lbl.setFont(derived);
                grid.add(lbl);

                derived = fnt.deriveFont(Font.PLAIN, 18);
                area = new JTextArea("Type text here to try out the font.");
                area.setBorder(BorderFactory.createLoweredBevelBorder());
                area.setFont(derived);
                add(area, BorderLayout.CENTER);
            }
        }
    }
}
