var defaultStrings = [];
const color_grey = "#6b6b6b";
const color_red = "#ff8f8f";

/**
* It clears default content of the element and sets it's color to black.
* 
* @function
* @name clearDefaultContent
* @kind function
* @param {any} element to set
* @param {any} text to set
* @returns {void}
*/
function clearDefaultContent(element, text) {
    if (element.innerText == text) {
        element.innerText = "";
        element.style.color = "#000000";
        element.style.backgroundColor = "#ffffff";
    }
}

/**
* It returns the value of the element with id "processors".
* 
* @function
* @name getProcessor
* @kind function
* @returns {any}
*/
function getProcessor() {
    return document.getElementById("processors").value;
}


/**
 * It returns the value of the element with id "versions".
 * 
 * @function
 * @name getVersion
 * @kind function
 * @returns {any}
 */
function getVersion() {
    return document.getElementById("versions").value;
}

/**
* It clears all data fields.
* 
* @function
* @name clearDataField
* @kind function
*/
function clearDataField() {
    document.getElementById("xmlArea").innerHTML = "";
    document.getElementById("xmlArea").style.color = null;
    document.getElementById("xmlArea").style.backgroundColor = null;
    
    document.getElementById("transformArea").innerHTML = "";
    document.getElementById("transformArea").style.color = null;
    document.getElementById("transformArea").style.backgroundColor = null;

    document.getElementById("resultArea").innerHTML = "";
}


/**
* It fills the XML area with a sample XML.
* 
* @function
* @name fillDefaultXML
* @kind function
* @param {any} element
* @returns {void}
*/
function fillDefaultXML(element) {
    if (element.classList.contains("active")) {
        const serverAddress = window.location.protocol + "//" + window.location.hostname + ":8086";
        clearDefaultContent(document.getElementById("xmlArea"), "Insert XML here");
        fetch(serverAddress + "/assets/samples/sampleXml.xml")
        .then(response => response.text())
        .then((exampleData) => {
            document.getElementById("xmlArea").innerText = exampleData;
            highlightSyntax("xmlArea");
            document.getElementById("xmlArea").style.backgroundColor = null;
            
        })
    }
}


/**
* It fills the XSD area with a sample XSD and XML area with matching XML.
* 
* @function
* @name fillDefaultXSD
* @kind function
* @param {any} element
* @returns {void}
*/
function fillDefaultXSD(){
    const serverAddress = window.location.protocol + "//" + window.location.hostname + ":8086";
    fetch(serverAddress + "/assets/samples/sampleXSD.xsd")
        .then( response => response.text() )
        .then( (XSDSchema) => {
            document.getElementById('transformArea').innerText = XSDSchema;
            highlightSyntax("transformArea");
        } )
    fetch(serverAddress + "/assets/samples/sampleXMLForXSD.xml")
        .then( response => response.text() )
        .then( (XMLSample) => {
            document.getElementById('xmlArea').innerText = XMLSample;
            highlightSyntax("xmlArea");
        } )
    
}


/**
 * The `fillDefaultXSLT()` function fetches a default XSLT template from the server and sets the value of the element with id "transformArea" to the fetched template.
 * 
 * @function
 * @name fillDefaultXSLT
 * @kind function
 * @returns {void}
 */
function fillDefaultXSLT() {
    const serverAddress = window.location.protocol + "//" + window.location.hostname + ":8086";
    fetch(serverAddress + "/assets/samples/XSLTTemplate.xslt")
        .then( response => response.text() )
        .then( (XSTLTemplate) => {
            document.getElementById('transformArea').innerText = XSTLTemplate;
            highlightSyntax("transformArea");
        } )   
}

/**
* It sets default content for the element an changes it's color to grey
* 
* @function
* @name setDefaultContent
* @kind function
* @param {any} element to set
* @param {any} text to set
*/
function setDefaultContent(element, text) {
    if (element.value == "") {
        var id = element.getAttribute('id');
        if (!defaultStrings.includes(text)) {
            defaultStrings.push(text);
        }
        if (id == "xmlArea") {
            element.style.color = color_grey;
            element.value = text;
        }
        if (id == "transformArea") {
            element.style.color = color_grey;
            element.value = text;
        }
        if (id == "jsonArea") {
            element.style.color = color_grey;
            element.value = text;
        }
    }
}

/**
* It hides list for specified version of XPath
* 
* @function
* @name hideList
* @kind function
* @param {any} collList class name of list to hide
* @returns {void}
*/
function hideList(collList) {
    for (i = 0; i < collList.length; i++) {
        if (collList[i].nextElementSibling !== null) {
            collList[i].nextElementSibling.style.maxHeight = null;
            collList[i].nextElementSibling.classList.toggle("collapsibleDataExpanded", false);
        }
        collList[i].style.display = 'none';
        collList[i].classList.remove("collapsibleActive");
    }
}

/**
* It checks if the text is a default text.
* 
* @function
* @name checkDefault
* @kind function
* @param {any} text
* @returns {boolean}
*/
function checkDefault(text) {
    return defaultStrings.includes(text);
}

/**
* It show list for specified version of XPath
* 
* @function
* @name showList
* @kind function
* @param {any} collList class name of list to hide
* @returns {void}
*/
function showList(collList) {
    for (i = 0; i < collList.length; i++) {
        collList[i].style.display = 'block';
    }
}

/**
* A function that is used to fold/unfold collapsible elements.
* 
* @function
* @name smoothFoldElement
* @kind function
* @param {any} element
* @param {any} toogleState
* @param {any} toggleParrent
* @returns {void}
*/
function smoothFoldElement(element, toogleState, toggleParrent) {
    if (toogleState) {
        if (toggleParrent) {
            element.parentElement.style.maxHeight = "0px";
        }
        
        element.classList.toggle("active", false);
        var subLists = collapsibleData.getElementsByClassName("collapsibleData");
        for (j = 0; j < subLists.length; j++) {
            subLists[j].style.maxHeight = null;
        }
    } else {
        collapsibleData.parentElement.style.maxHeight = (collapsibleData.parentElement.scrollHeight) + "px";
        collapsibleData.classList.toggle("active", true);
        if (collapsibleData.parentElement.classList.contains("collapsibleData") && collapsibleData.parentElement.classList.contains("active")) {
            collapsibleData.parentElement.style.maxHeight = (collapsibleData.parentElement.scrollHeight + collapsibleData.scrollHeight) + "px";
        }
    }
}

/**
* Set tooltip info, function is called by onClick handlers
* 
* @function
* @name refreshTooltip
* @kind function
* @returns {void}
*/
function refreshTooltip() {
    var resizeList = document.getElementsByClassName("collapsibleData");
    document.getElementById("processorTooltipInfo").innerText = procInfo;
    document.getElementById("xsltelementsheader").innerText = XSLTheader;
}



/**
* A function that performs a request to the server.
* 
* @function
* @name performRequest
* @kind function
* @param {any} endpoint of target service
* @param {any} checkXML enable checking for empty XML
* @param {any} checkTransform enable checking for empty transform data
* @returns {false | undefined}
*/
function performRequest(endpoint, checkXML, checkTransform) {
    const sourceId = "xmlArea";
    const transformId = "transformArea";
    var xmlData = document.getElementById(sourceId).innerText.trim();
    var transformData = document.getElementById(transformId).innerText.trim();
    
    var port = 8081;
    if (getProcessor() == "libxml") {
        port = 8082;
    }
    
    var empty = false;
    if (defaultStrings.includes(xmlData) && checkXML) {
        document.getElementById(sourceId).style.backgroundColor = color_red;
        xmlData = "";
        empty = true;
    }
    if (defaultStrings.includes(transformData) && checkTransform) {
        document.getElementById(transformId).style.backgroundColor = color_red;
        empty = true;
    }
    if (!empty) {
        restRequest(port, endpoint, xmlData, transformData).then(function (result) {
            document.getElementById("resultArea").innerText = result.result;
            highlightSyntax("resultArea");
            document.getElementById("procinfo").innerText = ' Computed using ' + result.processor;
            
                
            if (result.status == "OK") {
                document.getElementById("procinfo").innerText += " (" + result.time + "ms)";
                if (result.type)
                    document.getElementById("procinfo").innerText += ". Returned: " + result.type;
                else
                    document.getElementById("procinfo").innerText += ". Engine doesn't support return of data types.";
                procinfo.style.color = "#30aa58";
            } else {
                procinfo.style.color = "#aa3030";
            }
        });
    } else {
        document.getElementById("resultArea").innerHTML = "No data provided!";
        return false;
    }
    
}

/**
* Function that prepares data to send and handles response
* 
* @function
* @name performFormatRequest
* @kind function
* @param {any} endpoint of target service
* @param {any} checkXML enable checking for empty XML
* @param {any} sourceId ID of element to get XML from
* @param {any} targetId ID of element to write formatted XML
* @returns {void}
*/
function performFormatRequest(endpoint, checkXML, sourceId, targetId) {
    const sourceElement = document.getElementById(sourceId);
    const targetElement = document.getElementById(targetId);
    const infoElement = document.getElementById("formatinfo");
    const port = 8082;
    var xmlData = sourceElement.innerText.trim();
    
    var empty = false;
    if (defaultStrings.includes(xmlData) && checkXML) {
        sourceElement.style.backgroundColor = color_red;
        xmlData = "";
        empty = true;
    }
    
    if (!empty) {
        restRequest(port, endpoint, xmlData, "").then(function (result) {
            if (result.status == "OK") {
                targetElement.innerText = result.result.trim();
                highlightSyntax(targetElement.id);

                targetElement.style.backgroundColor = null;
                infoElement.innerText = ' Computed'.concat(" in ", result.time, "ms.");
                infoElement.style.color = "#30aa58";
                
            }
            else {
                targetElement.style.backgroundColor = color_red;
                infoElement.innerText = result.result;
                infoElement.style.color = "#aa3030";
            }
            
        });
    }
    
    
}


/**
* Form REST request, send and return received data
* 
* @async
* @function
* @name restRequest
* @kind function
* @param {any} port of target service
* @param {any} endpoint of target service
* @param {any} xmlData XML that will be sent
* @param {any} transformData data used to transform given XML
* @returns {Promise<any>}
*/
async function restRequest(port, endpoint, xmlData, transformData) {
    const escapeChar = "specialEscapeChar";
    
    const addr = window.location.protocol + "//" + window.location.hostname + ":" + port + "/" + endpoint;
    
    if (defaultStrings.includes(xmlData)) {
        xmlData = "<empty/>";
    }
    
    var jsonData = JSON.stringify({
        "data": xmlData,
        "process": transformData,
        "processor": getProcessor(),
        "version": getVersion()
    });
    var init = {
        headers: new Headers({
        }),
        body: jsonData,
        // body: data,
        method: "POST"
    };
    var request = new Request(addr, init);
    
    
    var result = await fetch(request).then(response => {
        return response.text().then(function (text) {
            return JSON.parse(text);
        });
        
    });
    return result;
}