class CurvesSettingsPopup extends HTMLElement{

    constructor(applySettingsCallback){
        super();
        this.applySettingsCallback = applySettingsCallback;
    }

    initTable(){

        let userConfiguration = getUserConfiguration(); //located in SEAWebClientLocalStorage.js
        let tbody = this.querySelector("#curves-settings-popup-table tbody");
        tbody.innerHTML = "";

        for(let lineConfiguration of userConfiguration){ 
            this.createRow(tbody, lineConfiguration);
        }
        
        this.createRow(tbody); // we add another row by default at the end
    }

    doApplySettingsCallback(){
        
        try{
            let localStorageBuffer = [];
            let formattedUserConfiguration = this.getFormattedUserConfiguration(localStorageBuffer);

            localStorage.clear();
            saveUserConfiguration(localStorageBuffer); //located in SEAWebClientLocalStorage.js

            this.hide();
            this.applySettingsCallback(formattedUserConfiguration);
        }catch{}
       
    }

    /**
     * Feeds localStorageBuffer with user rows to save, while formatting each row for later API call
     * Throws an error if a row is invalid (no variable is given for a non empty line)
     * @param {[]} localStorageBuffer an array feeded by this method, that contains the JS object representing the data out of a line
     * @returns the formatted user configuration object to be passed as the payload to the server
     */
    getFormattedUserConfiguration(localStorageBuffer){
        let formatedUserConfiguration = {};

        let rows = this.querySelectorAll("tbody tr");
        for(let row of rows){
            
            let configurationLineObject = this.getRowValues(row);
            let formmatedLineConfiguration = {...configurationLineObject};

            if(!formmatedLineConfiguration.hasOwnProperty("variable")){
                let definedFields = Object.keys(formmatedLineConfiguration).length;
                if(formmatedLineConfiguration.hasOwnProperty("cat")){
                    if(formmatedLineConfiguration["cat"] === "*"){
                        if (definedFields >= 2){
                            alertify.error("Variable not defined for some row(s).");
                            throw Error;
                        }
                    }else{
                        alertify.error("Variable not defined for some row(s).");
                        throw Error;
                    }
                }else{
                    if (definedFields > 0){
                        alertify.error("Variable not defined for some row(s).");
                        throw Error;
                    }
                }
            }else{
                let key = formmatedLineConfiguration["variable"];
                delete formmatedLineConfiguration["variable"];
                if(formmatedLineConfiguration.hasOwnProperty("parameter")){
                    key +=  (formmatedLineConfiguration["parameter"] != "value") ? "." + formmatedLineConfiguration["parameter"] : "";
                    delete formmatedLineConfiguration["parameter"];
                }
                if(Object.keys(formmatedLineConfiguration).length > 0){
                    formatedUserConfiguration[key] = formmatedLineConfiguration;
                    localStorageBuffer.push(configurationLineObject);
                }                
            }
        }
        return formatedUserConfiguration;
    }

    /**
     * Gets the data out of the given HTML row as a JSON object
     * @param {*} row An HTML tr element of the table
     * @returns A JS object containing the data out of the HTML element : there is a key if the value is not an empty string
     */
    getRowValues(row){
        let configuration = {};

        for(let cell of row.children){
            let content = cell.children[0]; //there is only one child per cell
            if(content.nodeName == "DIV"){ //we skip the first cell which is the bin
                content = content.children[0];
                if(content.nodeName == "INPUT" && content.value !== ""){
                    configuration[content.name] = content.value;
                }
                else if (content.nodeName == "SEA-COLOR-SELECTOR" && content.getValue() !== ""){
                    configuration["color"] = content.getValue();
                }
            }
        }
        return configuration;
    }

    getUserConfiguration(){
        let userConfiguration = [];
        for(let i = 0; i < localStorage.length; i++){
            userConfiguration.push(JSON.parse(localStorage.getItem(localStorage.key(i))));
        }
        return userConfiguration;
    }

    saveUserConfiguration(userConfiguration){
        for(let i = 0; i < userConfiguration.length; i++){
            localStorage.setItem(i, JSON.stringify(userConfiguration[i]));
        }
    }

    addNewRowIfEmpty(){
        let tbody = this.querySelector("#curves-settings-popup-table tbody");
        if(tbody.childNodes.length == 0){
            this.createRow(tbody);
        }
    }

    addRow(){
        let tbody = this.querySelector("#curves-settings-popup-table tbody");
        this.createRow(tbody);
    }
    
    show(){
        this.style.visibility = "visible";
        this.initTable();
        window.addEventListener("click", this.backgroundClickCallback);
    }
    
    hide(){
        this.style.visibility = "hidden";
        window.removeEventListener("click", this.backgroundClickCallback);
    }
    
    backgroundClickCallback = ({target}) => {
        if(target.id == "curves-settings-popup"){
            this.doApplySettingsCallback();
        }
    }

    connectedCallback(){
        this.render();
        this.hide();    
        this.getElementsByTagName("img")[0].onclick = () => {this.doApplySettingsCallback();};
        this.getElementsByClassName("add-row-button")[0].onclick = () => {this.addRow();};
        this.getElementsByClassName("cancel-button")[0].onclick = () => {this.hide();};
        this.getElementsByClassName("apply-button")[0].onclick = () => {this.doApplySettingsCallback();};
    }

    // 
    /**
     * Adds a row to tbody
     * The process is disigned in this way because seaColorSelector.setValue is called, and its content has to be
     * generated before calling this method, that is why we need to append the newly created HTML element
     * as soon as possible.
     * If lineConfiguration == null, an empty row is added to the table
     * @param {*} tbody - The HTML element of the table body
     * @param {*} lineConfiguration - The object representing one line of configuration on the client side
     * @returns 
     */
    createRow(tbody, lineConfiguration = null){
        
        let row = document.createElement("tr");
        tbody.appendChild(row)
        let binCell = document.createElement("td");

        let binImg = document.createElement("img");
        binImg.src = "res/bin.png";
        binImg.onclick = () => {
            binImg.parentNode.parentNode.remove();
            this.addNewRowIfEmpty();
        }
        binCell.appendChild(binImg);
        row.append(binCell)

        this.createTextInput(row, lineConfiguration, "variable")

        this.createTextInput(row, lineConfiguration, "parameter")      

        this.createTextInput(row, lineConfiguration, "cat")

        let colorCell = document.createElement("td");
        let colorDiv = document.createElement("div");
        let seaColorSelector = new ColorSelector();
        row.append(colorCell);
        colorCell.append(colorDiv);
        colorDiv.appendChild(seaColorSelector); //need to first append it before calling setValue
        seaColorSelector.setValue("");
        if(lineConfiguration != null && lineConfiguration.hasOwnProperty('color')){
            seaColorSelector.setValue(lineConfiguration['color']);
        }

        this.createTextInput(row, lineConfiguration, "unit")

        return row;
    }

    createTextInput(row, lineConfiguration, type){
        let cell = document.createElement("td");
        let div = document.createElement("div");
        let input = document.createElement("input");
        input.type = "text";
        input.spellcheck = false
        input.autocorrect = "off"
        input.name = type;
        input.classList.add("text-input");
        input.value = "";
        if (type == "cat"){
            input.value = "*";
        }
        if(lineConfiguration != null && lineConfiguration.hasOwnProperty(type)){
            input.value = lineConfiguration[type];
        }
        div.appendChild(input)
        cell.appendChild(div);
        row.append(cell)
    }

    render(){
        this.innerHTML = `
        <link rel="stylesheet" href="components/curves_settings_popup/curves_settings_popup.css"/>
        <div id="curves-settings-popup">
            <div id="curves-settings-popup-container">
                
                <div id="curves-settings-popup-header">
                    <span>Curves settings</span>
                    <img src="res/close.png"/>
                </div>

                <div id="curves-settings-popup-content">

                    <div class="scrollable-content">
                        <table id="curves-settings-popup-table">
                            <thead style="position: sticky;">
                                <tr>
                                    <th class="bin-cell"></th>
                                    <th class="variable-cell">Variable</th>
                                    <th class="parameter-cell">Parameter</th>
                                    <th class="cat-cell">Category</th>
                                    <th class="color-cell">Color</th>
                                    <th class="unit-cell">Unit</th>
                                </tr>
                            </thead>
                            <tbody>
                            </tbody>
                        </table>
                        <div class="buttons-wrapper">
                            <button class="add-row-button">Add line</button>
                            <button class="apply-button">Apply</button> 
                            <button class="cancel-button">Cancel</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        `;
    }
}

customElements.define("sea-curves-settings-popup", CurvesSettingsPopup);