/*
 * @(#)PDFUtilities.java  1.0  2008-09-29
 * 
 * Copyright (c) 2008 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */

package ch.randelshofer.pdf.plaf;

import java.awt.*;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicGraphicsUtils;
/**
 * PDFUtilities.
 *
 * @author Werner Randelshofer, Hausmatt 10, CH-6405 Immensee
 * @version 1.0 2008-09-29 Created.
 */
public class PDFUtilities extends BasicGraphicsUtils  {
    /*
     * Convenience function for determining ComponentOrientation.  Helps us
     * avoid having Munge directives throughout the code.
     */
    public static boolean isLeftToRight(Component c) {
        return c.getComponentOrientation().isLeftToRight();
    }

    /**
     * Returns true, if the specified component is focus owner or permanent
     * focus owner and if the component is on an the active window.
     */
    public static final boolean isFocused(Component component) {
        // When a component is used as a cell renderer, the focus can
        // not be determined from the component itself.
        if (component instanceof JComponent) {
            if (((JComponent) component).getClientProperty("Quaqua.Component.cellRendererFor") != null) {
                component = (Component) ((JComponent) component).getClientProperty("Quaqua.Component.cellRendererFor");
            }
        }

            boolean isFocusOwner = component.isFocusOwner();

            Window ancestor = SwingUtilities.getWindowAncestor(component);
            KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();

            return isFocusOwner ||
                    component == kfm.getPermanentFocusOwner() &&
                    ancestor != null &&
                    ancestor.isFocused();
    }
    /**
     * Returns true if the component is on a Dialog or a Frame, which is active,
     * or if it is on a Window, which is focused.
     * Always returns true, if the component has no parent window.
     */
    public static boolean isOnActiveWindow(Component c) {
        // In the RootPaneUI, we set a client property on the whole component
        // tree, if the ancestor Frame gets activated or deactivated.
        if (c instanceof JComponent) {
            Boolean value = (Boolean) ((JComponent) c).getClientProperty("Frame.active");
            // Unfortunately, the value is not always reliable.
            // Therefore we can only do a short circuit, if the value is true.
            if (value != null && value.booleanValue()) {
                return true;
            //return value.booleanValue();
            }
        }

        Window window = SwingUtilities.getWindowAncestor(c);
        boolean isOnActiveWindow;
        if (window == null) {
            isOnActiveWindow = true;
        } else if ((window instanceof Frame) || (window instanceof Dialog)) {
            isOnActiveWindow = window.isActive();
        } else {
            if (window.getFocusableWindowState()) {
                isOnActiveWindow = window.isFocused();
            } else {
                isOnActiveWindow = true;
            }
        }

        // In case the activation property is true, we fix the value of the
        // client property, so that we can do a short circuit next time.
        if (isOnActiveWindow && (c instanceof JComponent)) {
            ((JComponent) c).putClientProperty("Frame.active", new Boolean(isOnActiveWindow));
        }
        return isOnActiveWindow;
    }

    /**
     * Returns true, if the component should use the small appearance.
     * @param c
     * @return true, , if the component should use the small appearance.
     */
    public static boolean isSmallSizeVariant(JComponent c) {
        Font f = c.getFont();
        if (f != null && f.getSize() <= 11) {
            return true;
        }
        String p = (String) c.getClientProperty("JComponent.sizeVariant");
        return p != null && p.equals("small");
    }
    public static boolean isHeadless() {
        return GraphicsEnvironment.isHeadless();
    }
    public static void repaintBorder(JComponent component) {
        JComponent c = component;
        Border border = null;
        Container container = component.getParent();
        if (container instanceof JViewport) {
            c = (JComponent) container.getParent();
            if (c != null) {
                border = c.getBorder();
            }
        }
        if (border == null) {
            border = component.getBorder();
            c = component;
        }
        if (border != null && c != null) {
            int w = c.getWidth();
            int h = c.getHeight();
            Insets insets = c.getInsets();
            c.repaint(0, 0, w, insets.top);
            c.repaint(0, insets.top, insets.left, h - insets.bottom - insets.top);
            c.repaint(0, h - insets.bottom, w, insets.bottom);
            c.repaint(w - insets.right, insets.top, insets.right, h - insets.bottom - insets.top);
        }
    }
    public static final Object beginGraphics(Graphics2D graphics2d) {
        Object object = graphics2d.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);

        /*
        AffineTransform tx = graphics2d.getTransform();
        AffineTransform savedTransform = (AffineTransform) tx.clone();
        tx.scale(0.9,0.9);
        graphics2d.setTransform(tx);
         */
        graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        /*graphics2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
        RenderingHints.VALUE_FRACTIONALMETRICS_ON);*/

        //if (true) return savedTransform;
        return object;
    }

    public static final void endGraphics(Graphics2D graphics2d, Object oldHints) {
        /*
        if (true) {
        graphics2d.setTransform((AffineTransform) oldHints);
        return;
        }*/

        if (oldHints != null) {
            graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    oldHints);
        }
    }

    /**
     * Returns the ui that is of type <code>klass</code>, or null if
     * one can not be found.
     */
    public static Object getUIOfType(ComponentUI ui, Class klass) {
        if (klass.isInstance(ui)) {
            return ui;
        }
        return null;
    }

    /**
     * Draw a string with the graphics <code>g</code> at location
     * (<code>x</code>, <code>y</code>)
     * just like <code>g.drawString</code> would.
     * The character at index <code>underlinedIndex</code>
     * in text will be underlined. If <code>index</code> is beyond the
     * bounds of <code>text</code> (including < 0), nothing will be
     * underlined.
     *
     * @param g Graphics to draw with
     * @param text String to draw
     * @param underlinedIndex Index of character in text to underline
     * @param x x coordinate to draw at
     * @param y y coordinate to draw at
     * @since 1.4
     */
    public static void drawStringUnderlineCharAt(Graphics g, String text,
            int underlinedIndex, int x, int y) {        
        g.drawString(text, x, y);
        if (underlinedIndex >= 0 && underlinedIndex < text.length()) {
            FontMetrics fm = g.getFontMetrics();
            int underlineRectX = x + fm.stringWidth(text.substring(0, underlinedIndex));
            int underlineRectY = y;
            int underlineRectWidth = fm.charWidth(text.charAt(underlinedIndex));
            int underlineRectHeight = 1;
            g.fillRect(underlineRectX, underlineRectY + fm.getDescent() - 1,
                    underlineRectWidth, underlineRectHeight);
        }
    }

}
