package application;


	import javafx.application.Application;
import javafx.collections.ObservableList;
	import javafx.event.EventHandler;
	import javafx.event.EventType;
	import javafx.scene.Cursor;
	import javafx.scene.Node;
	import javafx.scene.Parent;
	import javafx.scene.Scene;
	import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

	/**
	 * Util class to handle window resizing when a stage style set to StageStyle.UNDECORATED.
	 * Includes dragging of the stage.
	 * Original on 6/13/14.
	 * Updated on 8/15/17.
	 * Updated on 12/19/19.
	 *
	 * @author Alexander.Berg
	 * @author Evgenii Kanivets
	 * @author Zachary Perales
	 */

	public class ResizeHelperAlexander extends Main {

		 @Override
		 public void start(Stage stage) {
		        BorderPane root = new BorderPane();
		        Scene scene = new Scene(root, 800, 600);
		        stage.setScene(scene);
		        //stage.setTitle("Resizable Stage Example");
                System.out.println("Hello");
		        // Call addResizeListener() from ResizeHelperAlexander and pass primaryStage
		        ResizeHelperAlexander.addResizeListener(stage);

		        stage.show();
		 }
		 
	    public static void addResizeListener(Stage stage) {
	    	System.out.println("Hello2");
	        addResizeListener(stage, 1, 1, Double.MAX_VALUE, Double.MAX_VALUE);
	    }

	    public static void addResizeListener(Stage stage, double minWidth, double minHeight, double maxWidth, double maxHeight) {
	    	
	    	ResizeListener resizeListener = new ResizeListener(stage);
	        stage.getScene().addEventHandler(MouseEvent.MOUSE_MOVED, resizeListener);
	        stage.getScene().addEventHandler(MouseEvent.MOUSE_PRESSED, resizeListener);
	        stage.getScene().addEventHandler(MouseEvent.MOUSE_DRAGGED, resizeListener);
	        stage.getScene().addEventHandler(MouseEvent.MOUSE_EXITED, resizeListener);
	        stage.getScene().addEventHandler(MouseEvent.MOUSE_EXITED_TARGET, resizeListener);

	        resizeListener.setMinWidth(minWidth);
	        resizeListener.setMinHeight(minHeight);
	        resizeListener.setMaxWidth(maxWidth);
	        resizeListener.setMaxHeight(maxHeight);

	        ObservableList<Node> children = stage.getScene().getRoot().getChildrenUnmodifiable();
	        for (Node child : children) {
	            addListenerDeeply(child, resizeListener);
	        }
	        System.out.println("Hello3");
	    }

	    
	    public static void addListenerDeeply(Node node, EventHandler<MouseEvent> listener) {
	    	System.out.println("Hello4");
	        node.addEventHandler(MouseEvent.MOUSE_MOVED, listener);
	        node.addEventHandler(MouseEvent.MOUSE_PRESSED, listener);
	        node.addEventHandler(MouseEvent.MOUSE_DRAGGED, listener);
	        node.addEventHandler(MouseEvent.MOUSE_EXITED, listener);
	        node.addEventHandler(MouseEvent.MOUSE_EXITED_TARGET, listener);
	        if (node instanceof Parent) {
	            Parent parent = (Parent) node;
	            ObservableList<Node> children = parent.getChildrenUnmodifiable();
	            for (Node child : children) {
	                addListenerDeeply(child, listener);
	            } 
	        }
	        System.out.println("Hello4");
	    }
	    

	    static class ResizeListener implements EventHandler<MouseEvent> {
	        private Stage stage;
	        private Cursor cursorEvent = Cursor.DEFAULT;
	        private boolean resizing = true;
	        private int border = 4;
	        private double startX = 0;
	        private double startY = 0;
	        private double screenOffsetX = 0;
	        private double screenOffsetY = 0;
	       
	        // Max and min sizes for controlled stage
	        private double minWidth;
	        private double maxWidth;
	        private double minHeight;
	        private double maxHeight;
	   
	        public ResizeListener(Stage stage) {
	            this.stage = stage;
	        }

	        public void setMinWidth(double minWidth) {
	            this.minWidth = minWidth;
	        }

	        public void setMaxWidth(double maxWidth) {
	            this.maxWidth = maxWidth;
	        }

	        public void setMinHeight(double minHeight) {
	            this.minHeight = minHeight;
	        }

	        public void setMaxHeight(double maxHeight) {
	            this.maxHeight = maxHeight;
	        }

	        @Override
	        public void handle(MouseEvent mouseEvent) {
	        	System.out.println("Hello6");
	            EventType<? extends MouseEvent> mouseEventType = mouseEvent.getEventType();
	            Scene scene = stage.getScene();

	            double mouseEventX = mouseEvent.getSceneX(),
	                    mouseEventY = mouseEvent.getSceneY(),
	                    sceneWidth = scene.getWidth(),
	                    sceneHeight = scene.getHeight();

	            if (MouseEvent.MOUSE_MOVED.equals(mouseEventType)) {
	                if (mouseEventX < border && mouseEventY < border) {
	                    cursorEvent = Cursor.NW_RESIZE;
	                } else if (mouseEventX < border && mouseEventY > sceneHeight - border) {
	                    cursorEvent = Cursor.SW_RESIZE;
	                } else if (mouseEventX > sceneWidth - border && mouseEventY < border) {
	                    cursorEvent = Cursor.NE_RESIZE;
	                } else if (mouseEventX > sceneWidth - border && mouseEventY > sceneHeight - border) {
	                    cursorEvent = Cursor.SE_RESIZE;
	                } else if (mouseEventX < border) {
	                    cursorEvent = Cursor.W_RESIZE;
	                } else if (mouseEventX > sceneWidth - border) {
	                    cursorEvent = Cursor.E_RESIZE;
	                } else if (mouseEventY < border) {
	                    cursorEvent = Cursor.N_RESIZE;
	                } else if (mouseEventY > sceneHeight - border) {
	                    cursorEvent = Cursor.S_RESIZE;
	                } else {
	                    cursorEvent = Cursor.DEFAULT;
	                }
	                scene.setCursor(cursorEvent);
	            } else if (MouseEvent.MOUSE_EXITED.equals(mouseEventType) || MouseEvent.MOUSE_EXITED_TARGET.equals(mouseEventType)) {
	                scene.setCursor(Cursor.DEFAULT);
	            } else if (MouseEvent.MOUSE_PRESSED.equals(mouseEventType)) {
	                startX = stage.getWidth() - mouseEventX;
	                startY = stage.getHeight() - mouseEventY;
	            } else if (MouseEvent.MOUSE_DRAGGED.equals(mouseEventType)) {
	                if (!Cursor.DEFAULT.equals(cursorEvent)) {
	                    resizing = true;
	                    if (!Cursor.W_RESIZE.equals(cursorEvent) && !Cursor.E_RESIZE.equals(cursorEvent)) {
	                        double minHeight = stage.getMinHeight() > (border * 2) ? stage.getMinHeight() : (border * 2);
	                        if (Cursor.NW_RESIZE.equals(cursorEvent) || Cursor.N_RESIZE.equals(cursorEvent)
	                                || Cursor.NE_RESIZE.equals(cursorEvent)) {
	                            if (stage.getHeight() > minHeight || mouseEventY < 0) {
	                                setStageHeight(stage.getY() - mouseEvent.getScreenY() + stage.getHeight());
	                                stage.setY(mouseEvent.getScreenY() );
	                            }
	                        } else {
	                            if (stage.getHeight() > minHeight || mouseEventY + startY - stage.getHeight() > 0) {
	                                setStageHeight(mouseEventY + startY);
	                            }
	                        }
	                    }

	                    if (!Cursor.N_RESIZE.equals(cursorEvent) && !Cursor.S_RESIZE.equals(cursorEvent)) {
	                        double minWidth = stage.getMinWidth() > (border * 2) ? stage.getMinWidth() : (border * 2);
	                        if (Cursor.NW_RESIZE.equals(cursorEvent) || Cursor.W_RESIZE.equals(cursorEvent)
	                                || Cursor.SW_RESIZE.equals(cursorEvent)) {
	                            if (stage.getWidth() > minWidth || mouseEventX < 0) {
	                                setStageWidth(stage.getX() - mouseEvent.getScreenX() + stage.getWidth());
	                                stage.setX(mouseEvent.getScreenX());
	                            }
	                        } else {
	                            if (stage.getWidth() > minWidth || mouseEventX + startX - stage.getWidth() > 0) {
	                                setStageWidth(mouseEventX + startX);
	                            }
	                        }
	                    }
	                    resizing = false;
	                }
	            }

	            if (MouseEvent.MOUSE_PRESSED.equals(mouseEventType) && Cursor.DEFAULT.equals(cursorEvent)) {
	                resizing = false;
	                screenOffsetX = stage.getX() - mouseEvent.getScreenX();
	                screenOffsetY = stage.getY() - mouseEvent.getScreenY();
	            }

	            if (MouseEvent.MOUSE_DRAGGED.equals(mouseEventType) && Cursor.DEFAULT.equals(cursorEvent) && resizing == false) {
	                stage.setX(mouseEvent.getScreenX() + screenOffsetX);
	                stage.setY(mouseEvent.getScreenY() + screenOffsetY);
	            }

	        }

	        private void setStageWidth(double width) {
	            width = Math.min(width, maxWidth);
	            width = Math.max(width, minWidth);
	            stage.setWidth(width);
	        }

	        private void setStageHeight(double height) {
	            height = Math.min(height, maxHeight);
	            height = Math.max(height, minHeight);
	            stage.setHeight(height);
	        }

	    }
	}