package com.example.rgcas;

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.IOException;
import java.nio.file.attribute.GroupPrincipal;

public class HelloApplication extends Application {
	
	private static Group getSpiral ( double radius, int numberOfArms, int numberOfParts ) {
		Group spiral = new Group ( );
		
		Circle center = new Circle ( radius, Color.RED );
		spiral.getChildren ( ).addAll ( center );
		
		for ( int i = 0; i < numberOfArms; ++i ) {
			Group current = new Group ( );
			Group arm = new Group ( current );
			for ( int j = 0; j < numberOfParts; ++j ) {
				current.getTransforms ( ).addAll (
						new Rotate ( 20 ),
						new Translate ( radius, 0 ),
						new Scale ( 1.25, 1.25 ),
						new Translate ( radius, 0 )
				);
		
				Circle circle = new Circle ( radius, Color.RED );
				current.getChildren ( ).addAll ( circle );
		
				Group newGroup = new Group ( );
				current.getChildren ( ).addAll ( newGroup );
				current = newGroup;
			}
			
			arm.getTransforms ( ).addAll (
					new Rotate ( 360. * i / numberOfArms )
			);
			spiral.getChildren ( ).addAll ( arm );
		}
		
		Rotate rotate = new Rotate ( );
		Scale scale = new Scale ( );
		spiral.getTransforms ( ).addAll ( rotate, scale );
		
		Timeline timeline = new Timeline (
				new KeyFrame (
						Duration.ZERO,
						new KeyValue ( rotate.angleProperty ( ), 0, Interpolator.EASE_BOTH ),
						new KeyValue ( scale.xProperty ( ), 1, Interpolator.LINEAR ),
						new KeyValue ( scale.yProperty ( ), 1, Interpolator.LINEAR )
				),
				new KeyFrame (
						Duration.seconds ( 2 ),
						new KeyValue ( rotate.angleProperty ( ), 360, Interpolator.EASE_BOTH ),
						new KeyValue ( scale.xProperty ( ), 0.5, Interpolator.LINEAR ),
						new KeyValue ( scale.yProperty ( ), 0.5, Interpolator.LINEAR )
				)
		);
		timeline.setCycleCount ( Animation.INDEFINITE );
		timeline.setAutoReverse ( true );
		timeline.play ( );
		
		return new Group ( spiral );
	}
	
	private static Group getSmiley ( double width, double height ) {
		final double radius = Math.min ( width, height ) * 0.45;
		Group smiley = new Group ( );
		
		Circle face = new Circle ( radius );
		face.setFill ( null );
		face.setStroke ( Color.BLACK );
		face.setStrokeWidth ( 10 );
		
		Circle leftEye = new Circle ( 0.2 * radius );
		leftEye.setFill ( Color.BLACK );
		Scale leftEyeScale = new Scale ( );
		leftEye.getTransforms ( ).addAll (
				new Translate ( -radius / 2, -radius / 2 ),
				leftEyeScale
		);
		
		Circle rightEye = new Circle ( 0.2 * radius );
		rightEye.setFill ( Color.BLACK );
		Scale rightEyeScale = new Scale ( );
		rightEye.getTransforms ( ).addAll (
				new Translate ( radius / 2, -radius / 2 ),
				rightEyeScale
		);
		
		Arc mouth = new Arc ( 0, 0, radius / 2, radius / 2, 0, -180 );
		mouth.setFill ( null );
		mouth.setStroke ( Color.BLACK );
		mouth.setStrokeWidth ( 10 );
		
		Scale mouthScale = new Scale ( );
		mouth.getTransforms ( ).addAll (
				new Translate ( 0, radius / 4 ),
				mouthScale,
				new Translate ( 0, -radius / 4 )
		);
		
		smiley.getChildren ( ).addAll ( face, leftEye, rightEye, mouth );
		smiley.getTransforms ( ).add (
				new Translate ( width / 2, height / 2 )
		);
		
		Timeline timeline = new Timeline (
				new KeyFrame (
						Duration.ZERO,
						new KeyValue ( leftEyeScale.yProperty ( ), 1 ),
						new KeyValue ( rightEyeScale.yProperty ( ), 0.1 ),
						new KeyValue ( mouthScale.yProperty ( ), 1 )
				),
				new KeyFrame (
						Duration.seconds ( 2 ),
						new KeyValue ( leftEyeScale.yProperty ( ), 1 ),
						new KeyValue ( rightEyeScale.yProperty ( ), 1 ),
						new KeyValue ( mouthScale.yProperty ( ), 0 )
				),
				new KeyFrame (
						Duration.seconds ( 4 ),
						new KeyValue ( leftEyeScale.yProperty ( ), 0.1 ),
						new KeyValue ( rightEyeScale.yProperty ( ), 1 ),
						new KeyValue ( mouthScale.yProperty ( ), -1 )
				)
		);
		
		timeline.setCycleCount ( Animation.INDEFINITE );
		timeline.setAutoReverse ( true );
		timeline.play ( );
		
		return smiley;
	}
	
	private static Group getPendulum ( double width, double height ) {
		Group pendulum = new Group ( );
		
		Rectangle base = new Rectangle ( 0.5 * width, height - width / 2 );
		base.setFill ( Color.BLACK );
		base.getTransforms ( ).addAll (
				new Translate ( -width / 4, 0 )
		);
		pendulum.getChildren ( ).addAll ( base );
		
		Circle redCircle = new Circle ( width / 2, Color.RED );
		redCircle.getTransforms ( ).addAll (
				new Translate ( 0, height - width / 2 )
		);
		pendulum.getChildren ( ).addAll ( redCircle );
		
		Circle blackCircle = new Circle ( width / 4, Color.BLACK );
		blackCircle.getTransforms ( ).addAll (
				new Translate ( 0, height - width / 2 )
		);
		pendulum.getChildren ( ).addAll ( blackCircle );
		
		Rotate rotate = new Rotate ( );
		pendulum.getTransforms ( ).addAll ( rotate );
		
		Timeline timeline = new Timeline (
				new KeyFrame (
						Duration.ZERO,
						new KeyValue ( rotate.angleProperty ( ), -20, Interpolator.EASE_BOTH )
				),
				new KeyFrame (
						Duration.seconds ( 3 ),
						new KeyValue ( rotate.angleProperty ( ), 20, Interpolator.EASE_BOTH )
				)
		);
		timeline.setAutoReverse ( true );
		timeline.setCycleCount ( Animation.INDEFINITE );
		timeline.play ( );
		
		// timeline.setOnFinished (
		// 		event -> { pendulum.getChildren ( ).remove (  ); }
		// );
		
		return new Group ( pendulum );
	}
	
	@Override
	public void start ( Stage stage ) throws IOException {
		final double WINDOW_WIDTH  = 600;
		final double WINDOW_HEIGHT = 600;
		
		Group root = new Group ( );
		Scale scale = new Scale ( );
		root.getTransforms ( ).addAll (
				scale
		);
		
		Scene scene = new Scene (
				root,
				WINDOW_WIDTH,
				WINDOW_HEIGHT
		);
		
		// final double radius = Math.min ( WINDOW_WIDTH, WINDOW_HEIGHT ) * 0.03;
		// Group spiral = HelloApplication.getSpiral ( radius, 6, 4 );
		// spiral.getTransforms ( ).addAll (
		// 		new Translate ( WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 )
		// );
		// root.getChildren ( ).addAll ( spiral );
		
		// Group smiley = HelloApplication.getSmiley ( WINDOW_WIDTH, WINDOW_HEIGHT );
		// root.getChildren ( ).addAll ( smiley );
		
		Group pendulum = HelloApplication.getPendulum ( WINDOW_WIDTH * 0.05, WINDOW_HEIGHT * 0.9 );
		pendulum.getTransforms ( ).addAll (
				new Translate ( WINDOW_WIDTH / 2, 0 )
		);
		root.getChildren ( ).addAll ( pendulum );
		
		scene.widthProperty ( ).addListener (
				// ( ObservableValue<Number> observable, Number oldValue, Number newValue ) -> {}
				( observable, oldValue, newValue ) -> {
					double newScaleX = newValue.doubleValue ( ) / WINDOW_WIDTH;
					
					scale.setX ( newScaleX );
				}
		);
		
		scene.addEventHandler ( KeyEvent.KEY_PRESSED, event -> {
			if ( event.getCode ( ).equals ( KeyCode.NUMPAD0 ) ) {
				System.out.println ( "Pressed NUMPAD0" );
			}
		} );
		
		Rectangle selection = new Rectangle ( );
		selection.setFill ( null );
		selection.setStroke ( Color.RED );
		selection.setStrokeWidth ( 10 );
		root.getChildren ( ).addAll ( selection );
		
		scene.addEventHandler ( MouseEvent.ANY, event -> {
			double x = event.getX ( );
			double y = event.getY ( );
			
			if ( event.getEventType ( ).equals ( MouseEvent.MOUSE_PRESSED ) ) {
				selection.setX ( x );
				selection.setY ( y );
				selection.setWidth ( 0 );
				selection.setHeight ( 0 );
			} else if ( event.getEventType ( ).equals ( MouseEvent.MOUSE_DRAGGED ) ) {
				double width = x - selection.getX ( );
				double height = y - selection.getY ( );
				
				selection.setWidth ( width );
				selection.setHeight ( height );
			}
		} );
		
		stage.setTitle ( "Hello!" );
		stage.setScene ( scene );
		// stage.setResizable ( false );
		stage.show ( );
	}
	
	public static void main ( String[] args ) {
		launch ( );
	}
}