var template = '<div class="custom-control custom-checkbox"><input id="{{id}}" type="checkbox" class="custom-control-input" value="{{value}}"> <label for="{{id}}" class="custom-control-label">{{value}}</label></div>'

var filterTerms = {}
var filters = {}
$.fn.dataTable.ext.search.push(
    function (settings, data, dataIndex) {
        var isAllowed = true
        for (var i = 0; i < data.length; i++) {
            var filter = filters[i]
            if (filter && !filter(data[i], dataIndex)) {
                isAllowed = false
            }
        }

        return isAllowed
    }
)

function createStandardFilters(table, columns, items) {
    createTextFilter(table)

    $.each(columns, function (index, column) {
        switch (column.type) {
            case "item":
            case "subnodes":
                createItemFilter(table, column, index, items)
                break
            default:
                hideFilter(column)
        }
    })
}

function createMasterDetailFilters(table, columns, items) {
    createTextFilter(table)

    $.each(columns, function (index, column) {
        switch (column.type) {
            case "column":
                createColumnFilter(table, column, items)
                break
            case "item":
                createMasterDetailFilter(table, column, index, items)
                break
            default:
                hideFilter(column)
        }
    })
}

function createColumnFilter(table, column, items) {
    var element = $('#filter-' + column.name)

    var values = items
        .map(function (v) { return v.generatedColumns })
        .flat()
        .filter(distinct)
        .map(function (v) { return [v] })

    createFilterElements(element, column, values)

    element.find("input[type='checkbox']").each(function () {
        var tableColumn = table.column(this.value + ":name")
        $(this).prop("checked", tableColumn.visible())

        $(this).change(function () {
            tableColumn.visible(this.checked)
            table.draw() // To reapply filters
        })
    })
}

function createTextFilter(table) {
    $('#text-filter-input').keyup(function () {
        table.search(this.value).draw()
    })
}

function hideFilter(column) {
    var element = $('#filter-' + column.name)
    element.parent().hide()
}

function createItemFilter(table, column, columnIndex, items) {
    var element = $('#filter-' + column.name)

    var values = items.map(function (v) { return v[column.data] }).filter(exists)

    createFilterElements(element, column, values)

    element.find("input[type='checkbox']").change(function () {
        var selected = element.find("input:checked")
            .map(function () { return $(this).attr("value") })
            .get()

        filterTerms[columnIndex] = selected

        if (column.type === 'subnodes') {
            filters[columnIndex] = function (value, dataIndex) {
                return !selected.length || includes(selected, value.split(","))
            }
        }
        else {
            filters[columnIndex] = function (value, dataIndex) {
                return !selected.length || includes(selected, [value])
            }
        }

        table.draw()
    })
}

function createMasterDetailFilter(table, column, columnIndex, items) {
    var element = $('#filter-' + column.name)

    var values = items.map(function (item) { return getRowValues(item) })

    createFilterElements(element, column, values)

    element.find("input[type='checkbox']").change(function () {
        var selected = element.find("input:checked")
            .map(function () { return $(this).attr("value") })
            .get()

        filterTerms[columnIndex] = selected

        filters[columnIndex] = function (value, dataIndex) {
            var item = items[dataIndex]

            var rowValues = getRowValues(item, function (c) { return table.column(c + ":name").visible() === true })

            return !selected.length || includes(selected, rowValues)
        }

        table.draw()
    })

    function getRowValues(item, predicate) {
        return item.generatedColumns
            .filter(function (c) { return !predicate || predicate(c) })
            .map(function (c) { return item[c][column.name] })
            .flat()
            .filter(function (v) { return v.length })
            .filter(distinct)
    }
}

function createFilterElements(element, column, values) {
    var html = ''
    var allValues = []
    $.each(values, function (index, items) {
        $.each(items, function (i, item) {
            if (allValues.indexOf(item.trim()) == -1) {
                allValues.push(item.trim())
            }
        })
    })

    allValues.sort()

    $.each(allValues.filter(distinct), function (itemIndex, item) {
        var id = "filter-" + column.name + "-item-" + itemIndex
        html += template.replace(/{{id}}/g, id).replace(/{{value}}/g, item)
    })

    element.html(html)

    element.find(".custom-control-label").each(function () {
        if (!$(this).text().length) {
            $(this).parent().hide()
        }
    })
}

function distinct(value, index, self) {
    return self.indexOf(value) === index
}

function exists(value) {
    return !!value
}

function includes(searchIn, searchFor) {
    var found = false
    $.each(searchIn, function (_i1, value1) {
        $.each(searchFor, function (_i2, value2) {
            if (value1.trim() == value2.trim()) {
                found = true
            }
        })
    })

    return found
}