/*
 * Copyright (c) 2005, 2023, 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 6239944
  @summary PIT: Right clicking on the scrollbar of the choice's dropdown disposes the drop-down, on XToolkit
  @key headful
  @requires (os.family == "linux" | os.family == "windows")
*/

import java.awt.Choice;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

public class ChoiceHandleMouseEvent_2 {

    static Robot robot;
    static volatile Choice choice1;
    static volatile Frame frame;
    static boolean isWindows;

    public static void main(String[] args) throws Exception {
        String os = System.getProperty("os.name").toLowerCase();
        if (!os.startsWith("windows") && !os.startsWith("linux")) {
            System.out.println("This test is only for Windows and Linux");
            return;
        }
        isWindows = os.startsWith("windows");
        try {
            EventQueue.invokeAndWait(() -> createUI());
            runTest();
        } finally {
            if (frame != null) {
                EventQueue.invokeAndWait(() -> frame.dispose());
            }
       }
    }

    static void createUI() {
        choice1 = new Choice();
        for (int i = 1; i<50; i++) {
            choice1.add("item-0"+i);
        }
        choice1.setForeground(Color.red);
        choice1.setBackground(Color.red);
        frame = new Frame("ChoiceHandleMouseEvent_2");
        frame.setBackground(Color.green);
        Panel panel = new Panel();
        panel.setBackground(Color.green);
        panel.add(choice1);
        frame.add(panel);
        frame.setSize(300,300);
        frame.setLocationRelativeTo(null);
        frame.validate();
        frame.setVisible(true);
    }

    static void runTest() throws Exception {
        robot = new Robot();
        robot.setAutoWaitForIdle(true);
        robot.setAutoDelay(50);
        robot.delay(100);

        /*
         * Stage 1. Choice should be closed if user dragged mouse
         * outside of Choice after opening it.
         * Should only pass on Windows or XAWT.
         * Choice on motif might be opened only by click on small box
         * in the right side.
         */
         testDragMouseButtonOut(InputEvent.BUTTON1_DOWN_MASK);
         System.out.println("Passed Stage 1: Choice should be closed if mouse dragged out.");

        /*
         * Stage 2: Choice should be closed if LeftMouse drag finished
         * on Scrollbar. This involeves only one
         * MousePress and one MouseRelease event
         */
         // first parameter is for opening choice. The second is for
         // selecting item inside the menu
         testDragMouseButtonOnSB(InputEvent.BUTTON1_DOWN_MASK);
         System.out.println("Passed Stage 2: Choice should be closed if " +
                            "LeftMouse drag finished on Scrollbar.");

        /*
         * Stage 3: Pressing RIGHT/MIDDLE MouseButton on Scrollbar
         * shouldn't close Choice's pop-down menu.
         * Pressing LEFT MouseButton shouldn't close it too. It should
         * scroll it.
         * This is an unstable test because we doesn't have an API to
         * get Scrollbar from Choice. There is a possibility not to
         * hit the scrollbar that couldn't been predicted.
         */
         // first parameter is for opening choice. The second is for
         // selecting item inside the menu
         testPressOnScrollbar(InputEvent.BUTTON1_DOWN_MASK, InputEvent.BUTTON2_DOWN_MASK);
         testPressOnScrollbar(InputEvent.BUTTON1_DOWN_MASK, InputEvent.BUTTON3_DOWN_MASK);
         System.out.println("Passed Stage 3: Choice correctly reacts on mouse click on its Scrollbar.");

         /*
          * Stage 4: Choice should close its popdown menu if user opened a Choice then
          * releases Mouse and then presses Mouse again and dragged it on Choice's Scrollbar
          * This involves only one MousePress and one MouseRelease
          * event, so it differs from Stage 2.
          */
          // first parameter is for opening choice. The second is for
          // selecting item inside the menu or scrollbar
          testDragMouseOnScrollbar(InputEvent.BUTTON1_DOWN_MASK, InputEvent.BUTTON1_DOWN_MASK);
          System.out.println("Passed Stage 4: Choice should close if user opened a " +
                             "Choice then releases Mouse and then presses Mouse again " +
                             "and drag it on Choice's Scrollbar .");
    }


    //Stage 4
    static void testDragMouseOnScrollbar(int openButton, int button) {
        Point pt = choice1.getLocationOnScreen();
        robot.mouseMove(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2);
        robot.delay(100);
        robot.mousePress(openButton);
        robot.mouseRelease(openButton);
        robot.delay(200);

        robot.mouseMove(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2);
        robot.mousePress(button);
        /*X-coordinate should be closer to right edge of Choice, so
          divider 4 is used. */
        dragMouse(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2,
                  pt.x + choice1.getWidth() - choice1.getHeight()/4, pt.y + 5*choice1.getHeight());
        robot.mouseRelease(button);
        robot.delay(200);

        int px = pt.x + choice1.getWidth()/2;
        int py = pt.y + 3 * choice1.getHeight();
        Color color = robot.getPixelColor(px, py);
        //should take a color on the point on the choice's menu
        System.out.println("Got color " + color + " at (" + px + "," + py + ")");
        if (color.equals(Color.red)) {
            throw new RuntimeException(
               "Test failed. Choice didn't close after drag without firstPress on ScrollBar " + button);
        } else {
            System.out.println("Stage 4 passed."+ button);
        }

        //close opened choice
        robot.keyPress(KeyEvent.VK_ESCAPE);
        robot.keyRelease(KeyEvent.VK_ESCAPE);
        robot.delay(200);
    }

    //stage 3
    static void testPressOnScrollbar(int openButton, int button) {
        if (!isWindows) {
            return; // Windows-only tests.
        }
        Point pt = choice1.getLocationOnScreen();
        robot.mouseMove(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2);
        robot.delay(100);
        robot.mousePress(openButton);
        robot.mouseRelease(openButton);
        robot.delay(200);
        /*X-coordinate should be closer to right edge of Choice, so
          divide by 4 is used. */
        int px = pt.x + choice1.getWidth() - choice1.getHeight()/4;
        int py = pt.y + 5*choice1.getHeight();
        robot.mouseMove(px, py);
        robot.delay(200);
        robot.mousePress(button);
        robot.mouseRelease(button);
        robot.delay(200);

        System.out.println("x= "+px);
        System.out.println("y= "+py);

        /*
          This is for Windows only.
          On XP theme choice become closed on RightMouseClick over a scrollbar.
          A system menu is opened after that. On Classic theme Choice doesn't react on it at all.
        */
        boolean isXPTheme = false;
        Object themeObject = Toolkit.getDefaultToolkit().getDesktopProperty("win.xpstyle.themeActive");
        // it returns null when Classic theme is active but we should
        // check it's boolean value anyway if event it's not null.
        if (themeObject != null) {
            isXPTheme = ((Boolean)themeObject).booleanValue();
        }
        System.out.println("isXPTheme="+isXPTheme);
        px = pt.x + choice1.getWidth()/2;
        py = pt.y + 3 * choice1.getHeight();
        Color color = robot.getPixelColor(px, py);
        //we should take a color on the point on the choice's menu
        System.out.println("Got color " + color + " at (" + px + "," + py + ")");
        System.out.println("RED="+Color.red);
        System.out.println("GREEN="+Color.green);
        if (isXPTheme && button == InputEvent.BUTTON3_DOWN_MASK) {
            if (!color.equals(Color.green)) {
                throw new RuntimeException("Stage 3 failed(XP theme). " +
                  "Choice wasn't closed with pressing button on its Scrollbar" + openButton +":"+button);
            } else {
                System.out.println("Stage 3 passed(XP theme)." + openButton +":"+button);
            }
        } else {
            if (!color.equals(Color.red)) {
                throw new RuntimeException("Stage 3 failed(classic theme). " +
                   "Choice is being closed with pressing button on its Scrollbar" + openButton +":"+button);
            } else {
                System.out.println("Stage 3 passed(classic theme)." + openButton +":"+button);
            }
        }

        //close opened choice
        robot.keyPress(KeyEvent.VK_ESCAPE);
        robot.keyRelease(KeyEvent.VK_ESCAPE);
        robot.delay(200);
    }

    // Stage 1
    static void testDragMouseButtonOut(int button) {
        Point pt = choice1.getLocationOnScreen();

        robot.mouseMove(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2);
        robot.mousePress(button);
        dragMouse(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2,
                  pt.x + choice1.getWidth()*2, pt.y + choice1.getHeight()/2);
        robot.mouseRelease(button);
        robot.delay(200);
        int px = pt.x + choice1.getWidth()/2;
        int py = pt.y + 3 * choice1.getHeight();
        Color color = robot.getPixelColor(px, py);
        //should take a color on the point on the choice's menu
        System.out.println("Got color " + color + " at (" + px + "," + py + ")");
        System.out.println("RED="+Color.red);
        // fix 6268989: On Windows Choice shouldn't been closed if
        //  Mouse dragged outside of Choice after one mouse press.
        if (isWindows) {
            if (color.equals(Color.red)) {
                System.out.println("Stage 1 passed. On Windows Choice shouldn't be " +
                      "closed if Mouse dragged outside of Choice after one mouse press "+button);
            } else {
                throw new RuntimeException("Test failed. Choice on Windows shouldn't be " +
                   "closed after drag outside of Choice after one mouse press "+button);
            }
        } else {
            if (color.equals(Color.red)) {
                throw new RuntimeException("Test failed. Choice didn't close " +
                                           "after drag outside of Choice "+button);
            } else {
                System.out.println("Stage 1 passed."+ button);
            }
        }

        //close opened choice
        robot.keyPress(KeyEvent.VK_ESCAPE);
        robot.keyRelease(KeyEvent.VK_ESCAPE);
        robot.delay(200);
    }

    //stage 2
    static void testDragMouseButtonOnSB(int button) {
        Point pt = choice1.getLocationOnScreen();

        robot.mouseMove(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2);
        robot.mousePress(button);
        /*X-coordinate should be closer to right edge of Choice, so
          divider 4 is used. */
        dragMouse(pt.x + choice1.getWidth()/2, pt.y + choice1.getHeight()/2,
                  pt.x + choice1.getWidth() - choice1.getHeight()/4, pt.y + 5*choice1.getHeight());
        robot.mouseRelease(button);
        robot.delay(200);
        int px = pt.x + choice1.getWidth()/2;
        int py = pt.y + 3 * choice1.getHeight();
        Color color = robot.getPixelColor(px, py);
        //should take a color on the point on the choice's menu
        System.out.println("Got color " + color + " at (" + px + "," + py + ")");
        if (isWindows) {
            if (color.equals(Color.red)) {
                System.out.println("Stage 2 passed. On Windows Choice shouldn't be " +
                                   " closed if Mouse dragged on its scrollbar "+button);
            } else {
                throw new RuntimeException("Test failed. On Windows Choice shouldn't be " +
                                           " closed if Mouse dragged on its scrollbar  "+button);
            }
        } else {
            if (color.equals(Color.red)) {
                throw new RuntimeException("Test failed. Choice didn't close after drag on ScrollBar "+button);
            } else {
                System.out.println("Stage 2 passed."+ button);
            }
        }

        //close opened choice
        robot.keyPress(KeyEvent.VK_ESCAPE);
        robot.keyRelease(KeyEvent.VK_ESCAPE);
        robot.delay(200);
    }

    static void dragMouse(int x0, int y0, int x1, int y1) {
        int curX = x0;
        int curY = y0;
        int dx = x0 < x1 ? 1 : -1;
        int dy = y0 < y1 ? 1 : -1;

        while (curX != x1) {
            curX += dx;
            robot.mouseMove(curX, curY);
        }
        while (curY != y1) {
            curY += dy;
            robot.mouseMove(curX, curY);
        }
    }
}