package nz.ac.massey.javaecs.examples.Systems;

import java.util.BitSet;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import nz.ac.massey.javaecs.ECSSystem;
import nz.ac.massey.javaecs.Engine;
import nz.ac.massey.javaecs.Entity;
import nz.ac.massey.javaecs.examples.App;
import nz.ac.massey.javaecs.examples.Components.BoxRender;
import nz.ac.massey.javaecs.examples.Components.Render;
import nz.ac.massey.javaecs.examples.Components.TextRender;
import nz.ac.massey.javaecs.examples.Components.Vec2D;

public class RenderSystem extends ECSSystem{
    JFXView jFXView;
    Engine gameEngine;
    Thread renderThread;
    double renderScale;
    int screenX = 512;
    int screenY = 512;

    public RenderSystem(Engine gameEngine, double renderScale){
        this.gameEngine = gameEngine;
        // Set registrations
        registrationSet = new BitSet();
        registrationSet.set(gameEngine.getComponentIndex(Render.class));
        registrationSet.set(gameEngine.getComponentIndex(Vec2D.class));
        this.renderScale = renderScale;
    }

    @Override
    public void init() {
        // Spawn a new asynchronous thread (won't rejoin the main program flow)
        renderThread = new Thread(new RenderStarter());
        renderThread.start();
    }

    @Override
    public void update(double dt) {
        // This approach needs reconsidering, as it creates an excessive amount of objects that 
        Group renderScene = new Group();
        for (Entity entity : entities) {
            if (((Render)gameEngine.getComponentData(entity, Render.class)).renderType == BoxRender.class){
                BoxRender box = (BoxRender)gameEngine.getComponentData(entity, BoxRender.class);
                Vec2D vec2d = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);

                Rectangle rect = new Rectangle(box.xSize* renderScale, box.ySize * renderScale);
                rect.setFill(new Color(box.r, box.g, box.b, box.a));
                rect.setX(6 + (vec2d.x * renderScale));
                rect.setY(506 - (vec2d.y * renderScale) - rect.getHeight());
                renderScene.getChildren().add(rect);
            }
            else if (((Render)gameEngine.getComponentData(entity, Render.class)).renderType == TextRender.class){
                Vec2D vec2d = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
                TextRender text = (TextRender)gameEngine.getComponentData(entity, TextRender.class);
                Text t = new Text(vec2d.x * renderScale, vec2d.y * renderScale, text.content);
                t.setFont(new Font(text.size));
                t.setFill(text.color);
                t.setStroke(text.color);
                renderScene.getChildren().add(t);
            }
        }

        // Must be run by the UI thread, not the main thread.
        // This dispatches the operation run() to the UI.
        Platform.runLater(new Runnable(){
            @Override
            public void run() {
                JFXView.root.getChildren().clear();
                JFXView.root.getChildren().add(renderScene);
            }
        });
    }

    // Add a renderer
    public class RenderStarter implements Runnable{

        @Override
        public void run() {
            JFXView.run();
        }
        void updateScene(Group newGroup){
            JFXView.root.getChildren().clear();
            JFXView.root.getChildren().add(newGroup); 
        }
    }

    public static class JFXView extends Application {
        private static Group root;

        @Override
        public void start(Stage primaryStage) throws Exception {
            // based on the colorful circles sample at https://docs.oracle.com/javase/8/javafx/get-started-tutorial/animation.htm 
            root = new Group();
            Scene scene = new Scene(root, 512, 512, Color.BLACK);
            primaryStage.setScene(scene);
            primaryStage.show();
            // Signal the renderer is ready
            App.rendererReadySemaphore.release();
        }
        
        public static void run(){
            launch(new String[0]);
        }
    }
}
