package fabrik.simulator.pic16f84;

import com.gluonhq.charm.glisten.control.ToggleButtonGroup;
import javafx.collections.ObservableList;
import javafx.scene.control.ToggleButton;
import javafx.stage.Stage;

import java.io.IOException;

public class IOPorts {
    private static final int A = 0;
    private static final int B = 1;
    private static final int PORTA = 5;
    private static final int PORTB = 6;
    private static final int TRISA = 0x85;
    private static final int TRISB = 0x86;

    private static int [] trisLatch = {0xFF, 0xFF};
    private static int [] dataLatch = new int[2];

    public static void setBit (int address, int bit){
        if (address < 7) {
            dataLatch[address - PORTA] |= (1 << bit);
        }
        else{
            trisLatch[address - TRISA] |= (1 << bit);
        }
        refreshPorts();
    }

    public static void clearBit(int address, int bit) {
        if (address < 7) {
            if (((dataLatch[address-PORTA] >> bit)&1) == 1){
                dataLatch[address-PORTA] -= (int) Math.pow(2, bit);
            }
        }
        else{
            if (((trisLatch[address-TRISA] >> bit)&1) == 1){
                trisLatch[address-TRISA] -= (int) Math.pow(2, bit);
            }
        }
        refreshPorts();
    }

    public static void setRegister(int address, int content) {
        if (address < 7) {
            dataLatch[address - PORTA] = content;
        }
        else{
            trisLatch[address - TRISA] = content;
        }
        refreshPorts();
    }

    private static void refreshPorts() {
        DataRegister.setDirectRegister(PORTA, ((~((~dataLatch[A])&0xFF | trisLatch[A])) | (trisLatch[A] & DataRegister.getDirectRegister(PORTA))) & 0xFF);
        DataRegister.setDirectRegister(PORTB, ((~((~dataLatch[B])&0xFF | trisLatch[B])) | (trisLatch[B] & DataRegister.getDirectRegister(PORTB))) & 0xFF);
        DataRegister.setDirectRegister(TRISA, trisLatch[A]);
        DataRegister.setDirectRegister(TRISB, trisLatch[B]);
        ToggleButtonGroup[] buttons = Controller_Frontend.getPORTbuttons();
        for (int i = 0; i < buttons.length; i++){
            int port = (i < 8) ? PORTA : PORTB;
            int bit = i % 8;
            boolean value = ((DataRegister.getDirectRegister(port) >> bit) & 1) == 1;
            buttons[i].getToggles().get(0).setSelected(!value);
            buttons[i].getToggles().get(1).setSelected(value);
        }
    }

    public static void refreshUI(ToggleButtonGroup[] buttonsTRIS, ToggleButtonGroup[] buttonsPORT) {
        for (int i = 0; i< buttonsTRIS.length; i++){
            int tris = (i < 8) ? trisLatch[A] : trisLatch[B];
            boolean val = isInput(tris, i%8);
            buttonsPORT[i].setDisable(!val);
            buttonsTRIS[i].getToggles().get(0).setSelected(val);
            buttonsTRIS[i].getToggles().get(1).setSelected(!val);
        }
    }

    private static boolean isInput(int i, int bit) {
        return (i >> bit & 1) == 1;
    }

    public static void setTRISfromUI(ToggleButtonGroup parent) throws IOException {
        int [] params = getToggleParams(parent);
        int tris = params[0];
        int bit = params[1];
        int value = params[2];
        ToggleButtonGroup [] buttonsPORT = Controller_Frontend.getPORTbuttons();
        if (value == 1){
            setBit(tris, bit);
            buttonsPORT[(tris-TRISA)*8 + bit].setDisable(false);
        }
        else{
            clearBit(tris, bit);
            buttonsPORT[(tris-TRISA)*8 + bit].setDisable(true);
        }
        refreshPorts();
        refreshTable(parent);
    }

    public static void setPORTfromUI(ToggleButtonGroup parent) throws IOException {
        int [] params = getToggleParams(parent);
        int port = params[0];
        int bit = params[1];
        int value = params [2];
        value = (value == 1) ? 0 : 1;
        DataRegister.setDirectBit(port, bit, value);
        refreshPorts();
        refreshTable(parent);
    }

    private static void refreshTable(ToggleButtonGroup parent) throws IOException {
        Stage stage = (Stage) parent.getScene().getWindow();
        Table.refresh();
        CreateWindow.refreshTable(stage);
    }

    private static int[] getToggleParams(ToggleButtonGroup parent) {
        String group = parent.getId();
        ObservableList<ToggleButton> toggles = parent.getToggles();
        int fileAddress;
        if (group.contains("TRIS"))
            if (group.contains("A"))
                fileAddress = TRISA;
            else
                fileAddress = TRISB;
        else
            if (group.contains("A"))
                fileAddress = PORTA;
            else
                fileAddress = PORTB;
        char index =group.charAt(group.length()-1);
        int bit = Integer.parseInt(String.valueOf(index));
        int value = (toggles.get(0).isSelected()) ? 1 : 0;
        return new int[]{fileAddress, bit, value};
    }
}
