/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package jace.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import jace.Emulator;
import jace.cheat.MemoryCell;
import jace.core.RAMListener;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.geometry.Insets;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;

/**
 *
 * @author blurry
 */
class Watch extends VBox {

    private static final int GRAPH_WIDTH = 50;
    private static final double GRAPH_HEIGHT = 50;
    int address;
    @SuppressWarnings("all")
    ScheduledFuture redraw;
    Canvas graph;
    List<Integer> samples = Collections.synchronizedList(new ArrayList<>());
    int value = 0;
    BooleanProperty holding = null;
    private final MetacheatUI outer;
    MemoryCell cell;

    public Watch(int address, final MetacheatUI outer) {
        super();
        this.outer = outer;
        this.address = address;
        cell = outer.cheatEngine.getMemoryCell(address);
        redraw = outer.animationTimer.scheduleAtFixedRate(this::redraw, MetacheatUI.FRAME_RATE, MetacheatUI.FRAME_RATE, TimeUnit.MILLISECONDS);
        setBackground(new Background(new BackgroundFill(Color.NAVY, CornerRadii.EMPTY, Insets.EMPTY)));
        Label addrLabel = new Label("$" + Integer.toHexString(address));
        addrLabel.setOnMouseClicked((evt)-> outer.inspectAddress(address));
        addrLabel.setTextAlignment(TextAlignment.CENTER);
        addrLabel.setMinWidth(GRAPH_WIDTH);
        addrLabel.setFont(new Font(Font.getDefault().getFamily(), 14));
        addrLabel.setTextFill(Color.WHITE);
        graph = new Canvas(GRAPH_WIDTH, GRAPH_HEIGHT);
        getChildren().add(addrLabel);
        getChildren().add(graph);
        CheckBox hold = new CheckBox("Hold");
        holding = hold.selectedProperty();
        holding.addListener((prop, oldVal, newVal) -> this.updateHold());
        getChildren().add(hold);
        hold.setTextFill(Color.WHITE);
    }

    public int getValue() {
        return value;
    }

    public void redraw() {
        boolean isRunning = Emulator.withComputer(c->c.getRunningProperty().get(), false);
        if (!isRunning) return;

        int val = cell.value.get() & 0x0ff;
        if (!holding.get()) {
            value = val;
        }
        if (samples.size() >= GRAPH_WIDTH) {
            samples.remove(0);
        }
        samples.add(val);
        Platform.runLater(() -> {
            GraphicsContext g = graph.getGraphicsContext2D();
            g.setFill(Color.BLACK);
            g.fillRect(0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
            if (samples.size() > 1) {
                g.setLineWidth(1);
                g.setStroke(Color.LAWNGREEN);
                int y = (int) (GRAPH_HEIGHT - ((samples.get(0) / 255.0) * GRAPH_HEIGHT));
                g.beginPath();
                g.moveTo(0, y);
                for (int i = 1; i < samples.size(); i++) {
                    y = (int) (GRAPH_HEIGHT - ((samples.get(i) / 255.0) * GRAPH_HEIGHT));
                    g.lineTo(i, y);
                }
                g.stroke();
            }
            g.beginPath();
            g.setStroke(Color.WHITE);
            g.strokeText(String.valueOf(val), GRAPH_WIDTH - 25, GRAPH_HEIGHT - 5);
        });
    }
    RAMListener holdListener;

    public BooleanProperty holdingProperty() {
        return holding;
    }

    private void updateHold() {
        if (!holding.get()) {
            outer.cheatEngine.removeListener(holdListener);
            holdListener = null;
        } else {
            value = Emulator.withComputer(c->c.getMemory().readRaw(address) & 0x0ff, 0);
            holdListener = outer.cheatEngine.forceValue("Watch force value", value, address);
        }
    }

    public void disconnect() {
        holding.set(false);
        redraw.cancel(false);
    }

}
