module RuboCop::Cop::CheckLineBreakable

def all_on_same_line?(nodes)

def all_on_same_line?(nodes)
  return true if nodes.empty?
  nodes.first.first_line == nodes.last.last_line
end

def already_on_multiple_lines?(node)

def already_on_multiple_lines?(node)
  node.first_line != node.last_line
end

def breakable_collection?(node, elements)

def breakable_collection?(node, elements)
  # For simplicity we only want to insert breaks in normal
  # hashes wrapped in a set of curly braces like {foo: 1}.
  # That is, not a kwargs hash. For method calls, this ensures
  # the method call is made with parens.
  starts_with_bracket = node.loc.begin
  # If the call has a second argument, we can insert a line
  # break before the second argument and the rest of the
  # argument will get auto-formatted onto separate lines
  # by other cops.
  has_second_element = elements.length >= 2
  starts_with_bracket && has_second_element
end

def children_could_be_broken_up?(children)

def children_could_be_broken_up?(children)
  return false if all_on_same_line?(children)
  last_seen_line = -1
  children.each do |child|
    return true if last_seen_line >= child.first_line
    last_seen_line = child.last_line
  end
  false
end

def contained_by_breakable_collection_on_same_line?(node)

def contained_by_breakable_collection_on_same_line?(node)
  node.each_ancestor.find do |ancestor|
    # Ignore ancestors on different lines.
    break if ancestor.first_line != node.first_line
    if ancestor.hash_type? || ancestor.array_type?
      elements = ancestor.children
    elsif ancestor.send_type?
      elements = process_args(ancestor.arguments)
    else
      next
    end
    return true if breakable_collection?(ancestor, elements)
  end
  false
end

def contained_by_multiline_collection_that_could_be_broken_up?(node)

def contained_by_multiline_collection_that_could_be_broken_up?(node)
  node.each_ancestor.find do |ancestor|
    if ancestor.hash_type? || ancestor.array_type?
      if breakable_collection?(ancestor, ancestor.children)
        return children_could_be_broken_up?(ancestor.children)
      end
    end
    next unless ancestor.send_type?
    args = process_args(ancestor.arguments)
    if breakable_collection?(ancestor, args)
      return children_could_be_broken_up?(args)
    end
  end
  false
end

def extract_breakable_node(node, max)

def extract_breakable_node(node, max)
  if node.send_type?
    args = process_args(node.arguments)
    return extract_breakable_node_from_elements(node, args, max)
  elsif node.array_type? || node.hash_type?
    return extract_breakable_node_from_elements(node, node.children, max)
  end
  nil
end

def extract_breakable_node_from_elements(node, elements, max)

def extract_breakable_node_from_elements(node, elements, max)
  return unless breakable_collection?(node, elements)
  return if safe_to_ignore?(node)
  line = processed_source.lines[node.first_line - 1]
  return if processed_source.commented?(node.loc.begin)
  return if line.length <= max
  extract_first_element_over_column_limit(node, elements, max)
end

def extract_first_element_over_column_limit(node, elements, max)

def extract_first_element_over_column_limit(node, elements, max)
  line = node.first_line
  i = 0
  i += 1 while within_column_limit?(elements[i], max, line)
  return elements.first if i.zero?
  elements[i - 1]
end

def process_args(args)

def process_args(args)
  # If there is a trailing hash arg without explicit braces, like this:
  #
  #    method(1, 'key1' => value1, 'key2' => value2)
  #
  # ...then each key/value pair is treated as a method 'argument'
  # when determining where line breaks should appear.
  if (last_arg = args.last)
    if last_arg.hash_type? && !last_arg.braces?
      args = args.concat(args.pop.children)
    end
  end
  args
end

def safe_to_ignore?(node)

def safe_to_ignore?(node)
  return true unless max
  return true if already_on_multiple_lines?(node)
  # If there's a containing breakable collection on the same
  # line, we let that one get broken first. In a separate pass,
  # this one might get broken as well, but to avoid conflicting
  # or redundant edits, we only mark one offense at a time.
  return true if contained_by_breakable_collection_on_same_line?(node)
  if contained_by_multiline_collection_that_could_be_broken_up?(node)
    return true
  end
  false
end

def within_column_limit?(element, max, line)

def within_column_limit?(element, max, line)
  element && element.loc.column < max && element.loc.line == line
end