import “../arrays/merge”; import “../core/rebind”; import “layout”;

d3.layout.hierarchy = function() {

var sort = d3_layout_hierarchySort,
    children = d3_layout_hierarchyChildren,
    value = d3_layout_hierarchyValue;

// Recursively compute the node depth and value.
// Also converts to a standard hierarchy structure.
function recurse(node, depth, nodes) {
  var childs = children.call(hierarchy, node, depth);
  node.depth = depth;
  nodes.push(node);
  if (childs && (n = childs.length)) {
    var i = -1,
        n,
        c = node.children = [],
        v = 0,
        j = depth + 1,
        d;
    while (++i < n) {
      d = recurse(childs[i], j, nodes);
      d.parent = node;
      c.push(d);
      v += d.value;
    }
    if (sort) c.sort(sort);
    if (value) node.value = v;
  } else if (value) {
    node.value = +value.call(hierarchy, node, depth) || 0;
  }
  return node;
}

// Recursively re-evaluates the node value.
function revalue(node, depth) {
  var children = node.children,
      v = 0;
  if (children && (n = children.length)) {
    var i = -1,
        n,
        j = depth + 1;
    while (++i < n) v += revalue(children[i], j);
  } else if (value) {
    v = +value.call(hierarchy, node, depth) || 0;
  }
  if (value) node.value = v;
  return v;
}

function hierarchy(d) {
  var nodes = [];
  recurse(d, 0, nodes);
  return nodes;
}

hierarchy.sort = function(x) {
  if (!arguments.length) return sort;
  sort = x;
  return hierarchy;
};

hierarchy.children = function(x) {
  if (!arguments.length) return children;
  children = x;
  return hierarchy;
};

hierarchy.value = function(x) {
  if (!arguments.length) return value;
  value = x;
  return hierarchy;
};

// Re-evaluates the `value` property for the specified hierarchy.
hierarchy.revalue = function(root) {
  revalue(root, 0);
  return root;
};

return hierarchy;

};

// A method assignment helper for hierarchy subclasses. function d3_layout_hierarchyRebind(object, hierarchy) {

d3.rebind(object, hierarchy, "sort", "children", "value");

// Add an alias for nodes and links, for convenience.
object.nodes = object;
object.links = d3_layout_hierarchyLinks;

return object;

}

function d3_layout_hierarchyChildren(d) {

return d.children;

}

function d3_layout_hierarchyValue(d) {

return d.value;

}

function d3_layout_hierarchySort(a, b) {

return b.value - a.value;

}

// Returns an array source+target objects for the specified nodes. function d3_layout_hierarchyLinks(nodes) {

return d3.merge(nodes.map(function(parent) {
  return (parent.children || []).map(function(child) {
    return {source: parent, target: child};
  });
}));

}