package fabrik.simulator.pic16f84;

import fabrik.simulator.pic16f84.frontendspecifics.VBox;
import fabrik.simulator.pic16f84.interfaces.*;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;

import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;

import javafx.scene.layout.HBox;


import static javafx.application.Application.launch;

public class Table extends PICComponent implements TableInterface  {
    private VBox tableBox;
    private static final int NUM_COLUMNS = 8; // Anzahl der Spalten
    private static final double TABLE_WIDTH = 425; // Breite der TableView
    private static final double TABLE_HEIGHT = 600; // Höhe der TableView

    private static String formatHex(String s) {
        return (s.length() == 1) ? "0" + s : s;
    }

    private static String formatBin (String s){
        int l = s.length();
        if (l < 8){
            StringBuilder sBuilder = new StringBuilder(s);
            for (int i = 0; i < 8 - l; i++){
                sBuilder.insert(0, "0");
            }
            s = sBuilder.toString();
        }
        return s;
    }

    public VBox getTable(){
        refresh();
        return tableBox;
    }

    public void refresh() {
        // Erstelle eine TableView für die Datenanzeige
        TableView<DataEntry[]> tableView = new TableView<>();
        tableView.setPrefWidth(TABLE_WIDTH);
        tableView.setPrefHeight(TABLE_HEIGHT);
        // Erstelle Spalten für die TableView
        for (int i = 0; i < NUM_COLUMNS; i++) {
            TableColumn<DataEntry[], String> column = new TableColumn<>("0" + (i));
            final int columnIndex = i;
            column.setCellValueFactory(cellData -> {
                if (cellData.getValue() != null && cellData.getValue().length > columnIndex) {
                    return new SimpleStringProperty(cellData.getValue()[columnIndex].getValue());
                } else {
                    return new SimpleStringProperty("");
                }
            });
            tableView.getColumns().add(column);
        }
        // Fülle die TableView mit Daten aus dem Array
        int numRows = (int) Math.ceil((double) dataRegister.getDataRegister().length / NUM_COLUMNS);
        for (int row = 0; row < numRows; row++) {
            DataEntry[] rowData = new DataEntry[NUM_COLUMNS];
            for (int col = 0; col < NUM_COLUMNS; col++) {
                int index = row * NUM_COLUMNS + col;
                if (index < dataRegister.getDataRegister().length) {
                    String address = "0x" + formatHex(Integer.toHexString(index).toUpperCase());
                    String value = "0x" + formatHex(Integer.toHexString(dataRegister.getDataRegister()[index]).toUpperCase());
                    rowData[col] = new DataEntry(address, value);
                } else {
                    rowData[col] = new DataEntry("", "");
                }
            }
            tableView.getItems().add(rowData);
        }

        // Erstelle Labels für die Spezialregister;

        Label spacing = new Label(" ");
        Label spacing2 = new Label(" ");
        Label wRegisterLabel = new Label("W-Register: 0x" + formatHex(Integer.toHexString(commands.get_wRegister()).toUpperCase()));
        Label cLabel = new Label("Carry-Flag: " + dataRegister.getCarryFlag());
        Label dcLabel = new Label("DigitCarry-Flag: " + dataRegister.getDigitCarryFlag());
        Label zLabel = new Label("Zero-Flag: " + dataRegister.getZeroFlag());
        Label pcLabel = new Label("PC: 0x" + formatHex(Integer.toHexString(dataRegister.getPC()).toUpperCase()));
        Label pclLabel = new Label("PCL: 0x" + formatHex(Integer.toHexString(dataRegister.getRegister(dataRegister.getPCL())).toUpperCase()));
        Label pclathLabel = new Label("PCLATH: 0x" + formatHex(Integer.toHexString(dataRegister.getRegister(dataRegister.getPCLATH())).toUpperCase()));
        Label statusLabel = new Label("STATUS: 0b" + formatBin(Integer.toBinaryString(dataRegister.getRegister(dataRegister.getSTATUS())))+ " (0x" + formatHex(Integer.toHexString(dataRegister.getRegister(dataRegister.getSTATUS())).toUpperCase()) + ")");
        Label fsrLabel = new Label("FSR: 0x" + formatHex(Integer.toHexString(dataRegister.getFSR()).toUpperCase()));
        Label prescalerLabel = new Label("Prescaler: 0x" + formatHex(Integer.toHexString(preScaler.getScaler())).toUpperCase());
        Label intconLabel = new Label("INTCON: 0b" + formatBin(Integer.toBinaryString(dataRegister.getRegister(dataRegister.getINTCON()))) + " (0x" + formatHex(Integer.toHexString(dataRegister.getRegister(dataRegister.getINTCON())).toUpperCase()) + ")");
        wRegisterLabel.setStyle("-fx-font-weight: bold");
        pcLabel.setStyle("-fx-font-weight: bold");
        statusLabel.setStyle("-fx-font-weight: bold");
        intconLabel.setStyle("-fx-font-weight: bold");

        HBox labelsAndButton = new HBox();
        VBox labels = new VBox();
        labels.getChildren().addAll(spacing, pcLabel, pclLabel, pclathLabel, wRegisterLabel, cLabel, dcLabel, zLabel, statusLabel, fsrLabel, prescalerLabel, intconLabel);
        VBox button = new VBox();
        Button resetButton = new Button("SFR reset");
        resetButton.setOnAction(e -> {
            triggerReset();
        });

        button.getChildren().addAll(spacing2, resetButton);

        labelsAndButton.getChildren().addAll(labels, button);


        // Erstelle einen VBox, um die TableView und Labels anzuzeigen
        VBox table = new VBox();
        table.getChildren().addAll(tableView, labelsAndButton);
        VBox.setMargin(tableView, new Insets(0, 0, 0, 0));
        tableBox = table;
    }

    private void triggerReset() {
        dataRegister.initDataRegister();
        ioPorts.refreshUI(frontendController.getTRISbuttons(), frontendController.getPORTbuttons());
        CreateWindow.refreshTable();
    }

    public static void main(String[] args) {
        launch(args);
    }

    // Hilfsklasse für die Datenanzeige in der TableView
    public static class DataEntry {
        private final String address;
        private final String value;

        public DataEntry(String address, String value) {
            this.address = address;
            this.value = value;
        }

        public String getAddress() {
            return address;
        }

        public String getValue() {
            return value;
        }
    }

    public void initialize(PICComponentLocator picComponents) {
        super.initialize(picComponents);
    }
}
