"use strict";

// Generated by CoffeeScript 2.3.2
// # CSV Generator
// Please look at the [documentation](https://csv.js.org/generate/) for additional information.
var _Generator,
    stream,
    util,
    indexOf = [].indexOf;

stream = require('stream');
util = require('util'); // ## Usage  
// Stream API, for maximum of power:
// `generate([options])`
// Callback approach, for ease of use:
// `generate([options], callback)`
// ## Source Code

module.exports = function () {
  var callback, data, generator, options;

  if (arguments.length === 2) {
    options = arguments[0];
    callback = arguments[1];
  } else if (arguments.length === 1) {
    if (typeof arguments[0] === 'function') {
      options = {};
      callback = arguments[0];
    } else {
      options = arguments[0];
    }
  } else if (arguments.length === 0) {
    options = {};
  }

  generator = new _Generator(options);

  if (callback) {
    data = [];
    generator.on('readable', function () {
      var d, results;
      results = [];

      while (d = generator.read()) {
        results.push(data.push(d));
      }

      return results;
    });
    generator.on('error', callback);
    generator.on('end', function () {
      if (!generator.options.objectMode) {
        if (generator.options.encoding) {
          data = data.join('');
        } else {
          data = Buffer.concat(data);
        }
      }

      return callback(null, data);
    });
  }

  return generator;
}; // ## `Generator([options])`
// Feel free to ask for new features and to participate by writting issues and preparing push requests.
// Options are documented [here](http://csv.js.org/generate/options/).


_Generator = function Generator() {
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var accepted_header_types, base, base1, base10, base11, base2, base3, base4, base5, base6, base7, base8, base9, i, j, k, len, ref, v;

  if (options.high_water_mark) {
    // Convert Stream Readable options if underscored
    options.highWaterMark = options.high_water_mark;
  }

  if (options.object_mode) {
    options.objectMode = options.object_mode;
  } // Call parent constructor


  stream.Readable.call(this, options); // Clone and camelize options

  this.options = {};

  for (k in options) {
    v = options[k];
    this.options[_Generator.camelize(k)] = v;
  } // Normalize options


  if ((base = this.options).columns == null) {
    base.columns = 8;
  }

  if ((base1 = this.options).delimiter == null) {
    base1.delimiter = ',';
  }

  if ((base2 = this.options).duration == null) {
    base2.duration = null;
  }

  if ((base3 = this.options).encoding == null) {
    base3.encoding = null;
  }

  if ((base4 = this.options).end == null) {
    base4.end = null;
  }

  if ((base5 = this.options).eof == null) {
    base5.eof = false;
  }

  if ((base6 = this.options).fixedSize == null) {
    base6.fixedSize = false;
  }

  if ((base7 = this.options).length == null) {
    base7.length = -1;
  }

  if ((base8 = this.options).maxWordLength == null) {
    base8.maxWordLength = 16;
  }

  if ((base9 = this.options).rowDelimiter == null) {
    base9.rowDelimiter = '\n';
  }

  if ((base10 = this.options).seed == null) {
    base10.seed = false;
  }

  if ((base11 = this.options).sleep == null) {
    base11.sleep = 0;
  }

  if (this.options.eof === true) {
    // Default values
    this.options.eof = this.options.rowDelimiter;
  } // State


  this._ = {
    start_time: this.options.duration ? Date.now() : null,
    fixed_size_buffer: '',
    count_written: 0,
    count_created: 0
  };

  if (typeof this.options.columns === 'number') {
    this.options.columns = new Array(this.options.columns);
  }

  accepted_header_types = Object.keys(_Generator).filter(function (t) {
    return t !== 'super_' && t !== 'camelize';
  });
  ref = this.options.columns;

  for (i = j = 0, len = ref.length; j < len; i = ++j) {
    v = ref[i];

    if (v == null) {
      v = 'ascii';
    }

    if (typeof v === 'string') {
      if (indexOf.call(accepted_header_types, v) < 0) {
        throw Error("Invalid column type: got \"".concat(v, "\", default values are ").concat(JSON.stringify(accepted_header_types)));
      }

      this.options.columns[i] = _Generator[v];
    }
  }

  return this;
};

util.inherits(_Generator, stream.Readable);
module.exports.Generator = _Generator; // ## `Generator.prototype.random()`
// Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option.

_Generator.prototype.random = function () {
  if (this.options.seed) {
    return this.options.seed = this.options.seed * Math.PI * 100 % 100 / 100;
  } else {
    return Math.random();
  }
}; // ## `Generator.prototype.end()`
// Stop the generation.


_Generator.prototype.end = function () {
  return this.push(null);
}; // ## `Generator.prototype._read(size)`
// Put new data into the read queue.


_Generator.prototype._read = function (size) {
  var column, data, header, j, l, len, len1, len2, len3, length, line, lineLength, m, n, ref; // Already started

  data = [];
  length = this._.fixed_size_buffer.length;

  if (length) {
    data.push(this._.fixed_size_buffer);
  }

  while (true) {
    // Time for some rest: flush first and stop later
    if (this._.count_created === this.options.length || this.options.end && Date.now() > this.options.end || this.options.duration && Date.now() > this._.start_time + this.options.duration) {
      // Flush
      if (data.length) {
        if (this.options.objectMode) {
          for (j = 0, len = data.length; j < len; j++) {
            line = data[j];

            this.__push(line);
          }
        } else {
          this.__push(data.join('') + (this.options.eof ? this.options.eof : ''));
        }
      } // Stop


      return this.push(null);
    } // Create the line


    line = [];
    ref = this.options.columns;

    for (l = 0, len1 = ref.length; l < len1; l++) {
      header = ref[l]; // Create the field

      line.push("".concat(header(this)));
    } // Obtain line length


    if (this.options.objectMode) {
      lineLength = 0;

      for (m = 0, len2 = line.length; m < len2; m++) {
        column = line[m];
        lineLength += column.length;
      }
    } else {
      // Stringify the line
      line = "".concat(this._.count_created === 0 ? '' : this.options.rowDelimiter).concat(line.join(this.options.delimiter));
      lineLength = line.length;
    }

    this._.count_created++;

    if (length + lineLength > size) {
      if (this.options.objectMode) {
        data.push(line);

        for (n = 0, len3 = data.length; n < len3; n++) {
          line = data[n];

          this.__push(line);
        }
      } else {
        if (this.options.fixedSize) {
          this._.fixed_size_buffer = line.substr(size - length);
          data.push(line.substr(0, size - length));
        } else {
          data.push(line);
        }

        this.__push(data.join(''));
      }

      break;
    }

    length += lineLength;
    data.push(line);
  }
}; // ## `Generator.prototype._read(size)`
// Put new data into the read queue.


_Generator.prototype.__push = function (record) {
  var _this = this;

  this._.count_written++;

  if (this.options.sleep > 0) {
    return setTimeout(function () {
      return _this.push(record);
    }, this.options.sleep);
  } else {
    return this.push(record);
  }
}; // ## `Generator.ascii(gen)`
// Generate an ASCII value.


_Generator.ascii = function (gen) {
  var _, _char, column, j, nb_chars, ref; // Column


  column = [];
  nb_chars = Math.ceil(gen.random() * gen.options.maxWordLength);

  for (_ = j = 0, ref = nb_chars; 0 <= ref ? j < ref : j > ref; _ = 0 <= ref ? ++j : --j) {
    _char = Math.floor(gen.random() * 32);
    column.push(String.fromCharCode(_char + (_char < 16 ? 65 : 97 - 16)));
  }

  return column.join('');
}; // ## `Generator.ascii(gen)`
// Generate an integer value.


_Generator["int"] = function (gen) {
  return Math.floor(gen.random() * Math.pow(2, 52));
}; // ## `Generator.bool(gen)`
// Generate an boolean value.


_Generator.bool = function (gen) {
  return Math.floor(gen.random() * 2);
}; // ## `Generator.camelize`


_Generator.camelize = function (str) {
  return str.replace(/_([a-z])/gi, function (_, match, index) {
    return match.toUpperCase();
  });
};