   - `acc_enc_hdr`, the HTTP header `Accept-Encoding`
   - `encs`, the list of supported encoding
   """
-  @spec choose_encoding([String.t],String.t) :: String.t | nil
-  def choose_encoding(encs,acc_enc_hdr), do:
-    choose(encs,acc_enc_hdr,"identity")
+  @spec choose_encoding([String.t], String.t) :: String.t | nil
+  def choose_encoding(encs, acc_enc_hdr) do
+    choose(encs, acc_enc_hdr, "identity")
+  end
 
   @doc """
   HTTP Charset negociation, get the charset to use from : 

  - `accept_header`, the HTTP header `Accept`
  - `ct_provided`, the list of provided content types
  """
  @spec choose_media_type([norm_content_type],String.t) :: norm_content_type | nil
  def choose_media_type(ct_provided,accept_header) do
    accepts = accept_header |> Plug.Conn.Utils.list |> Enum.map(fn "*"->"*/*";e->e end) |>  Enum.map(&Plug.Conn.Utils.media_type/1)
    accepts = for {:ok,type,subtype,params}<-accepts do 
      q = case Float.parse(params["q"] || "1") do {q,_}->q ; _ -> 1 end
      {q,type,subtype,Map.delete(params,"q")}
    end |> Enum.sort |> Enum.reverse
    Enum.find_value(accepts,fn {_,atype,asubtype,aparams}->
      Enum.find(ct_provided, fn {type,subtype,params}->
        (atype=="*" or atype==type) and (asubtype=="*" or asubtype==subtype) and aparams==params
      end)
    end)
  end

  @doc "Remove quotes from HTTP quoted string"
  def quoted_string(value), do: 
    Plug.Conn.Utils.token(value)
  @doc "Get the string list from a comma separated list of HTTP quoted strings"
  def split_quoted_strings(str), do:
    (str |> Plug.Conn.Utils.list |> Enum.map(&Plug.Conn.Utils.token/1))

  @doc "Convert a calendar date to a rfc1123 date string"
  @spec rfc1123_date({{year::integer,month::integer,day::integer}, {h::integer, min::integer, sec::integer}}) :: String.t
  def rfc1123_date({{yyyy, mm, dd}, {hour, min, sec}}) do
    day_number = :calendar.day_of_the_week({yyyy, mm, dd})
    :io_lib.format('~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT',
                     [:httpd_util.day(day_number), dd, :httpd_util.month(mm),
                      yyyy, hour, min, sec]) |> IO.iodata_to_binary
  end

  @doc "Convert rfc1123 or rfc850 to :calendar dates"
  @spec convert_request_date(String.t) :: {{year::integer,month::integer,day::integer}, {h::integer, min::integer, sec::integer}} | :bad_date
  def convert_request_date(date) do
    try do :httpd_util.convert_request_date('#{date}') catch _,_ -> :bad_date end
  end

  @doc """

defmodule Ewebmachine.Core.Utils do
  @moduledoc """
  HTTP utility module
  """

  @type norm_content_type :: {type :: String.t, subtype :: String.t, params :: map}

  @doc """
  Convert any content type representation (see spec) into a `norm_content_type`
  """
  @spec normalize_mtype({type :: String.t, params :: map} | type :: String.t | norm_content_type) :: norm_content_type
  def normalize_mtype({type, params}) do
    case String.split(type, "/") do
      [type, subtype] -> {type, subtype, params}
      _ -> {"application", "octet-stream", %{}}
    end
  end
  def normalize_mtype({_, _, %{}}=mtype), do: mtype
  def normalize_mtype(type) do
    case Plug.Conn.Utils.media_type(to_string(type)) do
      {:ok, type, subtype, params} -> {type, subtype, params}
      :error -> {"application", "octet-stream", %{}}
    end
  end

  @doc """
  Match normalized media types accepting a partial match (wildcard or
  incomplete params)
  """
  @spec fuzzy_mt_match(norm_content_type, norm_content_type) :: boolean
  def fuzzy_mt_match({h_type, h_subtype, h_params}, {a_type, a_subtype, a_params}) do
    (a_type == h_type or a_type == "*" ) and 
      (a_subtype == h_subtype or a_subtype=="*") and 
      Enum.all?(a_params, fn {k, v} -> h_params[k] == v end)
  end

  @doc """
  Format a `norm_content_type` into an HTTP content type header
  """
  @spec format_mtype(norm_content_type) :: String.t
  def format_mtype({type, subtype, params}) do
    params = params |> Enum.map(fn {k, v}->"; #{k}=#{v}" end) |> Enum.join()
    "#{type}/#{subtype}#{params}"
  end

