(function (paw, _super, utils, DOMPurify) {

    /**
     *  settings {
          blob: Blob,
          url: string,
          controls: boolean,
          downloadUrl: string,
          scaling: boolean,
          previewNotAvailableLabel: string
        }
     * 
     * @param {any} $container
     * @param {any} settings
    */
    paw.lang.extend(CsvComponent, _super);
    function CsvComponent($container, settings) {
        _super.call(this, $container, settings, 'fa fa-file-csv fa-4x');

        this.delimiters = [',', ';'];
        this.delimiter = ';';

        this.result = null;
    }

    CsvComponent.prototype.renderDocument = function () {
        var self = this;
        return this.blobToText(this.blob).then(function (csvText) {
            self.csvText = csvText;

            self.result = self.parseCsv(self.csvText);
            return self.result;
        });
    };

    CsvComponent.prototype.compilePreview = function () {
        if (utils.value.notSet(this.result)) {
            return utils.async.promise();
        }
        try {
            var $table = $('<table class="csv-preview-table' + (!this.result.integrityCheck ? ' csv-failed-integrity' : '') + '"><thead><tr><th></th></tr></thead><tbody></tbody></table>');
            var $thRow = $table.find('> thead > tr');
            var $tbody = $table.children('tbody');
            var gridDim = [40, 20];
            if (gridDim[0] < this.result.rows.length) {
                gridDim[0] = this.result.rows.length + 1;
            }
            if (this.result.rows.length > 0 && gridDim[1] < this.result.rows[0].length) {
                gridDim[1] = this.result.rows[0].length + 1;
            }

            for (var i = 0; i < gridDim[0]; i++) {
                var row = this.result.rows[i];
                var $trow = $('<tr></tr>');

                var markup = [];
                markup.push('<td class="csv-pewview-row-no">' + (i + 1) + '</td>');
                for (var j = 0; j < gridDim[1]; j++) {
                    var col = utils.value.isSet(row)? row[j] : null;
                    var txt = utils.value.isSet(col) ? DOMPurify.sanitize(col) : '';
                    markup.push('<td title="' + txt + '">' + txt + '</td>');
                    if (i === 0) {

                        $thRow.append('<th>' + this.calcColumnLabel(j + 1) + '</th>');
                    }
                }

                $trow.html(markup.join('\n'));
                $tbody.append($trow);
            }
            var $holder = $('<div class="csv-preview-holder"></div>')
            $holder.append($table);
            this.$container.html($holder);

            this.scaleSheet($holder);
        }
        catch (e) {
            return utils.async.reject(e);
        }
        return utils.async.promise();
    };

    CsvComponent.prototype.blobToText = function (blob) {
        var self = this;
        var encodings = ['utf-8', 'iso-8859-1', 'windows-1252'];
        return new Promise((resolve, reject) => {
            var reader = new FileReader();
            reader.onload = function (event) {
                var text = event.target.result;
                self.determineDelimiter(text);
                if (self.isValidCSV(text)) {
                    resolve(text);
                } else {
                    var err = new Error('Invalid or corrupted CSV file');
                    reject(err);
                    console.error(err);
                }
            };
            reader.onerror = function () {
                var err = new Error('Error reading Blob as text');
                reject(err);
                console.error(err);
            };
            var tryNextEncoding = function (index) {
                if (index >= encodings.length) {
                    var err = new Error('Unable to decode Blob content');
                    reject(err);
                    console.error(err);
                    return;
                }
                reader.readAsText(blob, encodings[index]);
            };
            tryNextEncoding(0);
        });
    };

    CsvComponent.prototype.isValidCSV = function (text) {
        return text.indexOf(this.delimiter) > -1 && text.indexOf('\n') > -1;
    };

    CsvComponent.prototype.parseCsv = function (csvString) {
        var lines = csvString.split('\n');
        var result = {
            rows: [],
            integrityCheck: true
        };
        var prevColLength = 0;
        for (var i = 0; i < lines.length; i++) {
            // last row, skip empty new line (if any)
            if (i === lines.length - 1 && lines[i].indexOf(this.delimiter) === -1) {
                continue;
            }

            var values = lines[i].split(this.delimiter);

            // check content integrity
            if (i > 0 && values.length !== prevColLength) {
                result.integrityCheck = false;
                result.rows.push([lines[i]]);
            }
            else {
                result.rows.push(values);
            }
            
            prevColLength = values.length;
        }

        if (!result.integrityCheck) {
            console.warn("CSV failed content integrity check");
        }

        return result;
    };

    CsvComponent.prototype.calcColumnLabel = function (index) {
        var label = '';
        while (index > 0) {
            var remainder = (index - 1) % 26;
            label = String.fromCharCode(65 + remainder) + label;
            index = Math.floor((index - 1) / 26);
        }
        return label;
    };

    CsvComponent.prototype.scaleSheet = function ($obj) {
        if (this.settings.scaling) {
            $obj.width(600);
            $obj.height(600);

            var w = $obj.width();
            var h = $obj.height();

            var delta = this.$container.innerHeight() / h;
            if (delta >= 1) {
                return;
            }
            $obj.css({
                transform: 'scale(' + delta + ')'
            });

            $obj.css({
                'margin-left': -w * 0.5 + w * delta * 0.5,
                'margin-top': -h * 0.5 + h * delta * 0.5
            });
        }
    };

    CsvComponent.prototype.determineDelimiter = function (csvText) {
        var self = this;
        utils.iterable.iterate(this.delimiters, function (delimiter) {
            if (csvText.indexOf(delimiter) > -1 && csvText.indexOf('\n') > -1) {
                self.delimiter = delimiter;
                return false;
            }
        });
    };


    paw.com.CsvComponent = CsvComponent;
})(paw, paw.com.DocumentViewerComponent, paw.utils, DOMPurify);