<commit_before>defmodule CoursePlanner.SystemVariable do
  @moduledoc """
  This module holds the model for one system variable
  """
  use CoursePlanner.Web, :model

  alias Ecto.Changeset

  schema "system_variables" do
    field :key,      :string
    field :value,    :string
    field :type,     :string
    field :visible,  :boolean
    field :editable, :boolean

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    target_params =
      [
       :key,
       :value,
       :type,
       :visible,
       :editable
      ]

    struct
    |> cast(params, target_params)
    |> validate_required(target_params)
    |> validate_value_type()
  end

  def changeset(struct, params, :update) do
    target_params =
      [
       :value,
       :type
      ]

    struct
    |> cast(params, target_params)
    |> validate_required(target_params)
    |> validate_value_type()
    |> validate_editable()
  end

  defp validate_editable(%{valid?: true} = changeset) do
    editable = changeset |> Changeset.get_field(:editable)

    if editable do
      changeset
    else
      add_error(changeset, :value, "operation is forbidden")
    end
  end
  defp validate_editable(changeset), do: changeset

  defp validate_value_type(%{valid?: true} = changeset) do
    value = changeset |> Changeset.get_field(:value)
    type  = changeset |> Changeset.get_field(:type)

    validation_result = parse_value(value, type)

    case validation_result do
      {:ok, _} -> changeset
      {:error, message} -> add_error(changeset, :value, message)
    end
  end
  defp validate_value_type(changeset), do: changeset

  def parse_value(value, type) do
    case type do
      "string"  -> {:ok, value}
      "list"     -> parse_list(value)
      "integer" -> parse_integer(value)
      "boolean" -> parse_boolean(value)
      _         -> {:error, "unknown type"}
    end
  end

  def parse_list(value) do
    parse_list =
    value
    |> String.split(",")
    |> Enum.map(&String.trim/1)
    |> Enum.reject(&(&1 == ""))

    {:ok, parse_list}
  end

  def parse_integer(value) do
    case Integer.parse(value) do
      {parsed_value, ""} -> validate_number_range_inclusive(parsed_value, 0, 1_000_000)
      _                  -> {:error, "the given value should be a number"}
    end
  end

  defp validate_number_range_inclusive(number, min, max) do<commit_msg>simplifies "parse_list"<commit_after>defmodule CoursePlanner.SystemVariable do
  @moduledoc """
  This module holds the model for one system variable
  """
  use CoursePlanner.Web, :model

  alias Ecto.Changeset

  schema "system_variables" do
    field :key,      :string
    field :value,    :string
    field :type,     :string
    field :visible,  :boolean
    field :editable, :boolean

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    target_params =
      [
       :key,
       :value,
       :type,
       :visible,
       :editable
      ]

    struct
    |> cast(params, target_params)
    |> validate_required(target_params)
    |> validate_value_type()
  end

  def changeset(struct, params, :update) do
    target_params =
      [
       :value,
       :type
      ]

    struct
    |> cast(params, target_params)
    |> validate_required(target_params)
    |> validate_value_type()
    |> validate_editable()
  end

  defp validate_editable(%{valid?: true} = changeset) do
    editable = changeset |> Changeset.get_field(:editable)

    if editable do
      changeset
    else
      add_error(changeset, :value, "operation is forbidden")
    end
  end
  defp validate_editable(changeset), do: changeset

  defp validate_value_type(%{valid?: true} = changeset) do
    value = changeset |> Changeset.get_field(:value)
    type  = changeset |> Changeset.get_field(:type)

    validation_result = parse_value(value, type)

    case validation_result do
      {:ok, _} -> changeset
      {:error, message} -> add_error(changeset, :value, message)
    end
  end
  defp validate_value_type(changeset), do: changeset

  def parse_value(value, type) do
    case type do
      "string"  -> {:ok, value}
      "list"    -> parse_list(value)
      "integer" -> parse_integer(value)
      "boolean" -> parse_boolean(value)
      _         -> {:error, "unknown type"}
    end
  end

  def parse_list(value) do
    parse_list = String.split(value, [" ", ","] , trim: true)
    {:ok, parse_list}
  end

  def parse_integer(value) do
    case Integer.parse(value) do
      {parsed_value, ""} -> validate_number_range_inclusive(parsed_value, 0, 1_000_000)
      _                  -> {:error, "the given value should be a number"}
    end
  end

  defp validate_number_range_inclusive(number, min, max) do
{'fraction_non_alphanumeric': 0.11347664324100869, 'fraction_numerical': 0.0037205456800330715, 'mean_word_length': 2.7395672333848533, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 44, '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': '2962290', 'n_tokens_mistral': 1615, 'n_tokens_neox': 1544, 'n_words': 379}