(function ($, DataTable, window) {
    'use strict';

    var buildParams = function (dt) {
        // DataTables already knows the current sort and search values. Send those
        // values so the export matches what the user is looking at.
        var params = dt.ajax.params();
        params.action = 'csv';
        params._token = $('meta[name="csrf-token"]').attr('content');
        params.visible_columns = null;

        return params;
    };

    var exportUrl = function (dt) {
        // Data loads from the page route. Exports use the sibling /export route.
        var url = dt.ajax.url() || window.location.href;
        var cleanUrl = url.split('#')[0];
        var pieces = cleanUrl.split('?');
        var base = pieces[0].replace(/\/+$/, '');
        var query = pieces.length > 1 ? '?' + pieces.slice(1).join('?') : '';

        return (base.match(/\/export$/) ? base : base + '/export') + query;
    };

    var responseText = function (response) {
        // The response may be JSON or a CSV file. Decode manually because the XHR
        // is configured for file downloads.
        if (window.TextDecoder) {
            return new TextDecoder('utf-8').decode(response);
        }

        var bytes = new Uint8Array(response);
        var text = '';
        for (var i = 0; i < bytes.length; i++) {
            text += String.fromCharCode(bytes[i]);
        }

        return text;
    };

    var flash = function (message, status) {
        if (window.Ignite && window.Ignite.Core && window.Ignite.Core.flash) {
            window.Ignite.Core.flash(message, status || 'info', 5000);
        }
    };

    var handleJsonResponse = function (xhr) {
        var data = JSON.parse(responseText(xhr.response || new ArrayBuffer(0)));
        if (data.message) {
            flash(data.message, data.status || 'info');
        }
    };

    var downloadResponse = function (xhr) {
        // Small reports still download immediately, just like the original CSV button.
        var filename = '';
        var disposition = xhr.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
            var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            var matches = filenameRegex.exec(disposition);
            if (matches !== null && matches[1]) {
                filename = matches[1].replace(/['"]/g, '');
            }
        }

        var type = xhr.getResponseHeader('Content-Type');
        var blob = new Blob([xhr.response], {type: type});
        if (typeof window.navigator.msSaveBlob !== 'undefined') {
            window.navigator.msSaveBlob(blob, filename);
            return;
        }

        var URL = window.URL || window.webkitURL;
        var downloadUrl = URL.createObjectURL(blob);
        if (filename) {
            var anchor = document.createElement('a');
            if (typeof anchor.download === 'undefined') {
                window.location = downloadUrl;
            } else {
                anchor.href = downloadUrl;
                anchor.download = filename;
                document.body.appendChild(anchor);
                anchor.click();
                document.body.removeChild(anchor);
            }
        } else {
            window.location = downloadUrl;
        }

        setTimeout(function () {
            URL.revokeObjectURL(downloadUrl);
        }, 100);
    };

    var requestDownload = function (dt) {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', exportUrl(dt), true);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function () {
            // JSON means the report was queued. A 200 file response means it is ready.
            var type = xhr.getResponseHeader('Content-Type') || '';
            if (type.indexOf('application/json') !== -1) {
                handleJsonResponse(xhr);
                return;
            }

            if (xhr.status === 200) {
                downloadResponse(xhr);
                return;
            }

            flash('The CSV export could not be started. Please try again.', 'danger');
        };
        xhr.onerror = function () {
            flash('The CSV export could not be started. Please try again.', 'danger');
        };
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        xhr.send($.param(buildParams(dt)));
    };

    DataTable.ext.buttons.reportDownloadCsv = {
        className: 'buttons-csv',
        text: function (dt) {
            return '<i class="fa fa-file-excel-o"></i> ' + dt.i18n('buttons.csv', 'CSV');
        },
        action: function (event, dt) {
            event.preventDefault();
            requestDownload(dt);
        }
    };

    // Only pages that load this file replace postCsv. Other pages keep the shared
    // Core DataTables CSV button.
    DataTable.ext.buttons.postCsv = DataTable.ext.buttons.reportDownloadCsv;
})(jQuery, jQuery.fn.dataTable, window);
