/*
 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.apple.laf;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.*;
import javax.swing.text.*;

import com.apple.laf.AquaUtils.RecyclableSingleton;
import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;

public class AquaTextPasswordFieldUI extends AquaTextFieldUI {
    static final RecyclableSingleton<CapsLockSymbolPainter> capsLockPainter = new RecyclableSingletonFromDefaultConstructor<CapsLockSymbolPainter>(CapsLockSymbolPainter.class);
    static CapsLockSymbolPainter getCapsLockPainter() {
        return capsLockPainter.get();
    }

    public static ComponentUI createUI(final JComponent c) {
        return new AquaTextPasswordFieldUI();
    }

    @Override
    protected String getPropertyPrefix() {
        return "PasswordField";
    }

    @Override
    public View create(final Element elem) {
        return new AquaPasswordView(elem);
    }

    @Override
    protected void installListeners() {
        super.installListeners();
        getComponent().addKeyListener(getCapsLockPainter());
    }

    @Override
    protected void uninstallListeners() {
        getComponent().removeKeyListener(getCapsLockPainter());
        super.uninstallListeners();
    }

    @Override
    protected void paintBackgroundSafely(final Graphics g) {
        super.paintBackgroundSafely(g);

        final JTextComponent component = getComponent();
        if (component == null) return;
        if (!component.isFocusOwner()) return;

        final boolean capsLockDown = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK);
        if (!capsLockDown) return;

        final Rectangle bounds = component.getBounds();
        getCapsLockPainter().paintBorder(component, g, bounds.x, bounds.y, bounds.width, bounds.height);
    }

    protected class AquaPasswordView extends PasswordView {
        public AquaPasswordView(final Element elem) {
            super(elem);
            setupDefaultEchoCharacter();
        }

        protected void setupDefaultEchoCharacter() {
            // this allows us to change the echo character in CoreAquaLookAndFeel.java
            final Character echoChar = (Character)UIManager.getDefaults().get(getPropertyPrefix() + ".echoChar");
            if (echoChar != null) {
                LookAndFeel.installProperty(getComponent(), "echoChar", echoChar);
            }
        }
    }

    static class CapsLockSymbolPainter extends KeyAdapter implements Border, UIResource {
        protected Shape capsLockShape;
        protected Shape getCapsLockShape() {
            if (capsLockShape != null) return capsLockShape;

            final RoundRectangle2D rect = new RoundRectangle2D.Double(0.5, 0.5, 16, 16, 8, 8);
            final GeneralPath shape = new GeneralPath(rect);
            shape.setWindingRule(Path2D.WIND_EVEN_ODD);

            // arrow
            shape.moveTo( 8.50,  2.00);
            shape.lineTo( 4.00,  7.00);
            shape.lineTo( 6.25,  7.00);
            shape.lineTo( 6.25, 10.25);
            shape.lineTo(10.75, 10.25);
            shape.lineTo(10.75,  7.00);
            shape.lineTo(13.00,  7.00);
            shape.lineTo( 8.50,  2.00);

            // base line
            shape.moveTo(10.75, 12.00);
            shape.lineTo( 6.25, 12.00);
            shape.lineTo( 6.25, 14.25);
            shape.lineTo(10.75, 14.25);
            shape.lineTo(10.75, 12.00);

            return capsLockShape = shape;
        }

        @Override
        public Insets getBorderInsets(final Component c) {
            return new Insets(0, 0, 0, 0);
        }

        @Override
        public boolean isBorderOpaque() {
            return false;
        }

        @Override
        public void paintBorder(final Component c, Graphics g, final int x, final int y, final int width, final int height) {
            g = g.create(width - 23, height / 2 - 8, 18, 18);

            g.setColor(UIManager.getColor("PasswordField.capsLockIconColor"));
            ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            ((Graphics2D)g).fill(getCapsLockShape());
            g.dispose();
        }

        @Override
        public void keyPressed(final KeyEvent e) {
            update(e);
        }

        @Override
        public void keyReleased(final KeyEvent e) {
            update(e);
        }

        void update(final KeyEvent e) {
            if (KeyEvent.VK_CAPS_LOCK != e.getKeyCode()) return;
            e.getComponent().repaint();
        }
    }
}
