// This script will be run within the webview itself
// It cannot access the main VS Code APIs directly.
(function () {
    const vscode = acquireVsCodeApi();


    for (const element of document.querySelectorAll(".pane-view .pane")) {
        addCollapseBehaviour(element);
    }

    console.log("Started");
    /**
     * @type {HTMLSelectElement}
     */
    const toolDropDown = document.getElementById("tools");
    toolDropDown.addEventListener('change', event => {
        var oldState = vscode.getState();
        var currentTool = toolDropDown.options[toolDropDown.selectedIndex].value;
        vscode.setState({ tools: oldState.tools, documentVars: oldState.documentVars, parameters: oldState.parameters, currentUri: oldState.currentUri, currentTool: currentTool });
        vscode.postMessage({ type: "toolSelected", toolName: currentTool });
    });

    // Handle messages sent from the extension to the webview
    window.addEventListener('message', event => {
        const message = event.data; // The json data that the extension sent
        console.log("Received message");
        switch (message.type) {
            case 'updateDocumentVars':
                {
                    updateDocumentVars(message.documentVars, message.uri);
                    break;
                }
            case 'updateParameters':
                {
                    updateParameters(message.parameters, message.toolName);
                    break;
                }
            case 'fillTools':
                {
                    fillTools(message.tools);
                    break;
                }
        }
    });

    const runButton = document.getElementById("run-button");
    runButton.addEventListener("click", event => {
        const state = vscode.getState();
        for (const file of state.documentVars) {
            if (file.uri === state.currentUri) {
                for (const tool of state.parameters) {
                    if (tool.toolName === state.currentTool) {
                        vscode.postMessage({ type: "runTool", uri: state.currentUri, toolName: toolDropDown.options[toolDropDown.selectedIndex].value, constants: file.constants, parameters: tool.parameters });
                        return;
                    }
                }
            }
        }
    });

    /**
     *
     * @param {HTMLElement} element
     */
    function addCollapseBehaviour(element) {
        const header = element.querySelector(".pane-header");
        const headerIcon = header.querySelector(".codicon");
        const body = element.querySelector(".pane-body");
        header.addEventListener("click", event => {
            if (body.classList.contains("hidden")) {
                body.classList.remove("hidden");
                headerIcon.classList.remove("codicon-chevron-right");
                headerIcon.classList.add("codicon-chevron-down");
            } else {
                body.classList.add("hidden");
                headerIcon.classList.remove("codicon-chevron-down");
                headerIcon.classList.add("codicon-chevron-right");
            }
        });
    }


    function fillTools(tools) {
        const select = document.querySelector("#tools");
        select.innerHTML = "";

        for (const tool of tools) {
            const option = document.createElement("option");
            option.value = tool;
            option.text = tool;
            select.appendChild(option);
        }

        const oldState = vscode.getState();
        select.selectedIndex = tools.findIndex(x => x === oldState.currentTool);

        vscode.postMessage({ type: "toolSelected", toolName: oldState.currentTool });

        vscode.setState({ tools: tools, documentVars: oldState.documentVars, parameters: oldState.parameters, currentUri: oldState.currentUri, currentTool: oldState.currentTool });
    }

    function addConstantItem(ul, name, value) {
        const li = document.createElement("li");

        const nameBox = document.createElement("label");
        nameBox.id = "name-" + name;
        nameBox.appendChild(document.createTextNode(name));
        nameBox.classList.add("name");

        li.appendChild(nameBox);

        const valueBox = document.createElement("input");
        valueBox.id = "value-" + name;
        valueBox.type = "text";
        valueBox.value = value;
        valueBox.classList.add("value");
        valueBox.addEventListener("input", event => {
            let oldState = vscode.getState();
            for (const file of oldState.documentVars) {
                if (file.uri === oldState.currentUri) {
                    for (const constant of file.constants) {
                        if (constant.name === name) {
                            constant.value = valueBox.value;
                            break;
                        }
                    }
                    break;
                }
            }
            vscode.setState({ tools: oldState.tools, documentVars: oldState.documentVars, parameters: oldState.parameters, currentUri: oldState.currentUri, currentTool: oldState.currentTool });
        });

        li.appendChild(valueBox);

        ul.appendChild(li);
    }

    function addParameterItem(ul, name, value) {
        const li = document.createElement("li");

        const nameBox = document.createElement("label");
        nameBox.id = "name-" + name;
        nameBox.appendChild(document.createTextNode(name));
        nameBox.classList.add("name");

        li.appendChild(nameBox);

        const valueBox = document.createElement("input");
        valueBox.id = "value-" + name;
        valueBox.type = "text";
        valueBox.value = value;
        valueBox.classList.add("value");
        valueBox.addEventListener("input", event => {
            let oldState = vscode.getState();
            for (const tool of oldState.parameters) {
                if (tool.toolName === oldState.currentTool) {
                    for (const parameter of tool.parameters) {
                        if (parameter.id === name) {
                            parameter.value = valueBox.value;
                            break;
                        }
                    }
                    break;
                }
            }
            vscode.setState({ tools: oldState.tools, documentVars: oldState.documentVars, parameters: oldState.parameters, currentUri: oldState.currentUri, currentTool: oldState.currentTool });
        });

        li.appendChild(valueBox);

        ul.appendChild(li);
    }

    /**
     *
     * @param {Array<{ uri: string, constants: Array<{ name: string, value: string }>, distributions: Array<{ name: string, value: string }> }>} documentVars
     * @param {string} uri
     */
    function updateDocumentVars(documentVars, uri) {
        const constantsUl = document.querySelector("#constants");
        const oldState = vscode.getState();

        // combines the oldstate constants with the "new" constants.
        for (const file of documentVars) {
            const index = oldState.documentVars.findIndex(x => x.uri === file.uri);
            if (index !== -1) {
                for (const constant of file.constants) {
                    const oldConstantIndex = oldState.documentVars[index].constants.findIndex(x => x.name === constant.name);
                    if (oldConstantIndex !== -1) {
                        constant.value = oldState.documentVars[index].constants[oldConstantIndex].value;
                    }
                }
            }
        }

        for (const file of oldState.documentVars) {
            const index = documentVars.findIndex(x => x.uri === file.uri);
            if (index === -1) {
                documentVars.push(file);
            }
        }

        constantsUl.innerHTML = "";
        // adds the constants to the sidebar.
        for (const file of documentVars) {
            if (file.uri === uri) {
                for (const constant of file.constants) {
                    addConstantItem(constantsUl, constant.name, constant.value);
                }
                break;
            }
        }

        if (constantsUl.innerHTML === "") {
            constantsUl.innerHTML = "There are no undefined constants.";
        }

        vscode.setState({ tools: oldState.tools, documentVars: documentVars, parameters: oldState.parameters, currentUri: uri, currentTool: oldState.currentTool });
    }

    /**
     * @param {Array<{ toolName: string, parameters: Array<{ id: string, value: string }> }>} parameters
     * @param {string} tool
     */
    function updateParameters(parameters, toolName) {
        const parametersUl = document.querySelector("#parameters");
        const oldState = vscode.getState();

        // combines the oldstate parameters with the "new" parameters.
        for (const tool of parameters) {
            const index = oldState.parameters.findIndex(x => x.toolName === tool.toolName);
            if (index !== -1) {
                for (const parameter of tool.parameters) {
                    const oldParameterIndex = oldState.parameters[index].parameters.findIndex(x => x.id === parameter.id);
                    if (oldParameterIndex !== -1) {
                        parameter.value = oldState.parameters[index].parameters[oldParameterIndex].value;
                    }
                }
            }
        }

        for (const tool of oldState.parameters) {
            const index = parameters.findIndex(x => x.toolName === tool.toolName);
            if (index === -1) {
                parameters.push(tool);
            }
        }

        parametersUl.innerHTML = parameters.length === 0 ? "There are no parameters." : "";
        // adds the parameters to the sidebar.
        for (const tool of parameters) {
            if (tool.toolName === toolName) {
                for (const parameter of tool.parameters) {
                    addParameterItem(parametersUl, parameter.id, parameter.value);
                }
                break;
            }
        }

        vscode.setState({ tools: oldState.tools, documentVars: oldState.documentVars, parameters: parameters, currentUri: oldState.currentUri, currentTool: oldState.currentTool });
    }

    const oldState = vscode.getState() || { tools: [], documentVars: [], parameters: [], currentUri: "", currentTool: "" };

    const tools = oldState.tools;
    const documentVars = oldState.documentVars;
    const parameters = oldState.parameters;
    const currentUri = oldState.currentUri;
    const currentTool = oldState.currentTool;

    if (oldState.tools.length === 0) {
        vscode.postMessage({ type: "init" });
    } else {
        fillTools(tools);
        updateParameters(parameters, currentTool);
        updateDocumentVars(documentVars, currentUri);
    }
}());