var Group = require('./group');

var _ = require('lodash');
var util = require('util');

var Repeat = function(options, factory) {
  'use strict';
  Repeat.super_.call(this, options);

  //separator defaults to ' '
  if (typeof options.separator === 'undefined') {
    options.separator = ' ';
  }
  if (typeof options.max === 'undefined') {
    options.max = Number.MAX_VALUE;
  }
  if (typeof options.min === 'undefined') {
    options.min = Number.MIN_VALUE;
  }
  if (typeof options.min === 'undefined') {
    options.min = Number.MIN_VALUE;
  }
  if (typeof options.unique === 'undefined') {
    options.unique = false;
  }

  this.child = factory.create(options.child);
  this.separator = factory.create(options.separator);
  this.max = options.max;
  this.min = options.min;
  this.unique = options.unique;
};

util.inherits(Repeat, Group);

Repeat.prototype.handleParse = function(input, lang, context, data, done) {
  'use strict';
  var parsesActive = 0;
  var this_ = this;

  var parseChild = function(input, wasSuggested, level) {
    
    var childData = function(option) {
      var ownResult = _.isArray(option.result[this_.id]) ? option.result[this_.id] : [];
      var childResult = option.result[this_.child.id];
      var newOption;
      var continueToSeparator;

      if (this_.unique && _.contains(ownResult, childResult)) {
        return;
      }

      if (typeof childResult !== 'undefined') {
        ownResult.push(childResult);
      }

      newOption = option.handleValue(this_.id, ownResult);

      newOption = newOption.handleValue(this_.child.id, undefined);

      //store continueToSeparator, in case the call to data data changes newOption
      continueToSeparator = newOption.suggestion.words.length === 0;

      if (level >= this_.min && level <= this_.max) {
        data(newOption);
      }

      if (level < this_.max && continueToSeparator) {
        parseSeparator(newOption, wasSuggested, level);
      }
    };

    var childDone = function(err) {
      if (err) {
        done(err);
      } else {
        parsesActive--;
        if (parsesActive === 0) {
          done();
        }
      }
    };

    parsesActive++;
    this_.child.parse(input, lang, context, childData, childDone);
  };

  var parseSeparator = function(input, wasSuggested, level) {

    var separatorData = function(option) {
      parseChild(option, wasSuggested, level + 1);
    };

    var separatorDone = function(err) {
      if (err) {
        done(err);
      } else {
        parsesActive--;
        if (parsesActive === 0) {
          done();
        }
      }
    };

    this_.separator.parse(input, lang, context, separatorData, separatorDone);
  };

  parseChild(input, false, 1);
};

module.exports = Repeat;
@@ -78,24 +78,53 @@
 e('util');%0A%0A
+//class Repeat extends Group%0A
 var Repeat =
@@ -213,90 +213,117 @@
 %0A%0A  
-//separator defaults to ' '%0A  if (typeof options.separator === 'undefined') %7B%0A    
+this.child = factory.create(options.child);%0A%0A  //separator defaults to ' '%0A  this.separator = factory.create(
 opti
@@ -340,150 +340,87 @@
 tor 
-=
+%7C%7C
  ' '
+)
 ;%0A
-  %7D%0A  if (typeof options.max === 'undefined') %7B%0A    options.max = Number.MAX_VALUE;%0A  %7D%0A  if (typeof options.min === 'undefined') %7B%0A   
+%0A  //options.max defaults to huge, but can be 0, so no %7C%7C%0A  this.max =
  opt
@@ -417,36 +417,37 @@
 .max = options.m
-in =
+ax %7C%7C
  Number.MIN_VALU
@@ -435,34 +435,34 @@
  %7C%7C Number.M
-IN
+AX
 _VALUE;%0A
   %7D%0A  if (ty
@@ -453,327 +453,91 @@
 UE;%0A
-  %7D%0A  if (typeof options.min === 'undefined') %7B%0A    options.min = Number.MIN_VALUE;%0A  %7D%0A  if (typeof options.unique === 'undefined') %7B%0A    options.unique = false;%0A  %7D%0A%0A  this.child = factory.create(options.child);%0A  this.separator = factory.create(options.separator);%0A  this.max = options.max;%0A  this.min = options.min;
+%0A  //min defaults to 0%0A  this.min = options.min %7C%7C 0;%0A%0A  //unique defaults to false
 %0A  t
@@ -563,16 +563,25 @@
 s.unique
+ %7C%7C false
 ;%0A%7D;%0A%0Aut
@@ -874,18 +874,8 @@
 t = 
-_.isArray(
 opti
@@ -897,37 +897,11 @@
 .id%5D
-) ? option.result%5Bthis_.id%5D :
+ %7C%7C
  %5B%5D;
@@ -1009,16 +1009,146 @@
 rator;%0A%0A
+      //if the repeat is unique and the childResult already exists in the result,%0A      // just stop - we will not do this branch%0A
       if
@@ -1318,24 +1318,78 @@
 );%0A      %7D%0A%0A
+      //set this repeat's result to the new ownResult%0A
       newOpt
@@ -1432,24 +1432,61 @@
 wnResult);%0A%0A
+      //clear out the child's result%0A
       newOpt
@@ -1695,16 +1695,81 @@
 === 0;%0A%0A
+      //only call data if we are within the min/max repeat range%0A
       if
@@ -1840,32 +1840,41 @@
 tion);%0A      %7D%0A%0A
+      //%0A
       if (level 

Refactor repeat