var port, textEncoder, writableStreamClosed, writer, historyIndex = -1;
const lineHistory = [];
maintenanceRun = 0;

function progressBar(percentage, message, color){
    var readbar = document.getElementById("readBar");
    readBar.style.background = color;
    readBar.style.width = percentage +"%";
    readBar.innerHTML = message;
}

async function connectSerial() {
    try {
        // Prompt user to select any serial port.
        const filters = [{ usbVendorId: 1027, usbProductId: 24597 }];
        port = await navigator.serial.requestPort({ filters });
        await port.open({ baudRate: 56700 });

        listenToPort();

        textEncoder = new TextEncoderStream();
        writableStreamClosed = textEncoder.readable.pipeTo(port.writable);

        writer = textEncoder.writable.getWriter();
    } catch {
        alert("Serial Connection Failed");
    }
}


async function sendSerialLine() {
    dataToSend = document.getElementById("lineToSend").value;
    lineHistory.unshift(dataToSend);
    historyIndex = -1; // No history entry selected
    dataToSend = dataToSend + "\r"; //enter
    dataToSend = dataToSend + "\n"; //new line
    appendToTerminal("> " + dataToSend); //send echo
    await writer.write(dataToSend);
    document.getElementById("lineToSend").value = "";
    //await writer.releaseLock();
}

async function startMaintenance(){
//Get Select Product
var product = document.getElementById("productlist");
var productSelected = product.options[product.selectedIndex].value; // get selected value
var getProductNumber = productSelected.split("|"); //Selected product contains productcode + product category
value = getProductNumber[0]; //get productcode
value_pt = getProductNumber[1]; // get PT code


if (value != 0){
    connectSerial();
    maintenanceRun = 1;
    progressBar("10", "Connecting", "#04AA6D");
}
else{
    progressBar("100", "Not ready - Please select product from dropdown", "#D96F58");
}
}

function maintenanceTest() {
    
    switch (maintenanceRun) {
        case 2: // SET PN
            progressBar("60", "Writing device, do not disconnect" , "#ff6666");
            var command = "setpn ";
            var createPN = value.padStart(12, "0");
            var payload = createPN.substring(0,4)+" "+createPN.substring(4,8)+" "+createPN.substring(8,12) ;
            pn = createPN.substring(0,4)+"-"+createPN.substring(4,8)+"-"+createPN.substring(8,12);
            writeToStream(command, payload);
            break;
    
        case 3: // SET PD
            progressBar("65", "Writing device, do not disconnect" , "#ff6666");
            var command3 = "setpd ";
            var payload3 = new Date().toLocaleDateString('sv').replaceAll('-', '');
            setTimeout(function() {writeToStream(command3, payload3);}, 3000);
            break;

        case 4: // SET PT
            progressBar("68", "Writing device, do not disconnect" , "#ff6666");
            var command3a = "setpt ";
            var payload3a = value_pt.padStart(2,"0");
            setTimeout(function() {writeToStream(command3a, payload3a);}, 3000);
            break;
        
        case 5: // RESET
            progressBar("70", "Reseting device, do not disconnect" , "#ff6666");
            serialResultsDiv.innerHTML ="";
            var command4 = "reset";
            var payload4 = "";
            setTimeout(function() {writeToStream(command4, payload4);}, 3000);
            break;
        
        case 6: //Clear cache after reset
            progressBar("75", "Reading, do not disconnect" , "#ff6666");
            maintenanceRun++;
            console.log(maintenanceRun);   
            setTimeout(maintenanceTest,8000);
            break;
        
        case 7: // Check PN correct                 
            progressBar("80", "Checking device after reset" , "#FBB404");
            data_after_reset = serialResultsDiv.innerHTML;
            console.log(data_after_reset);
            x1a = Array.from(new Set(data_after_reset.split(";"))).toString();
            var search_new_device_PN = "PN="+pn;

            if (x1a.indexOf(search_new_device_PN) > 0){
                    console.log("PN correct");
                    maintenanceRun++;
                    maintenanceTest();
            }
            else
            {
                progressBar("100", "Error: product not correctly written" , "#ff6666");
                console.log("PN not correct");
                maintenanceRun = 999;
                closePort();
            }
            break;   
        
        case 8: // Check PRD correct                 
            progressBar("82", "Checking device after reset" , "#FBB404");
            var search_new_device_PRD = "PRDDATE="+new Date().toLocaleDateString('sv');
            if (x1a.indexOf(search_new_device_PRD) > 0){
                    console.log("PRD correct");
                    maintenanceRun++;
                    maintenanceTest();
            }
            else
            {
                progressBar("100", "Error: production date not correctly written" , "#ff6666");
                console.log("PRDDATE not correct");
                maintenanceRun = 999;
                closePort();
            }
            break;   
        
        case 9: // Check PT correct                 
            progressBar("83", "Checking device after reset" , "#FBB404");
            var plugtype = value_pt.padStart(2,"0");
            var search_new_device_PT= "PLUGTYPE="+plugtype;
            if (x1a.indexOf(search_new_device_PT) > 0){
                    console.log("PT correct");
                    maintenanceRun++;
                    maintenanceTest();
            }
            else
            {
                progressBar("100", "Error: production date not correctly written" , "#ff6666");
                console.log("PlugTYPE not correct");
                maintenanceRun = 999;
                closePort();
            }
            break;      

        case 10: //Update equipmenthistory
                progressBar("90", "Updating equipment history" , "#FBB404");
                updateHistory();
                maintenanceRun++;
            break;
        
        case 11: //Printlabel
                progressBar("92", "Printing Label" , "#FBB404");
                printLabel();
                maintenanceRun++;
                setTimeout(maintenanceTest,3000);
                
        break;

        case 12: // ClosePort
                //last element to write completed then closePort and reset maintenanceRun.
        
                if (x1a.indexOf("STATE=SLEEP") > 0 )// change Maintenance to SLEEP
                {
                    progressBar("95", "Finalizing - do not disconnect", "#FBB404")
                    maintenanceRun = 0;
                    setTimeout(closePort,3000);
                }
                else{
                    progressBar("100", "Error: device not in sleep mode" , "#ff6666");
                    maintenanceRun = 999;
                    closePort();
                }
            break;
        
    }   
    }

function writeToStream(command, payload){
    limiter = "\r\n";
    dataToSend = command + payload + limiter;
    console.log(dataToSend);
    writer.write(dataToSend);
    maintenanceRun++;
    console.log(maintenanceRun);
    maintenanceTest();
}

async function listenToPort() {
    const textDecoder = new TextDecoderStream();
    readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
    reader = textDecoder.readable.getReader();
    progressBar("35", "Reading device", "#04AA6D")
    while (true) {
        const { value, done } = await reader.read();
        if (done) {
            break;
        }
        appendToTerminal(value);

        var item = serialResultsDiv.innerHTML;
        x = Array.from(new Set(item.split(";"))).toString();

        if (maintenanceRun != 0){
            if (x.indexOf("STATE=MAINTENANCE") > 0 && maintenanceRun == 1)
                {
                    progressBar("50", "Initializing program" , "#ff6666")
                    setTimeout(maintenanceTest,3000);
                    maintenanceRun = 2;
                }
        }
    }
}

const serialResultsDiv = document.getElementById("serialResults");
const plug_data = document.getElementById("plug_data");

async function appendToTerminal(newStuff) {
    serialResultsDiv.innerHTML += newStuff;
    
    const keyword = '$STATUS;STATE';
    const keyword2 = 'PWM';
    
    // To read and clean device data
    VCP = []; //for VCP values
    VPP1 = []; //for VPP1 values
    VPP2 = []; //for VPP2 values
    VBAT = []; //for VBAT values
    PWM = []; //for PWM values
    STATE = []; //for STATE values
    xChart = []; //x-axis chart values

    // Input string with multiple status reports
    const statusString = serialResultsDiv.innerHTML;
    let lineCounter = 0; 

    // Split the input by newline to get each status report
    let statusLines = statusString.split(/\r?\n/);

    // Process each status line and populate the parameter arrays and counters
    statusLines.forEach((line) => {

        if (line.includes(keyword) && line.includes(keyword2) && /\d$/.test(line.trim())) {
  
        const pairs = line.split(';');  // Split by ';'
        
        // Loop through each pair and split by '='
            pairs.forEach(pair => {
                const [key, value] = pair.split('=');
                if (key && value !== undefined && key !== "$STATUS") {  // Skip '$STATUS'
                    // Push the value and counter to the corresponding parameter object
                    if (key === "STATE") {
                        let state
                        switch (value) {
                            case 'FULL_CONNECT':
                                state = 5;
                                break;
                            case 'REACTIVATE':
                                state =  3;
                                break;
                            case 'WAIT_CONNECT':
                                state =  -5;
                                break;
                            case 'DISCONNECTED':
                                state =  0;
                                break;
                            default:
                                state = 0;
                                break;
                        }
                        STATE.push(state);
                    } else if (key === "VCP") {
                        VCP.push(value / 1000000);
                    } else if (key === "VPP1") {
                        VPP1.push(value / 1000000);
                    } else if (key === "VPP2") {
                        VPP2.push(value / 1000000);
                    } else if (key === "VBAT") {
                        VBAT.push(value / 1000000);
                    } else if (key === "PWM") {
                        PWM.push(value /10);
                    }
                }
            
            });
        xChart.push(lineCounter);
        lineCounter = lineCounter + 1;
        }
    });

    //vcp_data.value +=newStuff
    if (typeof plug_data !== "undefined"){    
        var plugdata = {"VCP":{VCP}, "VPP1":{VPP1},"VPP2":{VPP2},"VBAT":{VBAT}, "PWM":{PWM},"STATE":{STATE}, "xChart":{xChart}}
        plug_data.value = JSON.stringify(plugdata);
    }

    //serialOutput +=newStuff;
  
}

function renderChart(){
        new Chart("chart_VCP", {
        type: "line",
        data: {
            labels: xChart,
            datasets: [{ 
            label: "VCP",
            data: VCP,
            borderColor: "red",
            fill: false
            },
            { 
                label: "VBAT",
                data: VBAT,
                borderColor: "black",
                fill: false
            },{ 
                label: "VPP1",
                data: VPP1,
                borderColor: "green",
                fill: false
            },{ 
                label: "VPP2",
                data: VPP2,
                borderColor: "blue",
                fill: false
            },{
                label: "PWM",
                data: PWM,
                backgroundColor: "yellow",
                fill: false
            },{
                label: "STATE",
                data: STATE,
                backgroundColor: "purple",
                fill: false
            }
        ]
        },
        options: {
            legend: {display: true}
        }
        });
}

//Get the RAW data and turn into object
function getData() { 
    const keyword = '$STATUS;STATE';
    const keyword2 = 'PWM';
    
    // To read and clean device data
    const VCP = []; //for VCP values
    const VPP1 = []; //for VPP1 values
    const VPP2 = []; //for VPP2 values
    const VBAT = []; //for VBAT values
    const PWM = []; //for PWM values
    const STATE = []; //for STATE values
    const xChart = []; //x-axis chart values

    // Input string with multiple status reports
    const statusString = serialResultsDiv.innerHTML;
    let lineCounter = 0; 

    // Split the input by newline to get each status report
    let statusLines = statusString.split(/\r?\n/);

    // Process each status line and populate the parameter arrays and counters
    statusLines.forEach((line) => {

        if (line.includes(keyword) && line.includes(keyword2) && /\d$/.test(line.trim())) {
  
        const pairs = line.split(';');  // Split by ';'
        
        // Loop through each pair and split by '='
            pairs.forEach(pair => {
                const [key, value] = pair.split('=');
                if (key && value !== undefined && key !== "$STATUS") {  // Skip '$STATUS'
                    // Push the value and counter to the corresponding parameter object
                    if (key === "STATE") {
                        let state
                        switch (value) {
                            case 'FULL_CONNECT':
                                state = 5;
                                break;
                            case 'REACTIVATE':
                                state =  3;
                                break;
                            case 'WAIT_CONNECT':
                                state =  -5;
                                break;
                            case 'DISCONNECTED':
                                state =  0;
                                break;
                            default:
                                state = 0;
                                break;
                        }
                        STATE.push(state);
                    } else if (key === "VCP") {
                        VCP.push(value / 1000000);
                    } else if (key === "VPP1") {
                        VPP1.push(value / 1000000);
                    } else if (key === "VPP2") {
                        VPP2.push(value / 1000000);
                    } else if (key === "VBAT") {
                        VBAT.push(value / 1000000);
                    } else if (key === "PWM") {
                        PWM.push(value /10);
                    }
                }
            
            });
        xChart.push(lineCounter);
        lineCounter = lineCounter + 1;
        }
    });
}

async function closePort(){
        
        reader.cancel();
        await readableStreamClosed.catch(() => { /* Ignore the error */ });
        writer.close();
        await writableStreamClosed 
        console.log(maintenanceRun);
        await port.close();

        //Check for errors maintenanceRun = 999
        if (maintenanceRun != 999){
            serialResultsDiv.innerHTML = '';
            
            if (maintenanceRun !=0){
                if (value != 33){//Include the correct ROWID of the Productrecord
                    progressBar("100", "Ready", "#04AA6D");
                    }
                else{
                    progressBar("100", "Ready => Warning: Product requires TESLA adapter", "#ff6666");
                    }
            
            }
            else {
                progressBar("100", "Ready", "#04AA6D");
            }
        }

        maintenanceRun = 0; // reset maintenanceRun
        // Refresh the page
        window.location.reload();
}

async function closePortCarTest(){
        
    reader.cancel();
    await readableStreamClosed.catch(() => { /* Ignore the error */ });
    writer.close();
    await writableStreamClosed 
    console.log(maintenanceRun);
    await port.close();

    //Check for errors maintenanceRun = 999
    if (maintenanceRun != 999){
        serialResultsDiv.innerHTML = '';
        
        if (maintenanceRun !=0){
            if (value != 33){//Include the correct ROWID of the Productrecord
                progressBar("100", "Ready", "#04AA6D");
                }
            else{
                progressBar("100", "Ready => Warning: Product requires TESLA adapter", "#ff6666");
                }
        
        }
        else {
            progressBar("100", "Ready", "#04AA6D");
        }
    }

    maintenanceRun = 0; // reset maintenanceRun

}

async function updateHistory(){

    var data = document.getElementById("servicetoken").innerHTML; //get ServiceID
    var item1 = serialResultsDiv.innerHTML;
    x1 = Array.from(new Set(item1.split(";"))).toString();

    if (x1.indexOf("PN=") > 0){
        var a = x1.indexOf("PN=");
        var b = a + 3;
        var c = b + 14;
        pn = x1.substring(b,c);
    }

    if (x1.indexOf("SN=") > 0){
        var a = x1.indexOf("SN=");
        var b = a + 3;
        var c = b + 8;
        serial = x1.substring(b,c);
    }

    if (x1.indexOf("HW=") > 0){
        var a = x1.indexOf("HW=");
        var b = a + 3;
        var c = b + 8;
        hw = x1.substring(b,c);
    }

    if (x1.indexOf("FW=") > 0){
        var a = x1.indexOf("FW=");
        var b = a + 3;
        var c = b + 8;
        fw = x1.substring(b,c);
    }

    if (x1.indexOf("PRDDATE=") > 0){
        var a = x1.indexOf("PRDDATE=");
        var b = a + 8;
        var c = b + 10;
        prddate = x1.substring(b,c);
    }

    if (x1.indexOf("FWDATE=") > 0){
        var a = x1.indexOf("FWDATE=");
        var b = a + 7;
        var c = b + 10;
        fwdate = x1.substring(b,c);
    }
    
    var logDetails = {
        "ESM": 000,
        "SN": serial,
        "PN": pn,
        "HW": hw,
        "FW": fw,
        "HEX_BL": "",
        "PRD_BL_DATE": "",
        "HEX_FW": "",
        "PRD_FW_DATE": "",
        "PRDDATE": prddate,
        "FWDATE": fwdate,
        "PRD_DEVID_DATE": "",
        "PRD_PCBA_TEST_DATE": "",
        "PRD_ASSY_TEST_DATE": ""
    };

    var mainObject = {
        "sn": serial,
        "type": "7",
        "testdetails":
        {
            "historycreated" : new Date(),
            "external_device_sn": "Portal" ,
            "logdetails": logDetails,
            "historytype":7,
            "historylocation":2,
            "doubletestvalues":[] ,
            "stringtestvalues": [] ,
            "booleantestvalues": [],
        }
    };

    var testdetails = JSON.stringify(mainObject);

    var serialnumber = serial;
    var action = '/v0/application/createHistory';
    var url = link+action;
    
    var bearer = 'Bearer ' + data;
    
    const response = await fetch(url, {
            method: 'POST',
            withCredentials: true,
            credentials: 'include',
            headers: {
                'Authorization': bearer,
                'Content-Type': 'application/json'
            },
            body: testdetails
        });
        
        const historyresult = await response.json;
    
    setTimeout(maintenanceTest,5000);
    
    }

    function printLabel(){
    var BestandTePrinten = "./assets/ep2.label";
    var labelXml;
    
    try
        {
            // open label
            $.get(BestandTePrinten, function(labelXml){

                var label = dymo.label.framework.openLabelXml(labelXml);

                    //Get Select Product
                var product = document.getElementById("productlist");
                var productSelected = product.options[product.selectedIndex].innerHTML; // get selected value
                var getProductNumber = productSelected.split(" - "); //Selected product contains productcode + product category

                //Get Serial Number
                if (x1.indexOf("SN=") > 0){
                    var a = x1.indexOf("SN=");
                    var b = a + 3;
                    var c = b + 8;
                    serial = x1.substring(b,c);
                }

                var serialnumber = serial;
                var productcode = getProductNumber[0];

                console.log(serialnumber);
                console.log(productcode);

                label.setObjectText("STREEPJESCODE", serialnumber);
                label.setObjectText("ProductCode", productcode);

                // select printer to print on
                // for simplicity sake just use the first LabelWriter printer
                var printers = dymo.label.framework.getPrinters();
                if (printers.length == 0)
                    throw "No DYMO printers are installed. Install DYMO printers.";

                var printerName = "";
                for (var i = 0; i < printers.length; ++i)
                {
                    var printer = printers[i];
                    if (printer.printerType == "LabelWriterPrinter")
                    {
                        printerName = printer.name;
                        break;
                    }
                }

                if (printerName == "")
                    throw "No LabelWriter printers found. Install LabelWriter printer";

                // finally print the label
                label.print(printerName);

                // and print label again
                label.print(printerName);
            });
        }
            catch(e)
        {
            alert(e.message || e);
    }
}
