module Faraday::NestedParamsEncoder

def self.decode(query)

def self.decode(query)
  return nil if query == nil
  params = {}
  query.split("&").each do |pair|
    next if pair.empty?
    key, value = pair.split("=", 2)
    key = unescape(key)
    value = unescape(value.gsub(/\+/, ' ')) if value
    subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
    context = params
    subkeys.each_with_index do |subkey, i|
      is_array = subkey =~ /[\[\]]+\Z/
      subkey = $` if is_array
      last_subkey = i == subkeys.length - 1
      if !last_subkey || is_array
        value_type = is_array ? Array : Hash
        if context[subkey] && !context[subkey].is_a?(value_type)
          raise TypeError, "expected %s (got %s) for param `%s'" % [
            value_type.name,
            context[subkey].class.name,
            subkey
          ]
        end
        context = (context[subkey] ||= value_type.new)
      end
      if context.is_a?(Array) && !is_array
        if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
          context << {}
        end
        context = context.last
      end
      if last_subkey
        if is_array
          context << value
        else
          context[subkey] = value
        end
      end
    end
  end
  dehash(params, 0)
end

def self.dehash(hash, depth)

FIXME: this is not compatible with Rack::Utils.parse_nested_query
Internal: convert a nested hash with purely numeric keys into an array.
def self.dehash(hash, depth)
  hash.each do |key, value|
    hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
  end
  if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
    hash.keys.sort.inject([]) { |all, key| all << hash[key] }
  else
    hash
  end
end

def self.encode(params)

def self.encode(params)
  return nil if params == nil
  if !params.is_a?(Array)
    if !params.respond_to?(:to_hash)
      raise TypeError,
        "Can't convert #{params.class} into Hash."
    end
    params = params.to_hash
    params = params.map do |key, value|
      key = key.to_s if key.kind_of?(Symbol)
      [key, value]
    end
    # Useful default for OAuth and caching.
    # Only to be used for non-Array inputs. Arrays should preserve order.
    params.sort!
  end
  # Helper lambda
  to_query = lambda do |parent, value|
    if value.is_a?(Hash)
      value = value.map do |key, val|
        key = escape(key)
        [key, val]
      end
      value.sort!
      buffer = ""
      value.each do |key, val|
        new_parent = "#{parent}%5B#{key}%5D"
        buffer << "#{to_query.call(new_parent, val)}&"
      end
      return buffer.chop
    elsif value.is_a?(Array)
      buffer = ""
      value.each_with_index do |val, i|
        new_parent = "#{parent}%5B%5D"
        buffer << "#{to_query.call(new_parent, val)}&"
      end
      return buffer.chop
    elsif value.nil?
      return parent
    else
      encoded_value = escape(value)
      return "#{parent}=#{encoded_value}"
    end
  end
  # The params have form [['key1', 'value1'], ['key2', 'value2']].
  buffer = ''
  params.each do |parent, value|
    encoded_parent = escape(parent)
    buffer << "#{to_query.call(encoded_parent, value)}&"
  end
  return buffer.chop
end