import { Point, Connection, ConnectionNetwork } from "./classes.js"
// globale valiables
var voltageGraph = null; //graph for tracing single neurons
var simulationInterval = null; //interval for plotting data in Graphs
const connectionNet = new ConnectionNetwork();
var editor;

const boardColorSelected = "rgb(255, 215, 0)";
const boardColorNotSelected = "rgb(0, 187, 0)";

var outputURL = "";
var mainBoard = "";

/*******************************************************
*
Directory
1. Sundries
2. Cluster-Setup
3. Cluster-Functionality
4. Graph-Functiosn
5. For html-display
6. Functions for Profiles
7. Read in Networkinformations
8. Editor functions
9. Perform Simulation
10. Input Validation
11. Console Output
*
*******************************************************/

/* 1. Sundries */
// function to get the csrf-token for post and delete requests
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

/* 2. Cluster-Setup */
function readClusterInformations() {

    return fetch("/interface/cluster_information/")
        .then(res => {
            if (res.ok) {
                return res.json();
            } else if (res.status == 405) {
                console.log("Use not Get-Method");
                return null;
            } else {
                console.log("Some deeper issues with cluster_information.");
                return null;
            }
        })
}

// Creates the Cluster-Matrix of checkboxen with the size ixj
function initClusterDiv(i, j, fpgaNames) {
    let column = Math.min(i, j);
    let row = Math.max(i, j);
    let divCluster = document.querySelector("#matrix"); //height: 42vh, width: 50vw
    const divHeight = 84 //vh

    let countRows = row * 2 + 1;
    let countColumns = column * 2;

    let heightRow = divHeight / countRows;
    let strHeightRow = heightRow + "vh";

    let str = "repeat(" + countRows + ", " + strHeightRow + ")";
    divCluster.style.gridTemplateRows = str;

    str = "repeat(" + countColumns + "," + strHeightRow + ") auto"
    divCluster.style.gridTemplateColumns = str;

    let rowPosition = 0;
    let columnPosition = 0;

    // let fpgaNames = [["21", "20", "1B", "29", "31"], ["2B", "0A", "27", "1E", "1F"], ["B7", "C2", "C9", "82", "A9"], ["F4", "C3", "B8", "B2", "9E"], ["FB", "C7", "BC", "D3", "BA"], ["F2", "73", "C0", "ED", "D5"], ["FD", "3A", "AF", "B6", "C6"]]

    for (let r = 0; r < row; ++r) {
        for (let c = 0; c < column; ++c) {
            rowPosition = (r + 1) * 2;
            columnPosition = (c + 1) * 2;
            let id = "b-" + (c + 100) + "-" + (row - r - 1 + 100);

            createBoard(rowPosition, columnPosition, strHeightRow, id, divCluster, fpgaNames[r][c]);
        }
    }
    return heightRow; // XXX übergabe der höhe an initConnections besser machen
}

function createBoard(rowPosition, columnPosition, size, id, destination, name) {
    // create and insert checkbox
    let checkNew = document.createElement("input");
    checkNew.setAttribute("type", "checkbox");
    checkNew.setAttribute("name", "board");
    checkNew.setAttribute("id", id);
    checkNew.style.zIndex = "0";
    checkNew.style.display = "none";
    checkNew.addEventListener("change", toggleBoardColor);
    destination.appendChild(checkNew);

    // create and insert label to represent the checkboxes
    let labelNew = document.createElement("label");
    labelNew.setAttribute("for", id);
    labelNew.innerText = name;
    labelNew.style.width = size;
    labelNew.style.height = size;
    labelNew.style.gridRow = rowPosition + "/" + (rowPosition + 1);
    labelNew.style.gridColumn = columnPosition + "/" + (columnPosition + 1);
    destination.appendChild(labelNew);
}

async function readConnectionsInformations() {
    return await fetch("/interface/connections_informations/")
        .then(res => {
            if (res.ok) {
                return res.json();
            } else {
                console.log("Request error")
            }
        });
}

function initConnections(proportionList, connectionList, rowSize, torus) {

    let destination = document.querySelector("#matrix");

    let connections = new Array();
    for (let element of connectionList) {
        element = element.slice(1, -1);
        let str = element.split(",");
        connections.push(new Point(parseInt(str[0].trim()), parseInt(str[1].trim())));
    }
    // console.log(connections)

    let column = Math.min(proportionList[0], proportionList[1]);
    let row = Math.max(proportionList[0], proportionList[1]);
    // console.log("Row: " + row + ", Column: " + column);
    for (let c = 0; c < column; ++c) {
        for (let r = 0; r < row; ++r) {
            for (let conn of connections) {
                let secondX = c + conn.x;
                let secondY = r + conn.y;
                // console.log("X: " + secondX + ", Y: " + secondY);

                // XXX The if-else for the torus in the inner for ist inefficient. Maybe a Funktion for each of the possible taurus values
                if (torus === "both") {
                    if (secondX > column - 1) {
                        secondX = secondX - column;
                    } else if (secondX < 0) {
                        secondX = column + secondX;
                    }

                    if (secondY > row - 1) {
                        secondY = secondY - row;
                    } else if (secondY < 0) {
                        console.log(secondY)
                        secondY = row + secondY;
                        console.log(secondY)
                    }
                } else if (torus === "vertical") {
                    if (secondY > row - 1 || secondY < 0) {
                        continue
                    }

                    if (secondX > column - 1) {
                        secondX = secondX - column;
                    } else if (secondX < 0) {
                        secondX = column + secondX;
                    }
                } else if (torus === "horizontal") {
                    if (secondX > column - 1 || secondX < 0) {
                        continue;
                    }

                    if (secondY > row - 1) {
                        secondY = secondY - row;
                    } else if (secondY < 0) {
                        secondY = row + secondY;
                    }
                } else if (torus === "off") {
                    if (secondX > column - 1 || secondY > row - 1 || secondX < 0 || secondY < 0) {
                        continue;
                    }
                } else {
                    throw new Error(torus + " is undefined")
                }
                createConnection(c, r, secondX, secondY, column, row, rowSize, destination);
            }
        }
    }
}

// DELETE
/* function createConnection(width, height, marginTB, marginLR, rowPosition, columnPosition, destination) {
    let lineNew = document.createElement("hr");
    lineNew.style.width = width;
    lineNew.style.height = height;
    lineNew.style.margin = marginTB + " " + marginLR;
    lineNew.style.gridRow = rowPosition + "/" + (rowPosition + 1);
    lineNew.style.gridColumn = columnPosition + "/" + (columnPosition + 1);
    destination.appendChild(lineNew);
} */
function createConnection(firstBoardX, firstBoardY, secondBoardX, secondBoardY, columns, rows, rowSize, destination) {
    let firstBoardName = (firstBoardX + 100) + "-" + (rows - firstBoardY - 1 + 100);
    let secondBoardName = (secondBoardX + 100) + "-" + (rows - secondBoardY - 1 + 100);

    // length calculation
    let lenX = (firstBoardX - secondBoardX + Math.sign(secondBoardX - firstBoardX) * 0.5) * 2 * rowSize;
    let lenY = (firstBoardY - secondBoardY + Math.sign(secondBoardY - firstBoardY) * 0.5) * 2 * rowSize;
    let lenLine = Math.sqrt(Math.pow(lenX, 2) + Math.pow(lenY, 2)) / 2;
    let degree = (lenX != 0) ? Math.atan(lenY / lenX) * 180 / Math.PI : 90;

    const shiftFactor = lenLine * 0.12;
    let shiftOrigin = rowSize / 2 * 0.8

    let linePositionX = ((Math.abs(firstBoardX - secondBoardX) + 0.5) * rowSize) - (0.25 * lenX) + (Math.min(firstBoardX, secondBoardX) * 2 + 1) * rowSize - lenLine / 2;
    let linePositionY = ((Math.abs(firstBoardY - secondBoardY) + 0.5) * rowSize) - (0.25 * lenY) + (Math.min(firstBoardY, secondBoardY) * 2 + 1) * rowSize;

    if (Math.abs(firstBoardX - secondBoardX) >= Math.abs(firstBoardY - secondBoardY)) {
        linePositionY = linePositionY + shiftFactor - shiftOrigin;
    } else {
        linePositionX = linePositionX + shiftFactor - shiftOrigin;
    }

    let line = document.createElement("hr")
    let className = "connections c-" + firstBoardName + " c-" + secondBoardName;
    line.setAttribute("class", className);
    line.style.position = "absolute";
    line.style.left = linePositionX + "vh";
    line.style.top = linePositionY + "vh";
    line.style.width = (lenLine + 0.04) + "vh";
    line.style.transform = "rotate(" + degree + "deg)";
    line.addEventListener("click", showConnectionInformations);
    connectionNet.addElement(new Connection(firstBoardName, secondBoardName));
    destination.appendChild(line);


    linePositionX = ((Math.abs(firstBoardX - secondBoardX) + 0.5) * rowSize) + (0.25 * lenX) + (Math.min(firstBoardX, secondBoardX) * 2 + 1) * rowSize - lenLine / 2;
    linePositionY = ((Math.abs(firstBoardY - secondBoardY) + 0.5) * rowSize) + (0.25 * lenY) + (Math.min(firstBoardY, secondBoardY) * 2 + 1) * rowSize;

    if (Math.abs(firstBoardX - secondBoardX) >= Math.abs(firstBoardY - secondBoardY)) {
        linePositionY = linePositionY + shiftFactor - shiftOrigin;
    } else {
        linePositionX = linePositionX + shiftFactor - shiftOrigin;
    }

    line = document.createElement("hr")
    className = "connections c-" + secondBoardName + " c-" + firstBoardName;
    line.setAttribute("class", className);
    line.style.position = "absolute";
    line.style.left = linePositionX + "vh";
    line.style.top = linePositionY + "vh";
    line.style.width = (lenLine + 0.04) + "vh";
    line.style.transform = "rotate(" + degree + "deg)";
    line.addEventListener("click", showConnectionInformations);
    connectionNet.addElement(new Connection(secondBoardName, firstBoardName));
    destination.appendChild(line);
}

/* 3. Cluster Functionality */
// Toggle the backgroundColor of the labels if checkbox get checked
function toggleBoardColor() {
    let selected = isConnectionSelected();
    let id = this.getAttribute("id");
    let lab = document.querySelector("#matrix label[for=" + id + "]");
    let idElements = id.split("-");
    let className = ".c-" + idElements[1] + "-" + idElements[2];
    let connectionList = document.querySelectorAll(className);


    if (this.checked) {

        if (!selected) {
            let conn = document.querySelectorAll(".connections");
            for (let element of conn) {
                element.style.visibility = "hidden";
            }
        }

        lab.style.backgroundColor = boardColorSelected;

        for (let element of connectionList) {
            element.style.visibility = "visible";
        }

    } else {

        lab.style.backgroundColor = boardColorNotSelected;

        for (let element of connectionList) {
            element.style.visibility = "hidden";
        }

        if (!selected) {
            let conn = document.querySelectorAll(".connections");
            for (let element of conn) {
                element.style.visibility = "visible";
            }
        }
    }
}

function isConnectionSelected() {
    let checkboxList = document.querySelectorAll("#matrix > input[type=\"checkbox\"]");
    for (let element of checkboxList) {
        if (element.checked && document.querySelector("#matrix > label[for=" + element.getAttribute("id") + "]").style.backgroundColor === boardColorSelected) {
            return true;
        }
    }
    return false;
}

function showConnectionInformations() {
    let sideElement = document.querySelector("#errorInformations");
    let connName = this.getAttribute("class").split(" ");
    let conn = connectionNet.getConnection(connName[1] + " " + connName[2]);

    sideElement.style.visibility = "Visible";

    document.querySelector("#info-source").textContent = conn.startNode;
    document.querySelector("#info-target").textContent = conn.endNode;
    document.querySelector("#info-delivered").textContent = conn.deliveredFileCount;
    document.querySelector("#info-crcerror").textContent = conn.crcError;
    document.querySelector("#info-dropped").textContent = conn.droppedError;
    document.querySelector("#info-wrongid").textContent = conn.wrongId;
}

function hideInformations() {
    document.querySelector("#errorInformations").style.visibility = "hidden";
}

async function updateConnections() {
    // let boardList = document.querySelectorAll("#matrix > input[name=\"board\"]");
    // for(let board of boardList){
    //     let id = board.getAttribute("id").split("-");
    //     let name = id[1]+" "+id[2];
    //     console.log(name)
    // }
    let data = await readConnectionsInformations();
    let elementList;
    for (let element in data) {
        elementList = element.replace(/\(|\)/, '');
        elementList = elementList.replace(/\(|\)/, '');
        elementList = elementList.split("|");

        let conn = connectionList.getConnection("100-101 " + elementList[0] + "-" + elementList[1]);
        if (conn == -1) {
            console.log("Die connection gibt es nicht!")
        } else {
            conn.delivered = parseInt(data[element][0]);
            conn.CRC_Error = parseInt(data[element][1]);
            conn.dropped = parseInt(data[element][2]);
            conn.wrongID = parseInt(data[element][3]);
            conn.print();
        }
    }
}

/* 4. Graph Functions */
//function for generating the graph
async function loadDiagram() {
    const cav = document.querySelector('#cv_graph').getContext('2d');
    let timesteps = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
    let data = {
        labels: timesteps,
        datasets: [{
            label: 'Voltage Neuron',
            data: [],
            fill: false,
            borderColor: 'rgb(20, 80, 230)',
            tension: 0,
        }]
    }
    voltageGraph = new Chart(cav, {
        type: 'line',
        data: data,
    });
}

//function for adding elements to the graph
function addDataToGraph(graph, item) {
    let data = graph.data.datasets[0].data;
    let label = graph.data.labels;
    if (data.length >= 20) {
        label.shift();
        data.shift();
        label.push(label[label.length - 1] + 1);
    }
    data.push(item);
    graph.update();
}

//function for adding random numbers to graph
function updateGraph() {
    let item = Math.floor(Math.random() * 9 + 1);

    addDataToGraph(voltageGraph, item);
}

/* 5. For html-display */
function updateProgressbar(progress) {
    let bar = document.querySelector(".progress-bar");

    // let computed = getComputedStyle(bar);
    // let value = parseFloat(computed.getPropertyValue("--width")) || 0;

    bar.setAttribute("data-label", progress + "%")
    bar.style.setProperty("--width", progress)
}

//toggle between Diagram and Console
function toggleConsole() {
    let diagram = document.querySelector("#cv_graph");
    let con = document.querySelector("#console_output");

    if (diagram.style.display == "block") {
        diagram.style.display = "none";
        con.style.display = "block";
    } else {
        diagram.style.display = "block";
        con.style.display = "none";
    }
}

/* 6. Functions for profiles */
function saveProfile() {
    console.log("Save Profile");
    let params = getNetworkSettings();
    delete params.Boards;

    // const fetchOption = {
    //     method: "POST",
    //     credentials: "same-origin",
    //     headers: {
    //         "X-CSRFToken": getCookie("csrftoken"),
    //         "Accept": "applications/json",
    //         "Content-Type": "application/json"
    //     },
    //     body: JSON.stringify(params),
    // }

    // fetch("/interface/saveParameters/", fetchOption)
    //     .then(res => {
    //         if (res.ok) {
    //             console.log(res);
    //         } else {
    //             console.log("Fail saving params");
    //         }
    //     })


}

function loadProfile() {
    console.log("Load Profile");
    // TODO
}

/* 7. Read in Networkinformations */
function isNumber(number) {
    var num = 0;
    if (typeof (number) === "string") {
        try {
            num = parseFloat()
        }
        catch (e) {
            return false;
        }
        return true;
    }
    else if (typeof (number) === "number") {
        return true;
    }
    else {
        return false;
    }
}

function getSelectedBoards() {
    let nodes = document.querySelectorAll("#matrix input[type=checkbox]:checked");
    let selectedBoards = [];
    for (let node of nodes) {
        let name = document.querySelector("#matrix label[for=" + node.getAttribute("id") + "]").innerHTML;
        selectedBoards.push(name);
    }

    return selectedBoards;
}

function getNetworkSettings() {
    let params = document.querySelectorAll("#parameters input[type=number]");
    var parameters = {};
    for (let values of params) {
        let name = values.id
        let param = values.value;
        if (!isNumber(param)) {
            return;
        }

        switch (name) {
            case "tau-ms":
                parameters.tau_ms = param;
                break;
            case "c-pf":
                parameters.c_pf = param;
                break;
            case "t-ref-ms":
                parameters.t_ref_ms = param;
                break;
            case "v-reset-mv":
                parameters.v_reset_mv = param;
                break;
            case "v-thresh-mv":
                parameters.v_thresh_mv = param;
                break;
            case "tau-ex-ms":
                parameters.tau_ex_ms = param;
                break;
            case "tau-in-ms":
                parameters.tau_in_ms = param;
                break;
            case "h-ms":
                parameters.h_ms = param;
                break;
            case "weight-frac-exc":
                parameters.weightFracExc = param;
                break;
            case "weight-frac-inh":
                parameters.weightFracInh = param;
                break;
            case "syncs-per-time-step":
                parameters.syncsPerTimeStep = param;
                break;
            case "timestep-limit":
                parameters.timestepLimit = param;
                break;
            case "number-neurons":
                parameters.numberNeurons = param;
                break;
            default:
                throw "Not a valid Parameter";
        }
    }
    parameters.Boards = getSelectedBoards();
    return parameters;
}

async function sendDataToBackend() {
    let parameters = getNetworkSettings();
    const fetchOption = {
        method: "POST",
        credentials: "same-origin",
        headers: {
            "X-CSRFToken": getCookie("csrftoken"),
            "Accept": "applications/json",
            "Content-Type": "application/json"
        },
        body: JSON.stringify(parameters),
    }

    return await fetch("/interface/network_settings/set/", fetchOption)
        .then(res => {
            if (res.ok) {
                console.log(res.status);
                console.log("Set Parameters");
                return res.json();
                // return true;
            } else if (res.status == 400) {
                // window.alert(res.text());
                //window.alert("corrupted request");
                return res.text();
            } else if (res.status === 405) {
                console.log("Wrong Method.");
                window.alert("Use POST-Request to pass the parameters.");
                return false;
            } else {
                console.log(res.status);
                console.log("Some deeper issues with the server.");
                return false;
            }
        })
        .then(res => {
            if (res.first_output == undefined) {
                window.alert(res);
                return false;
            } else {
                addElementToConsole(res.first_output);
                addElementToConsole(res.second_output);
                return true;
            }
        });
}

/* 8. Editor functions */
async function setCodeInEditor() {
    editor.setValue("");
    let fetchOption = {
        method: "GET",
        credentials: "same-origin",
        headers: {
            "Accept": "text/plain",
        },
    }

    let content = await fetch("nestcode/", fetchOption)
        .then(res => {
            if (res.ok) {
                return res.text();
            }
            else {
                return "";
            }
        })
    editor.replaceRange(content, { line: 0, ch: 0 });
}

async function initEditor() {
    let text = $("#codemirror-textarea")[0];
    editor = CodeMirror.fromTextArea(text, { lineNumbers: true, mode: "python", theme: "eclipse" });
    editor.setSize(null, "90%");

    setCodeInEditor();
}

function showEditor() {
    $("#editor").css("visibility", "visible");
}

async function sendCodeToBackend(content) {
    let fetchOption = {
        method: "POST",
        credentials: "same-origin",
        headers: {
            "X-CSRFToken": getCookie("csrftoken"),
            "Accept": "text/plain",
            "Content-Type": "text/plain"
        },
        body: content
    }

    fetch("setCode/", fetchOption)
}

function saveEditor() {
    $("#editor").css("visibility", "hidden");

    let code = editor.getValue();
    sendCodeToBackend(code);
}

function cancelEditor() {
    setCodeInEditor();
    $("#editor").css("visibility", "hidden");
}

/* 9. Perform Simulation */
async function initSimulation() {
    if (!validateNumber()) {
        return;
    }
    let startButton = document.querySelector("#start");
    startButton.disabled = true;
    let outputButton = document.querySelector("#output-window");
    // outputButton.disabled = true;


    startInterval();
    document.querySelector(".progress-bar").style.display = "inline";
    let result = await sendDataToBackend();
    if (result) {

        updateProgressbar(40);
        await startSimulation();
        await calculateMetrics();

        startButton.innerHTML = "Restart";
        startButton.addEventListener("click", restartSimulation);
        startButton.removeEventListener("click", initSimulation);


    } else {
        document.querySelector(".progress-bar").style.display = "none";
        for (let element of document.querySelectorAll("footer b")) {
            element.style.display = "none";
        }
    }
    updateProgressbar(100);
    stopInterval();
    startButton.disabled = false;
    // outputButton.disabled = false;
    console.log("End");
}

async function startSimulation() {
    let selectedBoards = { "Boards": getSelectedBoards() };
    let numTimeStep = document.querySelector("#timestep-limit").value;
    let numNeurons = document.querySelector("#number-neurons").value;
    selectedBoards.timeStep = numTimeStep;
    selectedBoards.numNeurons = numNeurons;

    const fetchOption = {
        method: "POST",
        credentials: "same-origin",
        headers: {
            "X-CSRFToken": getCookie("csrftoken"),
            "Accept": "text/plain",
            "Content-Type": "application/json"
        },
        body: JSON.stringify(selectedBoards),
    }

    await fetch("/interface/simulation/start/", fetchOption)
        .then(res => {
            if (res.ok) {
                updateProgressbar(80)
                return res.json();
            } else if (res.status === 400) {
                console.log("Bad Parameters");
                return false;
            } else if (res.status = 405) {
                console.log("Wrong request-method.");
                window.alert("Use POST-Request");
                return false;
            } else {
                console.log("Some deeper issues with the server.")
                return false;
            }
        }).then(res => {
            if (res.simulation_output == undefined) {
                window.alert("ERROR: URL is not given");
            } else {
                addElementToConsole(res.simulation_output);
                addElementToConsole(res.info_output);
                validateSimulationData(res.sim_info, res.comm_info, res.main_board_id);
                mainBoard = res.main_board;
            }
        })

}

async function restartSimulation() {
    updateProgressbar(0);
    let selectedBoards = { "mainBoard": mainBoard };
    let numTimeStep = document.querySelector("#timestep-limit").value;
    selectedBoards.timeStep = numTimeStep;

    let startButton = document.querySelector("#start");
    startButton.disabled = true;
    let outputButton = document.querySelector("#output-window");
    outputButton.disabled = true;


    const fetchOption = {
        method: "POST",
        credentials: "same-origin",
        headers: {
            "X-CSRFToken": getCookie("csrftoken"),
            "Accept": "text/plain",
            "Content-Type": "application/json"
        },
        body: JSON.stringify(selectedBoards),
    }

    document.querySelector("#time").innerHTML = "0:00";
    startInterval();

    await fetch("/interface/simulation/restart/", fetchOption)
        .then(res => {
            if (res.ok) {
                updateProgressbar(40)
                return res.json();
            } else if (res.status === 400) {
                console.log("Bad Parameters");
                return false;
            } else if (res.status = 405) {
                console.log("Wrong request-method.");
                window.alert("Use POST-Request");
                return false;
            } else {
                console.log("Some deeper issues with the server.")
                return false;
            }
        }).then(res => {
            if (res.simulation_output == undefined) {
                window.alert("ERROR: URL is not given");
            } else {
                addElementToConsole(res.simulation_output);
                addElementToConsole(res.info_output);
                validateSimulationData(res.sim_info, res.comm_info, res.main_board_id);
                calculateMetrics();
            }
        })
    updateProgressbar(100);
    startButton.disabled = false;
    outputButton.disabled = false;
    stopInterval();
}

async function calculateMetrics() {
    const fetchOption = {
        method: "POST",
        credentials: "same-origin",
        headers: {
            "X-CSRFToken": getCookie("csrftoken"),
            "Accept": "text/plain",
            "Content-Type": "text/plain"
        }
    };

    await fetch("/interface/metrics/calculate/", fetchOption)
        .then(res => {
            if (res.ok) {
                console.log("Calculate metrics");
            } else {
                console.log("Error by calculating metrics");
            }
        })
}

/* 10. Input Validation */
function validateNumber() {
    const integer = ["weight-frac-exc", "weight-frac-inh", "syncs-per-time-step", "timestep-limit", "number-neurons"];

    let inputList = document.querySelectorAll("#parameters input[type=number]")
    let valueError = false;
    for (let element of inputList) {
        if (integer.includes(element.id)) {
            if (isNaN(element.value) || !Number.isInteger(parseFloat(element.value))) {
                element.style.borderColor = "red";
                valueError = true;
            } else {
                element.style.borderColor = "black";
            }
        } else {
            if (isNaN(element.value) || element.value === "") {
                element.style.borderColor = "red";
                valueError = true;
            } else {
                element.style.borderColor = "black";
            }
        }
    }
    return !valueError;
}

/* 11. Console Output */
async function addElementToConsole(output) {
    let console = document.querySelector("#console_output p");
    console.innerHTML = console.innerHTML + output;
}

async function validateSimulationData(simInfo, commInfo, mainBoard) {
    let mainPosX = parseInt(mainBoard.split(" ")[0]);
    let mainPosY = parseInt(mainBoard.split(" ")[1]);

    console.log("main: " + mainPosX + " " + mainPosY)

    for (let key in commInfo) {
        let sourceNode = key.split(" ");
        let targetId = (parseInt(sourceNode[0]) + mainPosX) + "-" + (parseInt(sourceNode[1]) + mainPosY)
        for (let source in commInfo[key]) {
            let sourceNodes = source.split(" ")
            let nodeId = (parseInt(sourceNodes[0]) + mainPosX) + "-" + (parseInt(sourceNodes[1]) + mainPosY)
            console.log(source + " " + commInfo[key][source])
            let dataInfo = commInfo[key][source];
            let update = connectionNet.updateConnection(nodeId + " " + targetId, parseInt(dataInfo[0]), parseInt(dataInfo[1]), parseInt(dataInfo[2]), parseInt(dataInfo[3]), parseInt(simInfo["timesteps"]));
            console.log("Update: " + update);
        }
    }
}

//start an Interval for diagram
function timer() {
    let timeLabel = document.querySelector("#time");
    let time = timeLabel.innerHTML.split(":");
    let sec = parseInt(time[1]) + 1;
    let min = parseInt(time[0]);
    if (sec >= 60) {
        min = min + 1;
        sec = 0;
    }

    let formattedSeconds = sec.toLocaleString('en-US', {
        minimumIntegerDigits: 2,
        useGrouping: false
    })
    timeLabel.innerHTML = min + " : " + formattedSeconds;
}

function startInterval() {
    let elements = document.querySelectorAll("footer b");
    for (let element of elements) {
        element.style.display = "inline";
    }
    simulationInterval = setInterval(timer, 1000);
}

function stopInterval() {
    clearInterval(simulationInterval);
}

//to Output
function loadOutputWindow() {
    window.open(outputURL);
}

async function init() {
    initEditor();

    loadDiagram();
    document.querySelector("#errorInformations button").onclick = hideInformations;

    let info = await readClusterInformations();
    let proportion = info["proportion"].split(", ");
    let proportionList = new Array(parseInt(proportion[0]), parseInt(proportion[1]));
    let connectionList = info["relative connectionlist"].split(";");
    let torus = info["torus"]
    let fpgaNames = info["names"]
    outputURL = info["url"]

    let sizeRow = initClusterDiv(proportionList[0], proportionList[1], fpgaNames);
    initConnections(proportionList, connectionList, sizeRow, torus);
    // toggleConnectionColor([2, 2], [0, 1], 100);
    // updateConnections();
}

// start after loading the page
document.addEventListener("DOMContentLoaded", async function () {

    document.querySelector("#start").addEventListener("click", initSimulation);
    document.querySelector("#bt_console").addEventListener("click", toggleConsole);
    document.querySelector("#bt_save_profile").addEventListener("click", saveProfile);
    document.querySelector("#bt_load_profile").addEventListener("click", loadProfile);
    document.querySelector("#output-window").addEventListener("click", loadOutputWindow);
    $("#toggle-editor").on("click", showEditor);
    $("#save-editor").on("click", saveEditor);
    $("#cancel-editor").on("click", cancelEditor);
    init();
});

// XXX Not in use
function getSelectedClusterBoard() {
    let boards = document.querySelectorAll("#matrix > input");
    let ret = [];
    for (let board of boards) {
        if (board.checked === true) {
            ret.push(board.getAttribute("id"));
        }
    }
    return ret;
}