/*
 * Copyright (c) 2015, 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.
 *
 * 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.
 */

/*
 * @test
 * @bug 8071705
 * @summary  Java application menu misbehaves when running multiple screen stacked vertically
 * @build bug8071705
 * @run main/othervm bug8071705
 */

import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.util.concurrent.CountDownLatch;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class bug8071705 {

    public static void main(String[] args) throws Exception {

        final CountDownLatch latch = new CountDownLatch(1);
        final boolean [] result = new boolean[1];

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = createGUI();
                GraphicsDevice[] devices = checkScreens();

                // check if we have more than one and if they are stacked
                // vertically
                GraphicsDevice device = checkConfigs(devices);
                if (device == null) {
                    // just pass the test
                    frame.dispose();
                    result[0] = true;
                    latch.countDown();
                } else {
                    FrameListener listener =
                            new FrameListener(device, latch, result);
                    frame.addComponentListener(listener);
                    frame.setVisible(true);
                }
            }
        });

        latch.await();

        if (result[0] == false) {
            throw new RuntimeException("popup menu rendered in wrong position");
        }

        System.out.println("OK");
    }

    private static GraphicsDevice[] checkScreens() {
        GraphicsEnvironment ge =
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        return ge.getScreenDevices();
    }

    private static JFrame createGUI() {
        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Some menu");
        menuBar.add(menu);

        for (int i = 0; i < 10; i++) {
            menu.add(new JMenuItem("Some menu #" + i));
        }

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(200, 200));
        frame.setJMenuBar(menuBar);
        return frame;
    }

    private static GraphicsDevice checkConfigs(GraphicsDevice[] devices) {

        GraphicsDevice correctDevice = null;
        if (devices.length < 2) {
            return correctDevice;
        }

        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Rectangle screenBounds = new Rectangle(toolkit.getScreenSize());
        int halfScreen = screenBounds.height/2;

        for(int i = 0; i < devices.length; i++) {
            if(devices[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
                GraphicsConfiguration conf =
                        devices[i].getDefaultConfiguration();
                Rectangle bounds = conf.getBounds();
                if (bounds.y >= halfScreen) {
                    // found
                    correctDevice = devices[i];
                    break;
                }
            }
        }
        return correctDevice;
    }

    private static class FrameListener extends ComponentAdapter {

        private GraphicsDevice device;
        private CountDownLatch latch;
        private boolean [] result;
        public FrameListener(GraphicsDevice device,
                             CountDownLatch latch,
                             boolean [] result)
        {
            this.device = device;
            this.latch = latch;
            this.result = result;
        }

        @Override
        public void componentShown(ComponentEvent e) {
            JFrame frame = (JFrame) e.getComponent();

            runActualTest(device, latch, frame, result);

            frame.setVisible(false);
            frame.dispose();
            latch.countDown();
        }
    }

    private static Rectangle setLocation(JFrame frame, GraphicsDevice device) {
        GraphicsConfiguration conf = device.getDefaultConfiguration();
        Rectangle bounds = conf.getBounds();

        // put just below half screen
        int x = bounds.x + bounds.width/2;
        int y = bounds.y + bounds.height/2;
        frame.setLocation(x, y);

        return bounds;
    }

    private static void runActualTest(GraphicsDevice device,
                                      CountDownLatch latch,
                                      JFrame frame,
                                      boolean [] result)
    {
        Rectangle screenBounds = setLocation(frame, device);
        JMenu menu = frame.getJMenuBar().getMenu(0);
        menu.doClick();

        Point location = menu.getLocationOnScreen();
        JPopupMenu pm = menu.getPopupMenu();
        Dimension pmSize = pm.getSize();

        int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY");
        int height = location.y + yOffset + pmSize.height + menu.getHeight();
        int available = screenBounds.y + screenBounds.height - height;
        if (available > 0) {
            Point origin = pm.getLocationOnScreen();
            if (origin.y < location.y) {
                // growing upward, wrong!
                result[0] = false;
            } else {
                // growing downward, ok!
                result[0] = true;
            }
        } else {
            // there is no space, growing upward would be ok, so we pass
            result[0] = true;
        }
    }
}
