text: define(function (require) {
    var _ = require('lodash');
    var extractBuckets = require('components/agg_response/hierarchical/_extract_buckets');
    return function (vis, resp) {
  
      // Create the initial results structure
      var results = { rows: [] };
  
      // Create a reference to the buckets and metrics
      var metrics = vis.aggs.bySchemaGroup.metrics;
      var buckets = vis.aggs.bySchemaGroup.buckets;
      var aggs = [];
  
      if (buckets) {
        _.each(buckets, function (bucket) {
          aggs.push(bucket);
          aggs.push(metrics);
        });
      } else {
        aggs.push(metrics);
      }
  
      // Create the columns
      results.columns = _(aggs).flatten().map(function (agg) {
        return {
          categoryName: agg.schema.name,
          id: agg.id,
          aggConfig: agg,
          aggType: agg.type,
          field: agg.params.field,
          label: agg.type.makeLabel(agg)
        };
      }).value();
  
  
      // if there are no buckets then we need to just set the value and return
      if (!buckets) {
        var value = resp.aggregations
          && resp.aggregations[metrics[0].id]
          && resp.aggregations[metrics[0].id].value
          || resp.hits.total;
        results.rows.push([value]);
        return results;
      }
  
      /**
       * Walk the buckets and create records for each leaf
       * @param {aggConfig} agg The aggConfig for the current level
       * @param {object} data The aggergation object
       * @param {array} [record] The record that will eventually get pushed to the rows
       * @returns {void}
       */
      function walkBuckets(agg, data, record) {
        if (!_.isArray(record)) {
          record = [];
        }
  
        // iterate through all the buckets
        _.each(extractBuckets(data[agg.id], agg), function (bucket) {
  
          var _record = _.flatten([record, bucket.key]);
          _.each(metrics, function (metric) {
            var value = bucket.doc_count;
            if (bucket[metric.id] && !_.isUndefined(bucket[metric.id].value)) {
              value = bucket[metric.id].value;
            }
            _record.push(value);
          });
  
          // If there is another agg to call we need to check to see if it has
          // buckets. If it does then we need to keep on walking the tree.
          // This is where the recursion happens.
          if (agg._next) {
            var nextBucket = bucket[agg._next.id];
            if (nextBucket && nextBucket.buckets) {
              walkBuckets(agg._next, bucket, _record);
            }
          }
          // if there are no more aggs to walk then  push the record to the rows.
          else {
            results.rows.push(_record);
          }
        });
      }
  
      // Start walking the buckets at the beginning of the aggregations object.
      walkBuckets(buckets[0], resp.aggregations);
  
      return results;
    };
  });
  