/* generator.js */

/**
 * An encapsulation of Chance.js that servers as an iteration-generator.
 * Only generate data when data is needed.
 */

var util = require('util');
var stream = require('stream');
var chanceBuilder = require('./chanceBuilder');
var format = require('util').format;
var debug = require('debug')('dataset:generator');

/**
 * DataStream Constructor
 * @param schema - a Schema object (generated by schema.js)
 * @param dataLength - the number of documents to generate
 */
function DataStream (schema, dataLength) {
  if (!(this instanceof DataStream)) {
    return new DataStream(schema, dataLength);
  }

  stream.Readable.call(this, {objectMode: true});
  this.dataLength = dataLength;
  this.restLength = dataLength;
  this.chance = chanceBuilder(schema);

  // // add schema-specific template to Chance.js
  // chance.mixin({
  //   _: function () {
  //     // todo: more complex logic
  //     var o = {};
  //     var field, type;
  //     for (field in schema) {
  //       type = schema[field];
  //       o[field] = chance[type]();
  //     }
  //     return o;
  //   }
  // });

  // log
  debug('OP: DataStream successfully built');
  debug('VERBOSE:' + this.toString());
}
util.inherits(DataStream, stream.Readable);

// readable stream
DataStream.prototype._read = function (n) {
  if (this.hasNext()) {
    this.push(this.next(n));
  } else {
    this.push(null);
  }
};

/**
 * @param step - max number of data to generate per this request
 * @return an array of documents conforming to the schema
 * @throws TypeError, StopIteration
 */
DataStream.prototype.next = function (step) {
  if (step === undefined) step = 1;
  if (typeof step !== 'number') {
    throw new Error('Not a number');
  }
  if (!this.hasNext()) {
    throw new Error('no more data to emit');
  }

  var i, data = [];
  step = Math.min(step, this.restLength);
  this.restLength -= step;
  for (i = 0; i < step; i++) {
    data.push(this.chance._0());
  }

  debug('OP: DataStream emitted %d docs, %d left', step, this.restLength);

  return data.slice(0);
};

DataStream.prototype.hasNext = function () {
  return this.restLength > 0;
};

DataStream.prototype.hasEnough = function (n) {
  return n <= this.restLength;
};

DataStream.prototype.toString = function () {
  return format('<DataStream:%d/%d,%j>',
    this.restLength, this.dataLength, this.chance._0());
};

module.exports = DataStream;

/* generator.js */

/**
 * An encapsulation of Chance.js that servers as an iteration-generator.
 * Only generate data when data is needed.
 */

var util = require('util');
var stream = require('stream');
var chanceBuilder = require('./chanceBuilder');
var format = require('util').format;
var debug = require('debug')('dataset:generator');

/**
 * DataStream Constructor
 * @param schema - a Schema object (generated by schema.js)
 * @param dataLength - the number of documents to generate
 */
function DataStream (schema, dataLength) {
  if (!(this instanceof DataStream)) {
    return new DataStream(schema, dataLength);
  }

  stream.Readable.call(this, {objectMode: true});
  this.dataLength = dataLength;
  this.restLength = dataLength;
  this.chance = chanceBuilder(schema);

  // log
  debug('OP: DataStream successfully built');
  debug('VERBOSE:' + this.toString());
}
util.inherits(DataStream, stream.Readable);

// readable stream
DataStream.prototype._read = function (n) {
  if (this.hasNext()) {
    this.push(this.next(n));
  } else {
    this.push(null);
  }
};

/**
 * @param step - max number of data to generate per this request
 * @return an array of documents conforming to the schema
 * @throws TypeError, StopIteration
 */
DataStream.prototype.next = function (step) {
  if (step === undefined) step = 1;
  if (typeof step !== 'number') {
    throw new Error('Not a number');
  }
  if (!this.hasNext()) {
    throw new Error('no more data to emit');
  }

  var i, data = [];
  step = Math.min(step, this.restLength);
  this.restLength -= step;
  for (i = 0; i < step; i++) {
    data.push(this.chance._0());
  }

  debug('OP: DataStream emitted %d docs, %d left', step, this.restLength);

  return data.slice(0);
};

DataStream.prototype.hasNext = function () {
  return this.restLength > 0;
};

DataStream.prototype.hasEnough = function (n) {
  return n <= this.restLength;
};

DataStream.prototype.toString = function () {
  return format('<DataStream:%d/%d,%j>',
    this.restLength, this.dataLength, this.chance._0());
};

module.exports = DataStream;

delete old chance