 defmodule Geolix.Database do
+  use Bitwise, only_operators: true
+
   @metadata_marker <<171, 205, 239>> <> "MaxMind.com"
 
   @doc """

  defp parse_stream(stream) do
    { metadata, _ } = drop_until_meta(stream) |> Geolix.Decoder.decode()
    metadata        = HashDict.new(metadata)
    metadata        = HashDict.put(metadata, "node_byte_size", div(HashDict.get(metadata, "record_size", 0), 4))
    metadata        = HashDict.put(
      metadata, "search_tree_size",
      HashDict.get(metadata, "node_count", 0) * HashDict.get(metadata, "node_byte_size", 0))

    { metadata, {} }
  end

  defp drop_until_meta(stream) do

      Enum.drop(stream, 1) |> drop_until_meta()
    end
  end

  defp drop_until_data(stream, metadata) do
    stream |> Enum.drop(HashDict.fetch!(metadata, "search_tree_size")) |> Enum.drop(16)
  end

  defp get_start_node(32, metadata, stream) do
    case HashDict.fetch!(metadata, "ip_version") do
      6 -> get_start_node_ipv4(0, 0, stream, metadata)
      _ -> 0
    end
  end
  defp get_start_node(_, _, _) do
    0
  end

  defp get_start_node_ipv4(node, 96, _, _) do
    node
  end
  defp get_start_node_ipv4(node, index, stream, metadata) do
    read_node(node, 0, stream, metadata)
      |> get_start_node_ipv4(index + 1, stream, metadata)
  end

  defp read_node(node, index, stream, metadata) do
    IO.puts "Reading node: #{node} (index: #{index})"

    offset = node * HashDict.fetch!(metadata, "node_byte_size")

    case HashDict.fetch!(metadata, "record_size") do
      24 ->
        stream
          |> Enum.drop(offset + index * 3)
          |> Enum.take(3)
          |> Enum.join()
          |> decode_uint
      invalid ->
        IO.puts("Invalid record size in metadata: #{invalid}")
        0
    end
  end

  defp decode_uint(bytes) do
    bitstring_to_list(bytes)
      |> Enum.map(fn(x) -> integer_to_binary(x, 16) end)
      |> Enum.join()
      |> String.to_char_list!()
      |> list_to_integer(16)
  end
end
