defmodule IBAN do
  @len %{ AL: 28, AD: 24, AT: 20, AZ: 28, BE: 16, BH: 22, BA: 20, BR: 29,
          BG: 22, CR: 21, HR: 21, CY: 28, CZ: 24, DK: 18, DO: 28, EE: 20,
          FO: 18, FI: 18, FR: 27, GE: 22, DE: 22, GI: 23, GR: 27, GL: 18,
          GT: 28, HU: 28, IS: 26, IE: 22, IL: 23, IT: 27, KZ: 20, KW: 30,
          LV: 21, LB: 28, LI: 21, LT: 20, LU: 20, MK: 19, MT: 31, MR: 27,
          MU: 30, MC: 27, MD: 24, ME: 22, NL: 18, NO: 15, PK: 24, PS: 29,
          PL: 28, PT: 25, RO: 24, SM: 27, SA: 24, RS: 22, SK: 24, SI: 19,
          ES: 24, SE: 24, CH: 21, TN: 24, TR: 26, AE: 23, GB: 22, VG: 24 }

  def valid?(iban) do
    iban = String.replace(iban, ~r/\s/, "")
    if Regex.match?(~r/^[\dA-Z]+$/, iban) do
      cc = String.slice(iban, 0..1) |> String.to_atom
      if String.length(iban) == @len[cc] do
        {left, right} = String.split_at(iban, 4)
        num = String.codepoints(right <> left)
              |> Enum.map_join(fn c -> String.to_integer(c,36) end)
              |> String.to_integer
        rem(num,97) == 1
      else
        false
      end
    else
      false
    end
  end
end

[ "GB82 WEST 1234 5698 7654 32",
  "gb82 west 1234 5698 7654 32",
  "GB82 WEST 1234 5698 7654 320",
  "GB82WEST12345698765432",
  "GB82 TEST 1234 5698 7654 32",
  "ZZ12 3456 7890 1234 5678 12"  ]
|> Enum.each(fn iban -> IO.puts "#{IBAN.valid?(iban)}\t#{iban}" end)
