/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */
import com.sun.glass.ui.Robot;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingNode;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 *
 * Test checks that SwingNode can be translucent and swing components draw correctly.
 *
 * @author aeremeev
 *
 */
public class SwingNodeTranslucentTest extends Application {

    private String[] components = new String[] {
        "javax.swing.JButton",
        "javax.swing.JCheckBox",
        "javax.swing.JTextField",
        "javax.swing.JLabel",
        "javax.swing.JList"
    };
    private Robot robot;
    private Stage primary;

    private final Color color = Color.RED;
    private static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");

    private Point location;
    private Dimension size;

    private Flag secondaryStageClicked = new Flag();
    private Flag mouseClicked = new Flag();

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.err.println("Uncaught exception on thread : " + t);
                e.printStackTrace();
                System.exit(1);
            }
        });
        stage.initStyle(StageStyle.TRANSPARENT);
        final SwingNode swingNode = new SwingNode();
        robot = createRobot();
        StackPane pane = new StackPane();
        Scene scene = new Scene(pane, 300, 300);
        stage.setScene(scene);
        Shape shape = Shape.union(Shape.subtract(new Rectangle(0, 0, 300, 300), new Ellipse(150, 150, 140, 140)), new Rectangle(120, 120, 60, 60));
        scene.setFill(null);
        pane.setClip(shape);
        pane.getChildren().add(swingNode);
        stage.setOnShown(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                new Thread(() -> {
                    try {
                        for (final String c : components) {
                            System.out.println("Testing " + c);
                            final JComponent component = init(swingNode, c);
                            Flag.waitForIdle(500);
                            SwingUtilities.invokeAndWait(() -> {
                                location = component.getLocationOnScreen();
                                size = component.getSize();
                            });
                            invokeAndWait(() -> {
                                robot.mouseMove(location.x + size.width / 2, location.y + size.height / 2);
                                delay(500);
                                robot.mousePress(MouseEvent.BUTTON1);
                                delay(100);
                                robot.mouseRelease(MouseEvent.BUTTON1);
                            });
                            if (!mouseClicked.waitForFlagTriggered()) {
                                System.err.println("Button did not get mouse click event");
                                System.exit(1);
                            }
                            invokeAndWait(() -> {
                                if (!colorCheck(c) && robot.getPixelColor(location.x + size.width / 2, location.y + size.height / 2) != color.getRGB()) {
                                    System.err.println("JComponent " + c + " is not red");
                                    System.exit(1);
                                }
                            });
                            reset();
                            Platform.runLater(() -> {
                                robot.mouseMove(location.x + size.width / 2, location.y + 5);
                                delay(500);
                                robot.mousePress(MouseEvent.BUTTON1);
                                delay(100);
                                robot.mouseRelease(MouseEvent.BUTTON1);
                            });
                            if (mouseClicked.waitForFlagTriggered(5)) {
                                System.err.println("Button got mouse click event");
                                System.exit(1);
                            }
                            if (!secondaryStageClicked.waitForFlagTriggered()) {
                                System.err.println("SwingNode is not translucent");
                                System.exit(1);
                            }
                            reset();
                            invokeAndWait(() -> {
                                robot.mouseMove(location.x + size.width - 5, location.y + size.height / 2);
                                delay(500);
                                robot.mousePress(MouseEvent.BUTTON1);
                                delay(100);
                                robot.mouseRelease(MouseEvent.BUTTON1);
                            });
                            if (mouseClicked.waitForFlagTriggered(5)) {
                                System.err.println("Button got mouse click event");
                                System.exit(1);
                            }
                            if (!secondaryStageClicked.waitForFlagTriggered()) {
                                System.err.println("SwingNode is not traslucent");
                                System.exit(1);
                            }
                            reset();
                            invokeAndWait(() -> {
                                robot.mouseMove(location.x + size.width / 2, location.y + size.height - 5);
                                delay(500);
                                robot.mousePress(MouseEvent.BUTTON1);
                                delay(100);
                                robot.mouseRelease(MouseEvent.BUTTON1);
                            });
                            if (mouseClicked.waitForFlagTriggered(5)) {
                                System.err.println("Button got mouse click event");
                                System.exit(1);
                            }
                            if (!secondaryStageClicked.waitForFlagTriggered()) {
                                System.err.println("SwingNode is not traslucent");
                                System.exit(1);
                            }
                            reset();
                            invokeAndWait(() -> {
                                robot.mouseMove(location.x + 5, location.y + size.height / 2);
                                delay(500);
                                robot.mousePress(MouseEvent.BUTTON1);
                                delay(100);
                                robot.mouseRelease(MouseEvent.BUTTON1);
                            });
                            if (mouseClicked.waitForFlagTriggered(5)) {
                                System.err.println("Button got mouse click event");
                                System.exit(1);
                            }
                            if (!secondaryStageClicked.waitForFlagTriggered()) {
                                System.err.println("SwingNode is not traslucent");
                                System.exit(1);
                            }
                        }
                    } catch (InvocationTargetException | InterruptedException e) {
                        e.printStackTrace();
                        System.exit(1);
                    }
                    System.exit(0);
                }).start();
            }
        });
        Stage s = new Stage();
        Scene secScene = new Scene(new StackPane(), 300, 300);
        s.setScene(secScene);
        s.initStyle(StageStyle.TRANSPARENT);
        s.initOwner(stage);
        secScene.setOnMouseClicked(new EventHandler<javafx.scene.input.MouseEvent>() {
            @Override
            public void handle(javafx.scene.input.MouseEvent event) {
                primary.toFront();
                secondaryStageClicked.flagTriggered();
            }
        });
        primary = stage;
        s.show();
        stage.show();
    }

    private boolean colorCheck(String c) {
        return (isMac && "javax.swing.JButton".equals(c));
    }

    private void reset() {
        secondaryStageClicked.reset();
        mouseClicked.reset();
    }

    private Robot createRobot() {
        return com.sun.glass.ui.Application.GetApplication().createRobot();
    }

    private void invokeAndWait(Runnable run) {
        com.sun.glass.ui.Application.invokeAndWait(run);
    }

    private JComponent init(final SwingNode swingNode, final String c) throws InterruptedException, InvocationTargetException {
        final JComponent[] component = new JComponent[1];
        SwingUtilities.invokeAndWait(() -> {
            try {
                JPanel panel = new JPanel();
                panel.setLayout(null);
                panel.setBackground(Color.BLUE);
                component[0] = (JComponent) Class.forName(c).newInstance();
                component[0].setBounds(110, 110, 80, 80);
                component[0].addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(java.awt.event.MouseEvent e) {
                        mouseClicked.flagTriggered();
                    }
                });
                if(component[0] instanceof JLabel){
                    component[0].setOpaque(true);
                }
                component[0].setBackground(color);
                panel.add(component[0]);
                swingNode.setContent(panel);
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
                ex.printStackTrace();
                throw new RuntimeException(ex);
            }
        });
        return component[0];
    }

    private void delay(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
        }
    }
}
