(function () {

function arraySort(isNumeric, order)
{
    return function(a,b)
    {
        if (a.value === "" && b.value !== "")
        {
            return 1;
        }
        if (b.value === "" && a.value !== "")
        {
            return -1;
        }
        if (isNumeric)
        {
            return (a.value - b.value) * order;
        }
        if (a.value < b.value)
        {
            return -1 * order;
        }
        if (a.value > b.value)
        {
            return 1 * order;
        }
        return 0;
    }
}


function sortTable(event)
{
    let table = getParentTable(event.target);
    let column = event.target.cellIndex;
    let tHeadings = table.getElementsByTagName("TH");
    let rows = table.rows;
    const tBodyNode = rows[1].parentNode;
    
    // Numeric columns should have numeric class
    let columnIsNumeric = tHeadings[column].classList.contains("numeric") ? 1 : 0;
    
    // Sort order: 1 for ascending, -1 for descending
    let order = (tHeadings[column].classList.contains("sorted") && !tHeadings[column].classList.contains("descending")) ? -1 : 1;
    
    let rowsArray = [];
    for (let i = 1; i < rows.length; i++)
    {
        let cellvalue = rows[i].getElementsByTagName("TD")[column].innerText;
        cellvalue = cellvalue.trim();
        rowsArray.push({value: cellvalue.toUpperCase(), row: rows[i]});
    }
    
    rowsArray.sort( arraySort(columnIsNumeric, order) );
    
    while (rowsArray.length > 0)
    {
        let r = rowsArray.shift();
        // Move row to bottom of table
        tBodyNode.appendChild(r.row);
    }
    
    // Apply class to TH so that CSS can style the heading of the sorted column
    for (let i = 0; i < tHeadings.length; i++)
    {
        tHeadings[i].classList.remove("sorted");
        tHeadings[i].classList.remove("descending");
    }
    tHeadings[column].classList.add("sorted");
    if (-1 === order)
    {
        tHeadings[column].classList.add("descending");
    }
}


function getParentTable(cell)
{
    let element = cell.parentElement;
    while (element !== null && element.tagName !== "TABLE")
    {
        element = element.parentElement;
    }
    return element;
}


function allowSorting()
{
    let tables = document.querySelectorAll('table.tablesort');
    for (let t = 0; t < tables.length; t++)
    {
        let tHeadings = tables[t].getElementsByTagName("TH");
        for (let i = 0; i < tHeadings.length; i++)
        {
            tHeadings[i].addEventListener('click', sortTable, false);
        }
    }
}


if (document.readyState === 'loading')
{
    document.addEventListener('DOMContentLoaded', allowSorting);
}
else
{
    allowSorting();
}

})();