<commit_before>defmodule Formex.View do
  use Phoenix.HTML

  @spec formex_for(Formex.Form.t, String.t, Keyword.t (t::any -> Phoenix.HTML.unsafe))
                   :: Phoenix.HTML.safe
  def formex_for(form, action, options \\ [], fun) do

    Phoenix.HTML.Form.form_for(form.changeset, action, options, fn f ->
      form
      |> Map.put(:phoenix_form, f)
      |> fun.()
    end)

  end

  @spec form_row(Formex.Form.t, Atom.t) :: Phoenix.HTML.safe
  def form_row(form, field_name) do

    field       = get_field(form, field_name)
    field_html  = generate_field_html(form, field)
    label_html  = generate_label_html(form, field)

    field_html = attach_addon(field_html, field)

    tags = [label_html, field_html]
      |> attach_error(form, field)

    wrapper_class = ["form-group"]
      |> attach_error_class(form, field)

    content_tag(:div, tags, class: Enum.join(wrapper_class, " "))

  end

  @spec form_row_horizontal(Formex.Form.t, Atom.t) :: Phoenix.HTML.safe
  def form_row_horizontal(form, field_name) do

    field       = get_field(form, field_name)
    field_html  = generate_field_html(form, field)
    label_html  = generate_label_html(form, field, "col-sm-2")

    field_html = attach_addon(field_html, field)

    tags = [field_html]
      |> attach_error(form, field)

    wrapper_class = ["form-group"]
      |> attach_error_class(form, field)

    column = content_tag(:div, tags, class: "col-sm-10")

    content_tag(:div, [label_html, column], class: Enum.join(wrapper_class, " "))

  end

  #

  @spec get_field(Formex.Form.t, Atom.t) :: Formex.Field.t
  defp get_field(form, field_name) do
     Enum.find(form.fields, fn field ->
       field.name == field_name
     end)
  end

  @spec generate_field_html(Formex.Form.t, Formex.Field.t) :: any
  defp generate_field_html(form, field) do

    type = field.type
    opts = field.opts
    data = field.data
    phoenix_opts = if opts[:phoenix_opts], do: opts[:phoenix_opts], else: []

    class = if opts[:class_add], do: opts[:class_add], else: ""

    args = [form.phoenix_form, field.name]
    args = args ++ cond do
      Enum.member? [:select, :multiple_select], type ->
        [data[:options], Keyword.merge([class: class<>" form-control"], phoenix_opts) ]

      Enum.member? [:checkbox], type ->
        [Keyword.merge([class: class], phoenix_opts) ]

      Enum.member? [:file_input], type ->
        [Keyword.merge([class: class], phoenix_opts) ]

      true ->
        [Keyword.merge([class: class<>" form-control"], phoenix_opts) ]
    end

    input = apply(Phoenix.HTML.Form, type, args)

    cond do
      Enum.member? [:checkbox], type ->
        content_tag(:div, [
          content_tag(:label, [
            input
            ])
          ], class: "checkbox")

      true ->
        input
    end
  end

  @spec generate_label_html(Formex.Form.t, Formex.Field.t, String.t) :: Phoenix.HTML.safe
  defp generate_label_html(form, field, class \\ "") do
    Phoenix.HTML.Form.label(
      form.phoenix_form,
      field.name,
      field.label,
      class: "control-label "<>class
    )
  end


  defp generate_error_field(form, field) do
    text = Application.get_env(:formex, :translate_error).(form.phoenix_form.errors[field.name])
    content_tag(:span, text, class: "help-block")
  end

  #

  defp attach_addon(field_html, field) do
    if field.opts[:addon] do
      addon = content_tag(:div, field.opts[:addon], class: "input-group-addon")
      content_tag(:div, [field_html, addon], class: "input-group" )
    else
      field_html
    end
  end

  defp attach_error(tags, form, field) do
    if form.phoenix_form.errors[field.name] do
      tags ++ [generate_error_field(form, field)]
    else
      tags
    end
  end

  defp attach_error_class(wrapper_class, form, field) do
    if form.phoenix_form.errors[field.name] do
      ["has-error" | wrapper_class]
    else
      wrapper_class
    end
  end

end<commit_msg>required class<commit_after>defmodule Formex.View do
  use Phoenix.HTML

  @spec formex_for(Formex.Form.t, String.t, Keyword.t (t::any -> Phoenix.HTML.unsafe))
                   :: Phoenix.HTML.safe
  def formex_for(form, action, options \\ [], fun) do

    Phoenix.HTML.Form.form_for(form.changeset, action, options, fn f ->
      form
      |> Map.put(:phoenix_form, f)
      |> fun.()
    end)

  end

  @spec form_row(Formex.Form.t, Atom.t) :: Phoenix.HTML.safe
  def form_row(form, field_name) do

    field       = get_field(form, field_name)
    field_html  = generate_field_html(form, field)
    label_html  = generate_label_html(form, field)

    field_html = attach_addon(field_html, field)

    tags = [label_html, field_html]
    |> attach_error(form, field)

    wrapper_class = ["form-group"]
    |> attach_error_class(form, field)
    |> attach_required_class(field)

    content_tag(:div, tags, class: Enum.join(wrapper_class, " "))

  end

  @spec form_row_horizontal(Formex.Form.t, Atom.t) :: Phoenix.HTML.safe
  def form_row_horizontal(form, field_name) do

    field       = get_field(form, field_name)
    field_html  = generate_field_html(form, field)
    label_html  = generate_label_html(form, field, "col-sm-2")

    field_html = attach_addon(field_html, field)

    tags = [field_html]
    |> attach_error(form, field)

    wrapper_class = ["form-group"]
    |> attach_error_class(form, field)
    |> attach_required_class(field)

    column = content_tag(:div, tags, class: "col-sm-10")

    content_tag(:div, [label_html, column], class: Enum.join(wrapper_class, " "))

  end

  #

  @spec get_field(Formex.Form.t, Atom.t) :: Formex.Field.t
  defp get_field(form, field_name) do
     Enum.find(form.fields, fn field ->
       field.name == field_name
     end)
  end

  @spec generate_field_html(Formex.Form.t, Formex.Field.t) :: any
  defp generate_field_html(form, field) do

    type = field.type
    opts = field.opts
    data = field.data
    phoenix_opts = if opts[:phoenix_opts], do: opts[:phoenix_opts], else: []

    class = if opts[:class], do: opts[:class], else: ""

    args = [form.phoenix_form, field.name]
    args = args ++ cond do
      Enum.member? [:select, :multiple_select], type ->
        [data[:options], Keyword.merge([class: class<>" form-control"], phoenix_opts) ]

      Enum.member? [:checkbox], type ->
        [Keyword.merge([class: class], phoenix_opts) ]

      Enum.member? [:file_input], type ->
        [Keyword.merge([class: class], phoenix_opts) ]

      true ->
        [Keyword.merge([class: class<>" form-control"], phoenix_opts) ]
    end

    input = apply(Phoenix.HTML.Form, type, args)

    cond do
      Enum.member? [:checkbox], type ->
        content_tag(:div, [
          content_tag(:label, [
            input
            ])
          ], class: "checkbox")

      true ->
        input
    end
  end

  @spec generate_label_html(Formex.Form.t, Formex.Field.t, String.t) :: Phoenix.HTML.safe
  defp generate_label_html(form, field, class \\ "") do
    Phoenix.HTML.Form.label(
      form.phoenix_form,
      field.name,
      field.label,
      class: "control-label "<>class
    )
  end


  defp generate_error_field(form, field) do
    text = Application.get_env(:formex, :translate_error).(form.phoenix_form.errors[field.name])
    content_tag(:span, text, class: "help-block")
  end

  #

  defp attach_addon(field_html, field) do
    if field.opts[:addon] do
      addon = content_tag(:div, field.opts[:addon], class: "input-group-addon")
      content_tag(:div, [field_html, addon], class: "input-group" )
    else
      field_html
    end
  end

  defp attach_error(tags, form, field) do
    if form.phoenix_form.errors[field.name] do
      tags ++ [generate_error_field(form, field)]
    else
      tags
    end
  end

  defp attach_error_class(wrapper_class, form, field) do
    if form.phoenix_form.errors[field.name] do
      wrapper_class ++ ["has-error"]
    else
      wrapper_class
    end
  end

  defp attach_required_class(wrapper_class, field) do
    if field.required do
      wrapper_class ++ ["required"]
    else
      wrapper_class
    end
  end

end
{'fraction_non_alphanumeric': 0.13134807858643271, 'fraction_numerical': 0.0007413814407512665, 'mean_word_length': 2.940603700097371, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7604592', 'n_tokens_mistral': 2837, 'n_tokens_neox': 2779, 'n_words': 569}