defmodule EverFaker.Gov.It do @moduledoc """ Functions for data created/released by the Italian government, like fiscal codes """ require Integer alias EverFaker.Util @doc """ Returns a random Italian fiscal code ## Examples iex> EverFaker.Gov.It.fiscal_id() "ELRCEA64C50A918F" iex> EverFaker.Gov.It.fiscal_id() "ZSLNKH22M34H480J" iex> EverFaker.Gov.It.fiscal_id() "OCPCVO90M50F353I" iex> EverFaker.Gov.It.fiscal_id() "PQYRFX94R54C681K" """ @spec fiscal_id() :: binary() def fiscal_id do surname() |> Kernel.<>(name()) |> Kernel.<>(birth_year()) |> Kernel.<>(birth_month()) |> Kernel.<>(birth_day()) |> Kernel.<>(town_code_letter()) |> Kernel.<>(town_code_numbers()) |> (&Kernel.<>(&1, cin(&1))).() end defp surname do Util.join(3, &Util.upper_letter/0) end defp name do Util.join(3, &Util.upper_letter/0) end defp birth_year do 0 |> EverFaker.random_between(99) |> Integer.to_string() |> String.pad_leading(2, "0") end defp birth_month do Util.pick(~w(A B C D E H L M P R S T)) end defp birth_day do 1..71 |> Util.pick() |> Integer.to_string() |> String.pad_leading(2, "0") end defp town_code_letter do Util.pick(~w(A B C D E F G H I L M Z)) end defp town_code_numbers do EverFaker.random_between(0, 999) |> Integer.to_string() |> String.pad_leading(3, "0") end defp cin(input) do {left, right} = input |> String.codepoints() |> Enum.with_index() |> Enum.reduce({0, 0}, fn {letter, index}, {acc_even, acc_odd} -> case Integer.is_even(index) do true -> {acc_even + cin_even(letter), acc_odd} false -> {acc_even, acc_odd + cin_odd(letter)} end end) Enum.at( ~w(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z), Integer.mod(left + right, 26) ) end defp cin_even("0"), do: 0 defp cin_even("1"), do: 1 defp cin_even("2"), do: 2 defp cin_even("3"), do: 3 defp cin_even("4"), do: 4 defp cin_even("5"), do: 5 defp cin_even("6"), do: 6 defp cin_even("7"), do: 7 defp cin_even("8"), do: 8 defp cin_even("9"), do: 9 defp cin_even("A"), do: 0 defp cin_even("B"), do: 1 defp cin_even("C"), do: 2 defp cin_even("D"), do: 3 defp cin_even("E"), do: 4 defp cin_even("F"), do: 5 defp cin_even("G"), do: 6 defp cin_even("H"), do: 7 defp cin_even("I"), do: 8 defp cin_even("J"), do: 9 defp cin_even("K"), do: 10 defp cin_even("L"), do: 11 defp cin_even("M"), do: 12 defp cin_even("N"), do: 13 defp cin_even("O"), do: 14 defp cin_even("P"), do: 15 defp cin_even("Q"), do: 16 defp cin_even("R"), do: 17 defp cin_even("S"), do: 18 defp cin_even("T"), do: 19 defp cin_even("U"), do: 20 defp cin_even("V"), do: 21 defp cin_even("W"), do: 22 defp cin_even("X"), do: 23 defp cin_even("Y"), do: 24 defp cin_even("Z"), do: 25 defp cin_odd("0"), do: 1 defp cin_odd("1"), do: 0 defp cin_odd("2"), do: 5 defp cin_odd("3"), do: 7 defp cin_odd("4"), do: 9 defp cin_odd("5"), do: 13 defp cin_odd("6"), do: 15 defp cin_odd("7"), do: 17 defp cin_odd("8"), do: 19 defp cin_odd("9"), do: 21 defp cin_odd("A"), do: 1 defp cin_odd("B"), do: 0 defp cin_odd("C"), do: 5 defp cin_odd("D"), do: 7 defp cin_odd("E"), do: 9 defp cin_odd("F"), do: 13 defp cin_odd("G"), do: 15 defp cin_odd("H"), do: 17 defp cin_odd("I"), do: 19 defp cin_odd("J"), do: 21 defp cin_odd("K"), do: 2 defp cin_odd("L"), do: 4 defp cin_odd("M"), do: 18 defp cin_odd("N"), do: 20 defp cin_odd("O"), do: 11 defp cin_odd("P"), do: 3 defp cin_odd("Q"), do: 6 defp cin_odd("R"), do: 8 defp cin_odd("S"), do: 12 defp cin_odd("T"), do: 14 defp cin_odd("U"), do: 16 defp cin_odd("V"), do: 10 defp cin_odd("W"), do: 22 defp cin_odd("X"), do: 25 defp cin_odd("Y"), do: 24 defp cin_odd("Z"), do: 23 end