% phonenumbers.sty
% LaTeX-Paket zur Formatierung von Telefonnummern
% LaTeX package for formatting telephone numbers
% Autor: K. Wehr
% Version: 1.1.1
% Datum: 13. November 2016

% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
% http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.


\RequirePackage{expl3}
\ProvidesExplPackage {phonenumbers} {2016/11/13} {1.1.1} {Telephone number package}

\RequirePackage{xparse}
\RequirePackage{l3keys2e}
\RequirePackage{ltxcmds}

\clist_const:Nn \c_phone_ziffern_clist {0,1,2,3,4,5,6,7,8,9}

\tl_const:Nn \c_phone_bindestrich_tl {\kern1pt - \kern1pt}

\str_new:N \l_phone_land_str
\str_new:N \l_phone_heimatland_str
\str_new:N \l_phone_auslandsvorwahltyp_str
\str_new:N \l_phone_vorwahldarstellung_str
\str_new:N \l_phone_vorwahltrennung_str
\str_new:N \l_phone_heimatvorwahl_str
\str_new:N \l_phone_bereinigte_eingabe_str
\str_new:N \l_phone_linktext_str

\int_new:N \l_phone_ziffernzahl_int

\tl_new:N \l_phone_ausgabetext_tl
\tl_new:N \l_phone_formatierte_nummer_tl

\bool_new:N \l_phone_vorwahl_gefunden_bool
\bool_new:N \l_phone_zeilenumbruch_bool
\bool_new:N \l_phone_eingabe_leer_bool
\bool_new:N \l_phone_durchwahl_leer_bool
\bool_new:N \l_phone_nummer_verlinken_bool

\cs_generate_variant:Nn \str_if_eq:nnT {xnT}
\cs_generate_variant:Nn \str_if_eq:nnTF {xnTF}
\cs_generate_variant:Nn \str_case:nn {Vn,xn}
\cs_generate_variant:Nn \str_case:nnF {VnF,xnF}
\cs_generate_variant:Nn \str_case:nnTF {VnTF,xnTF}
\cs_generate_variant:Nn \str_put_right:Nn {NV}
\cs_generate_variant:Nn \tl_put_right:Nn {Nv}
\cs_generate_variant:Nn \msg_new:nnn {nnx}
\cs_generate_variant:Nn \msg_info:nnn {nnV}
\cs_generate_variant:Nn \msg_info:nnnn {nnnv}
\cs_generate_variant:Nn \msg_warning:nnnn {nnnx}


\msg_new:nnn {phonenumbers} {illegal~character}
   {
      illegal~character~'#1'~in~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {empty~input}
   {
      empty~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {empty~extension}
   {
      empty~extension~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {missing~subscriber~number}
   {
      no~subscriber~number~(Teilnehmerrufnummer)~given~in~#1~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {invalid~area~code}
   {
      unknown~area~code~(Vorwahl)~in~#1~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {number~too~short}
   {
      #1~phone~number~has~less~than~#2~digits~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {number~too~long}
   {
      #1~phone~number~has~more~than~#2~digits~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {illegal~length}
   {
      #1~phone~number~has~no~legal~number~of~digits~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {illegal~extension}
   {
      extension~(Durchwahl)~of~#1~phone~number~ignored~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {home~area~code~set}
   {
      Your~home~is~in~#2~(area~code~#1)~according~to~line~\msg_line_number:.
   }

\msg_new:nnn {phonenumbers} {home~area~code~cleared}
   {
      home~area~code~#1~was~deleted~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {invalid~home~area~code}
   {
      #1~unknown~as~#2~geographic~area~code~(Ortsvorwahl)~\msg_line_context:
   }


\cs_new:Npn \phone_landesadjektiv:n #1
   {
      \str_case:nn {#1}
         {
            {DE} {German}
            {FR} {French}
            {US} {American}
         }
   }

\cs_generate_variant:Nn \phone_landesadjektiv:n {V}


\keys_define:nn {phonenumbers}
   {
      country .choices:nn = {DE,FR,US}
         {
            \str_set_eq:NN \l_phone_land_str \l_keys_choice_tl
         },
      country .initial:n = DE,
      country .value_required:n = true
   }

\keys_define:nn {phonenumbers}
   {
      foreign .choices:nn = {off,european,american,international}
         {
            \str_set_eq:NN \l_phone_auslandsvorwahltyp_str \l_keys_choice_tl
         },
      foreign .initial:n = off,
      foreign .default:n = international
   }

\keys_define:nn {phonenumbers}
   {
      area-code .choices:nn = {number,place,place-and-number}
         {
            \str_set_eq:NN \l_phone_vorwahldarstellung_str \l_keys_choice_tl
         },
      area-code .initial:n = number,
      area-code .value_required:n = true
   }

\keys_define:nn {phonenumbers}
   {
      area-code-sep .choices:nn = {space,slash,brackets,hyphen}
         {
            \str_set_eq:NN \l_phone_vorwahltrennung_str \l_keys_choice_tl
         },
      area-code-sep .initial:n = slash,
      area-code-sep .value_required:n = true
   }

\keys_define:nn {phonenumbers}
   {
      link .choices:nn = {on,off}
         {
            \str_if_eq:VnTF \l_keys_choice_tl {on}
               {
                  \bool_set_true:N \l_phone_nummer_verlinken_bool
               }
               {
                  \bool_set_false:N \l_phone_nummer_verlinken_bool
               }
         },
      link .initial:n = on,
      link .value_required:n = true
   }

\keys_define:nn {phonenumbers}
   {
      home-area-code .code:n =
         {
            \str_if_eq:nnTF {#1}{none}
               {
                  \str_if_empty:NF \l_phone_heimatvorwahl_str
                     {
                        \msg_info:nnV {phonenumbers} {home~area~code~cleared} \l_phone_heimatvorwahl_str
                        \str_clear:N \l_phone_heimatvorwahl_str
                     }
               }
               {
                  \str_case:VnF {\l_phone_land_str}
                     {
                        {FR} {\phone_FR_heimatvorwahl_festlegen:n {#1}}
                        {US} {\phone_US_heimatvorwahl_festlegen:n {#1}}
                     }
                     {
                        \clist_if_in:cnTF {c_phone_\l_phone_land_str _ortsvorwahlliste_clist} {#1}
                           {
                              \str_set_eq:NN \l_phone_heimatland_str \l_phone_land_str
                              \str_set:Nn \l_phone_heimatvorwahl_str {#1}
                              \msg_info:nnnv {phonenumbers} {home~area~code~set} {#1} {c_phone_\l_phone_land_str _ortsname_#1_tl}
                           }
                           {
                              \msg_warning:nnnx {phonenumbers} {invalid~home~area~code} {#1} {\phone_landesadjektiv:V \l_phone_land_str}
                           }
                     }
               }
         },
      home-area-code .initial:n = none,
      home-area-code .value_required:n = true
   }


\cs_new:Npn \phone_gruppierte_ziffernfolge_ausgeben:n #1
   {
      \int_set:Nn \l_phone_ziffernzahl_int {\tl_count:n {#1}}
      \tl_clear:N \l_phone_formatierte_nummer_tl

      \int_step_inline:nnnn {\l_phone_ziffernzahl_int} {-1} {1}
         {
            \tl_put_left:Nx \l_phone_formatierte_nummer_tl {\tl_item:nn {#1} {##1}}

            \int_if_even:nT {\l_phone_ziffernzahl_int + 1 - ##1}
               {
                  \int_compare:nNnT {##1} > {1}
                     {\tl_put_left:Nn \l_phone_formatierte_nummer_tl {\,}}
               }
         }

      \tl_put_right:NV \l_phone_ausgabetext_tl \l_phone_formatierte_nummer_tl
   }

\cs_generate_variant:Nn \phone_gruppierte_ziffernfolge_ausgeben:n {V,x}


\cs_new:Npn \phone_auslandsvorwahl_ausgeben:n #1
   {
      \str_case:VnTF \l_phone_land_str
         {
            {DE} { }
            {FR} { }
         }
         {
            \str_case:Vn \l_phone_auslandsvorwahltyp_str
               {
                  {international} {\tl_put_right:Nn \l_phone_ausgabetext_tl {+#1}}
                  {european} {\phone_gruppierte_ziffernfolge_ausgeben:n {00#1}}
                  {american} {\phone_gruppierte_ziffernfolge_ausgeben:n {011#1}}
               }
         }
         {
            \tl_put_right:Nx \l_phone_ausgabetext_tl
               {
                  \str_case:Vn \l_phone_auslandsvorwahltyp_str
                     {
                        {international} {+ #1}
                        {european} {00 #1}
                        {american} {011 #1}
                     }
               }
         }
   }

\cs_generate_variant:Nn \phone_auslandsvorwahl_ausgeben:n {x}


% #1: eingebene Nummer, #2: Handelt es sich um eine Durchwahl?
\cs_new:Npn \phone_eingabe_ueberpruefen:nN #1#2
   {
      \tl_if_blank:nTF {#1}
         {
            \bool_if:NTF #2
               {
                  \msg_warning:nn {phonenumbers} {empty~extension}
                  \bool_set_true:N \l_phone_durchwahl_leer_bool
               }
               {
                  \msg_warning:nn {phonenumbers} {empty~input}
                  \bool_set_true:N \l_phone_eingabe_leer_bool
               }
         }
         {
            \bool_if:NTF #2
               {
                  \bool_set_false:N \l_phone_durchwahl_leer_bool
               }
               {
                  \bool_set_false:N \l_phone_eingabe_leer_bool
               }
         }

      \str_clear:N \l_phone_bereinigte_eingabe_str

      \tl_map_inline:nn {#1}
         {
            \clist_if_in:NnTF \c_phone_ziffern_clist {##1}
               {
                  \str_put_right:Nn \l_phone_bereinigte_eingabe_str {##1}
               }
               {
                  \msg_warning:nnx {phonenumbers} {illegal~character} {##1}
               }
         }
   }

\cs_new:Npn \phone_nummerntext_ausgeben:
   {
      \bool_if:nTF {\l_phone_nummer_verlinken_bool && !\str_if_empty_p:N \l_phone_linktext_str}
         {
            \ltx@ifpackageloaded {hyperref}
               {
                  \href{tel\c_colon_str\l_phone_linktext_str}{\l_phone_ausgabetext_tl}
               }
               {
                  \l_phone_ausgabetext_tl
               }
         }
         {
            \l_phone_ausgabetext_tl
         }
   }

\cs_new:Npn \phone_nummer_ohne_durchwahl_ausgeben:n #1
   {
      \phone_eingabe_ueberpruefen:nN {#1} \c_false_bool

      \bool_if:NF \l_phone_eingabe_leer_bool
         {
            \str_case:Vn \l_phone_land_str
               {
                  {DE} {\phone_DE_nummer_ausgeben:V \l_phone_bereinigte_eingabe_str}
                  {FR} {\phone_FR_nummer_ausgeben:V \l_phone_bereinigte_eingabe_str}
                  {US} {\phone_US_nummer_ausgeben:V \l_phone_bereinigte_eingabe_str}
               }
         }

      \phone_nummerntext_ausgeben:
   }

% #1: Nummer, #2: Durchwahl
\cs_new:Npn \phone_nummer_mit_durchwahl_ausgeben:nn #1#2
   {
      \str_if_eq:VnTF \l_phone_land_str {DE}
         {
            \phone_eingabe_ueberpruefen:nN {#1} \c_false_bool
            \str_set_eq:NN \l_tmpa_str \l_phone_bereinigte_eingabe_str

            \phone_eingabe_ueberpruefen:nN {#2} \c_true_bool
            \str_set_eq:NN \l_phone_DE_durchwahl_str \l_phone_bereinigte_eingabe_str

            \phone_DE_nummer_ausgeben:V \l_tmpa_str

            \phone_nummerntext_ausgeben:
         }
         {
            \str_set:Nx \l_tmpa_str
               {
                  \str_case:Vn \l_phone_land_str
                     {
                        {FR} {French}
                        {US} {American}
                     }
               }

            \phone_eingabe_ueberpruefen:nN {#2} \c_true_bool

            \bool_if:NF \l_phone_durchwahl_leer_bool
               {
                  \msg_warning:nnx {phonenumbers} {illegal~extension} {\l_tmpa_str}
               }

            \phone_nummer_ohne_durchwahl_ausgeben:n {#1}
         }
   }

\cs_new:Npn \phone_vorwahlliste_ausgeben:n #1
   {
      \begin{tabbing}
      \str_case:VnF \l_phone_land_str
         {
            {US} {\hspace{3em}}
         }
         {
            \hspace{4em}
         }
      \= \kill

      \bool_set_false:N \l_phone_zeilenumbruch_bool

      \clist_map_inline:cn {c_phone_\l_phone_land_str _#1_clist}
         {
            \bool_if:NTF \l_phone_zeilenumbruch_bool
               {
                  \\
               }
               {
                  \bool_gset_true:N \l_phone_zeilenumbruch_bool
               }

            \str_case:VnTF \l_phone_land_str
               {
                  {DE} {\phone_DE_gruppierte_vorwahl_ausgeben:nN {##1} \c_true_bool}
                  {FR} {\phone_gruppierte_ziffernfolge_ausgeben:n {##1}}
               }
               {
                  \tl_use:N \l_phone_ausgabetext_tl
               }
               {
                  ##1
               }
            \>
            \tl_if_exist:cTF {c_phone_\str_use:N \l_phone_land_str _ortsname_##1_tl}
               {
                  \tl_use:c {c_phone_\str_use:N \l_phone_land_str _ortsname_##1_tl}
               }
               {
                  UNKNOWN~PLACE
               }
         }
      \end{tabbing}
   }

\NewDocumentCommand \setphonenumbers {m}
   {
      \keys_set:nn {phonenumbers} {#1}
   }

\NewDocumentCommand \phonenumber {omo}
   {
      \group_begin:
      \IfValueT {#1}
         {
            \keys_set:nn {phonenumbers} {#1}
         }

      \IfValueTF {#3}
         {
            \phone_nummer_mit_durchwahl_ausgeben:nn {#2} {#3}
         }
         {   
            \phone_nummer_ohne_durchwahl_ausgeben:n {#2}
         }
      \group_end:
   }

\NewDocumentCommand \AreaCodesGeographic {o}
   {
      \group_begin:
      \IfValueT {#1}
         {
            \keys_set:nn {phonenumbers} {#1}
         }

      \phone_vorwahlliste_ausgeben:n {ortsvorwahlliste}
      \group_end:
   }

\NewDocumentCommand \AreaCodesNonGeographic {o}
   {
      \group_begin:
      \IfValueT {#1}
         {
            \keys_set:nn {phonenumbers} {#1}
         }

      \phone_vorwahlliste_ausgeben:n {sondervorwahlliste}
      \group_end:
   }


%%%%%%%%%%%%%%%%%%%% DEUTSCHLAND %%%%%%%%%%%%%%%%%%%%

\file_input:n {DE_Vorwahlen}
\file_input:n {DE_Ortsnamen}

\clist_new:N \c_phone_DE_vorwahlliste_clist
\clist_concat:NNN \c_phone_DE_vorwahlliste_clist \c_phone_DE_ortsvorwahlliste_clist \c_phone_DE_sondervorwahlliste_clist

\str_new:N \l_phone_DE_vorwahl_str
\str_new:N \l_phone_DE_durchwahl_str
\int_new:N \l_phone_DE_hauptnummerlaenge_int
\bool_new:N \l_phone_DE_teilnehmerrufnummer_gueltig_bool

\msg_new:nnn {phonenumbers} {DE/subscriber~number~too~short}
   {
      subscriber~number~(Teilnehmerrufnummer)~has~less~than~#1~digits~in~German~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {DE/subscriber~number~too~long}
   {
      subscriber~number~(Teilnehmerrufnummer)~has~more~than~#1~digits~in~German~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {DE/illegal~start~of~subscriber~number}
   {
      subscriber~number~(Teilnehmerrufnummer)~starts~with~0~in~German~phone~number~\msg_line_context:
   }   


% #1: Vorwahl, #2: Soll die führende null ausgegeben werden?
\cs_new:Npn \phone_DE_gruppierte_vorwahl_ausgeben:nN #1#2
   {
      \int_compare:nNnTF {\str_count:n {#1}} = {5}
         {
            \str_set:Nx \l_tmpa_str {\str_range:nnn {#1} {1} {4}}
            \str_set:Nx \l_tmpb_str {\str_range:nnn {#1} {5} {5}}

            \bool_if:nTF {\str_if_eq_p:Vn \l_tmpa_str {0137} || \str_if_eq_p:Vn \l_tmpa_str {0180}}
               {
                  \bool_if:nTF {#2}
                     {
                        \phone_gruppierte_ziffernfolge_ausgeben:V \l_tmpa_str
                     }
                     {
                        \phone_gruppierte_ziffernfolge_ausgeben:x {\str_tail:N \l_tmpa_str}
                     }

                  \tl_put_right:Nn \l_phone_ausgabetext_tl {\,}
                  \tl_put_right:NV \l_phone_ausgabetext_tl \l_tmpb_str
               }
               {
                  \bool_if:nTF {#2}
                     {
                        \phone_gruppierte_ziffernfolge_ausgeben:n {#1}
                     }
                     {
                        \phone_gruppierte_ziffernfolge_ausgeben:x {\str_tail:n {#1}}
                     }
               }
         }
         {
            \bool_if:nTF {#2}
               {
                  \phone_gruppierte_ziffernfolge_ausgeben:n {#1}
               }
               {
                  \phone_gruppierte_ziffernfolge_ausgeben:x {\str_tail:n {#1}}
               }
         }
   }

% #1: Vorwahl, #2: Soll die führende null ausgegeben werden?
\cs_new:Npn \phone_DE_geklammerte_vorwahl_ausgeben:nN #1#2
   {
      % Klammern werden nur bei Ortsvorwahlen gesetzt
      \clist_if_in:NnTF \c_phone_DE_ortsvorwahlliste_clist {#1}
         {
            \tl_put_right:Nn \l_phone_ausgabetext_tl {(}
            \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} #2
            \tl_put_right:Nn \l_phone_ausgabetext_tl {)}
         }
         {
            \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} #2
         }
   }

% #1: Vorwahl, #2: Folgt eine Rufnummer?
\cs_new:Npn \phone_DE_vorwahl_ausgeben:nN #1 #2
   {
      \str_if_eq:VnTF \l_phone_auslandsvorwahltyp_str {off}
         {
            \clist_if_in:NnT \c_phone_DE_sondervorwahlliste_clist {#1}
               {
                  \str_if_eq:VnT \l_phone_vorwahldarstellung_str {place}
                     {
                        \str_set:Nn \l_phone_vorwahldarstellung_str {number}
                     }
               }

            \bool_if:nF {\str_if_eq_p:Vn \l_phone_heimatland_str {DE} && \str_if_eq_p:Vn \l_phone_heimatvorwahl_str {#1}}
               {
                  \str_case:Vn \l_phone_vorwahldarstellung_str
                     {
                        {number}
                           {
                              \bool_if:NTF #2
                                 {
                                    \str_if_eq:VnTF \l_phone_vorwahltrennung_str {brackets}
                                       {
                                          \phone_DE_geklammerte_vorwahl_ausgeben:nN {#1} \c_true_bool
                                          \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
                                       }
                                       {
                                          \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} \c_true_bool
      
                                          \tl_put_right:Nx \l_phone_ausgabetext_tl
                                             {
                                                \str_case:VnF \l_phone_vorwahltrennung_str
                                                   {
                                                      {space} {\c_space_tl}
                                                      {hyphen} {\c_phone_bindestrich_tl}
                                                   }
                                                   {
                                                      \slash
                                                   }
                                             }
                                       }
                                 }
                                 {
                                    \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} \c_true_bool
                                 }
                           }
                        {place}
                           {
                              \bool_if:NTF #2
                                 {
                                    \str_if_eq:VnT \l_phone_vorwahltrennung_str {brackets}
                                       {
                                          \tl_put_right:Nn \l_phone_ausgabetext_tl {(}
                                       }
      
                                    \tl_if_exist:cTF {c_phone_DE_ortsname_#1_tl}
                                       {
                                          \tl_put_right:Nv \l_phone_ausgabetext_tl {c_phone_DE_ortsname_#1_tl}
                                       }
                                       {
                                          \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} \c_true_bool
                                       }
      
                                    \tl_put_right:Nx \l_phone_ausgabetext_tl
                                       {
                                          \str_case:VnF \l_phone_vorwahltrennung_str
                                             {
                                                {brackets} {) \c_space_tl}
                                                {space} {\c_space_tl}
                                                {hyphen} {\c_phone_bindestrich_tl}
                                             }
                                             {
                                                \slash
                                             }
                                       }
                                 }
                                 {
                                    \tl_if_exist:cTF {c_phone_DE_ortsname_#1_tl}
                                       {
                                          \tl_put_right:Nv \l_phone_ausgabetext_tl {c_phone_DE_ortsname_#1_tl}
                                       }
                                       {
                                          \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} \c_true_bool
                                       }
                                 }
                           }
                        {place-and-number}
                           {
                              \tl_if_exist:cT {c_phone_DE_ortsname_#1_tl}
                                 {
                                    \tl_put_right:Nv \l_phone_ausgabetext_tl {c_phone_DE_ortsname_#1_tl}
                                    \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
                                 }
      
                              \str_if_eq:VnTF \l_phone_vorwahltrennung_str {brackets}
                                 {
                                    \phone_DE_geklammerte_vorwahl_ausgeben:nN {#1} \c_true_bool
      
                                    \bool_if:NT #2
                                       {
                                          \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
                                       }
                                 }
                                 {
                                    \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} \c_true_bool
      
                                    \bool_if:NT #2
                                       {
                                          \tl_put_right:Nx \l_phone_ausgabetext_tl
                                             {
                                                \str_case:VnF \l_phone_vorwahltrennung_str
                                                   {
                                                      {space} {\c_space_tl}
                                                      {hyphen} {\c_phone_bindestrich_tl}
                                                   }
                                                   {
                                                      \slash
                                                   }
                                             }
                                       }
                                 }
                           }
                     }
               }
         }
         {
            \phone_auslandsvorwahl_ausgeben:n {49}

            \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl

            \str_if_eq:VnTF \l_phone_vorwahltrennung_str {brackets}
               {
                  \phone_DE_geklammerte_vorwahl_ausgeben:nN {#1} \c_false_bool
               }
               {
                  \phone_DE_gruppierte_vorwahl_ausgeben:nN {#1} \c_false_bool
               }

            \bool_if:NT #2
               {
                  \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
               }
         }

      % Linktext schreiben, falls eine Rufnummer folgt
      \bool_if:NT #2
         {
            \str_put_right:Nn \l_phone_linktext_str {+49}
            \str_put_right:Nx \l_phone_linktext_str {\str_tail:n {#1}}
         }
   }

\cs_generate_variant:Nn \phone_DE_vorwahl_ausgeben:nN {Vx}


% #1: Nummer, #2: Mindestlänge, #3: Höchstlänge, #4: Nummernart
\cs_new:Npn \phone_DE_nummernlaenge_ueberpruefen:Nnnn #1#2#3#4
   {
      \int_set:Nn \l_tmpa_int {\str_count:N #1}

      \int_compare:nNnTF {\l_tmpa_int} < {#2}
         {
            \msg_warning:nnnn {phonenumbers} {number~too~short} {German~#4} {#2}
         }
         {
            \int_compare:nNnTF {\l_tmpa_int} > {#3}
               {
                  \msg_warning:nnnn {phonenumbers} {number~too~long} {German~#4} {#3}
               }
               {
                  \bool_set_true:N \l_phone_DE_teilnehmerrufnummer_gueltig_bool
               }
         }
   }

% #1: Vorwahl, #2: Teilnehmerrufnummer
\cs_new:Npn \phone_DE_teilnehmerrufnummernlaenge_ueberpruefen:Nn #1#2
   {
      \int_set:Nn \l_tmpa_int {\str_count:N #1}
      \int_add:Nn \l_tmpa_int {\str_count:n {#2}}
      \int_add:Nn \l_tmpa_int {\str_count:N \l_phone_DE_durchwahl_str}

      \int_compare:nNnTF {\l_tmpa_int} > {12}
         {
            \msg_warning:nnnn {phonenumbers} {number~too~long} {German} {12}
         }
         {
            \int_set:Nn \l_tmpa_int {\str_count:n {#2}}
            \int_add:Nn \l_tmpa_int {\str_count:N \l_phone_DE_durchwahl_str}

            \int_compare:nNnTF {\l_tmpa_int} < {3}
               {
                  \msg_warning:nnn {phonenumbers/DE} {subscriber~number~too~short} {3}
               }
               {
                  \int_compare:nNnTF {\l_tmpa_int} > {8}
                     {
                        \msg_warning:nnn {phonenumbers/DE} {subscriber~number~too~long} {8}
                     }
                     {
                        \bool_set_true:N \l_phone_DE_teilnehmerrufnummer_gueltig_bool
                     }
               }
         }
   }

% #1: Vorwahl, #2: Teilnehmerrufnummer
\cs_new:Npn \phone_DE_teilnehmerrufnummer_ausgeben:Nn #1 #2
   {
      % Überprüfen der Nummernlänge
      \str_if_empty:NTF #1
         {
            % Festnetznummer ohne Vorwahl
            \bool_if:NF \l_phone_eingabe_leer_bool
               {
                  \phone_DE_teilnehmerrufnummernlaenge_ueberpruefen:Nn #1 {#2}
               }
         }
         {
            \clist_if_in:NVTF \c_phone_DE_ortsvorwahlliste_clist #1
               {
                  % Festnetznummer
                  \str_if_eq:xnTF {\str_head:n {#2}} {0}
                     {
                        \msg_warning:nn {phonenumbers/DE} {illegal~start~of~subscriber~number}
                     }
                     {
                        \phone_DE_teilnehmerrufnummernlaenge_ueberpruefen:Nn #1 {#2}
                     }
               }
               {
                  % Mobilfunk-/Sondernummer
                  \str_set_eq:NN \l_tmpa_str #1
                  \str_put_right:Nn \l_tmpa_str {#2}

                  \str_if_eq:xnTF {\str_range:Nnn #1 {1} {5}} {09009}
                     {
                        \phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {12} {12} {09009}
                     }
                     {
                        \str_case:xnF {\str_range:Nnn #1 {1} {4}}
                           {
                              {0137} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {11} {0137}}
                              {0160} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {12} {mobile}}
                              {0162} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {12} {mobile}}
                              {0163} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {12} {mobile}}
                              {0164} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {5} {14} {0164}} % Funkruf
                              {0168} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {5} {15} {0168}} % Funkruf
                              {0169} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {5} {15} {0169}} % Funkruf
                              {0180} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {11} {0180}}
                              {0181} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {8} {15} {0181}}
                              {0191} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {5} {5} {0191}}
                              {0194} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {7} {7} {0194}}
                              {0700} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {12} {12} {0700}}
                              {0800} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {11} {0800}}
                              {0900} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {11} {0900}}
                           }
                           {
                              \str_case:xn {\str_range:Nnn #1 {1} {3}}
                                 {
                                    {015} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {12} {12} {mobile}}
                                    {017} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {11} {12} {mobile}}
                                    {018} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {12} {12} {018}}
                                    {019}
                                       {
                                          \phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {5} {7} {019}
      
                                          \int_compare:nNnT {\str_count:N \l_tmpa_str} = {6}
                                             {
                                                \msg_warning:nnn {phonenumbers} {illegal~length} {019}
                                                \bool_set_false:N \l_phone_DE_teilnehmerrufnummer_gueltig_bool
                                             }
                                       }
                                    {032} {\phone_DE_nummernlaenge_ueberpruefen:Nnnn \l_tmpa_str {12} {12} {032}}
                                 }
                           }
                     }
               }

            \bool_if:NTF \l_phone_DE_teilnehmerrufnummer_gueltig_bool
               {
                  % Für gültige Nummern mit Vorwahl Linktext schreiben:
                  \str_put_right:Nn \l_phone_linktext_str {#2}
                  \str_put_right:NV \l_phone_linktext_str \l_phone_DE_durchwahl_str
               }
               {
                  % Für ungültige Nummern mit Vorwahl Linktext löschen:
                  \str_clear:N \l_phone_linktext_str
               }
         }

      \bool_if:NTF \l_phone_DE_teilnehmerrufnummer_gueltig_bool
         {
            \phone_gruppierte_ziffernfolge_ausgeben:n {#2}
         }
         {
            \str_put_right:Nn \l_phone_ausgabetext_tl {#2}
         }

      \str_if_empty:NF \l_phone_DE_durchwahl_str
         {
            \tl_put_right:NV \l_phone_ausgabetext_tl \c_phone_bindestrich_tl
            \phone_gruppierte_ziffernfolge_ausgeben:V \l_phone_DE_durchwahl_str
         }
   }

\cs_generate_variant:Nn \phone_DE_teilnehmerrufnummer_ausgeben:Nn {Nx}


\cs_new_protected:Npn \phone_DE_nummer_ausgeben:n #1
   {
      \str_if_eq:xnTF {\str_head:n {#1}} {0}
         {
            \int_set:Nn \l_phone_DE_hauptnummerlaenge_int {\str_count:n {#1}}
            
            \bool_set_false:N \l_phone_vorwahl_gefunden_bool

            \int_step_inline:nnnn {6} {-1} {3}
               {
                  \bool_if:nF {\l_phone_vorwahl_gefunden_bool}
                     {
                        \int_compare:nT {\l_phone_DE_hauptnummerlaenge_int >= ##1}
                           {
                              \str_set:Nx \l_phone_DE_vorwahl_str {\str_range:nnn {#1} {1} {##1}}

                              \clist_if_in:NVT \c_phone_DE_vorwahlliste_clist \l_phone_DE_vorwahl_str
                                 {
                                    \bool_set_true:N \l_phone_vorwahl_gefunden_bool

                                    \phone_DE_vorwahl_ausgeben:Vx \l_phone_DE_vorwahl_str {\int_compare_p:nNn {##1} < {\l_phone_DE_hauptnummerlaenge_int}}
                                    
                                    \int_compare:nNnTF {##1} = {\l_phone_DE_hauptnummerlaenge_int}
                                       {
                                          \msg_warning:nnn {phonenumbers} {missing~subscriber~number} {German}
                                       }
                                       {
                                          \phone_DE_teilnehmerrufnummer_ausgeben:Nx \l_phone_DE_vorwahl_str {\str_range:nnn {#1} {##1 + 1} {-1}}
                                       }
                                 }
                           }
                     }
               }

            \bool_if:nF {\l_phone_vorwahl_gefunden_bool}
               {
                  \msg_warning:nnn {phonenumbers} {invalid~area~code} {German}
                  #1
                  \str_use:N \l_phone_DE_durchwahl_str
               }
         }
         {
            \phone_DE_teilnehmerrufnummer_ausgeben:Nn \c_empty_tl {#1}
         }
   }

\cs_generate_variant:Nn \phone_DE_nummer_ausgeben:n {V}


%%%%%%%%%%%%%%%%%%%% FRANKREICH %%%%%%%%%%%%%%%%%%%%

\file_input:n {FR_Vorwahlen}
\file_input:n {FR_Ortsnamen}

\clist_new:N \c_phone_FR_vorwahlliste_clist
\clist_concat:NNN \c_phone_FR_vorwahlliste_clist \c_phone_FR_ortsvorwahlliste_clist \c_phone_FR_sondervorwahlliste_clist

\int_new:N \l_phone_FR_nummerlaenge_int

\msg_new:nnn {phonenumbers} {FR/illegal~home~area~code}
   {
      The~only~legal~home~area~code~in~France~is~0508~(Saint-Pierre-et-Miquelon).~#1~cannot~be~set~as~home~area~code~\msg_line_context:.
   }

\msg_new:nnn {phonenumbers} {FR/missing~zero}
   {
      French~phone~number~has~no~zero~in~the~beginning~\msg_line_context:
   }


% #1: Heimatvorwahl
\cs_new:Npn \phone_FR_heimatvorwahl_festlegen:n #1
   {
      \clist_if_in:NnTF {\c_phone_FR_ortsvorwahlliste_clist} {#1}
         {
            % In Frankreich ist nur 0508 für Saint-Pierre-et-Miquelon als Heimatvorwahl erlaubt:
            \str_if_eq:nnTF {#1} {0508}
               {
                  \str_set:Nn \l_phone_heimatland_str {FR}
                  \str_set:Nn \l_phone_heimatvorwahl_str {#1}
                  \msg_info:nnnv {phonenumbers} {home~area~code~set} {#1} {c_phone_FR_ortsname_#1_tl}
               }
               {
                  \msg_warning:nnn {phonenumbers/FR} {illegal~home~area~code} {#1}
               }
         }
         {
            % keine gültige Ortsvorwahl:
            \msg_warning:nnnn {phonenumbers} {invalid~home~area~code} {#1} {French}
         }
   }

% #1: Vorwahl
\cs_new:Npn \phone_FR_ermittle_landeskennzahl:n #1
   {
      \str_case:nnF {#1}
         {
            {0262} {262}
            {026200} {262}
            {0269} {262}
            {0508} {508}
            {0590} {590}
            {0594} {594}
            {0596} {596}
            {0639} {262}
            {0690} {590}
            {0691} {590}
            {0692} {262}
            {0693} {262}
            {0694} {594}
            {0696} {596}
            {0697} {596}
         }
         {
            33
         }
   }

% #1: Vorwahl
\cs_new:Npn \phone_FR_vorwahl_ausgeben:n #1
   {
      \str_if_eq:VnTF \l_phone_auslandsvorwahltyp_str {off}
         {
            \clist_if_in:NnT \c_phone_FR_sondervorwahlliste_clist {#1}
               {
                  \str_if_eq:VnT \l_phone_vorwahldarstellung_str {place}
                     {
                        \str_set:Nn \l_phone_vorwahldarstellung_str {number}
                     }
               }

            \bool_if:nF {\str_if_eq_p:Vn \l_phone_heimatland_str {FR} && \str_if_eq_p:Vn \l_phone_heimatvorwahl_str {#1}}
               {
                  \str_case:Vn \l_phone_vorwahldarstellung_str
                     {
                        {number}
                           {
                              \phone_gruppierte_ziffernfolge_ausgeben:n {#1}
                              \tl_put_right:Nn \l_phone_ausgabetext_tl {\,}
                           }
                        {place}
                           {
                              \tl_if_exist:cTF {c_phone_FR_ortsname_#1_tl}
                                 {
                                    \tl_put_right:Nv \l_phone_ausgabetext_tl {c_phone_FR_ortsname_#1_tl}
                                    \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
                                 }
                                 {
                                    \phone_gruppierte_ziffernfolge_ausgeben:n {#1}
                                    \tl_put_right:Nn \l_phone_ausgabetext_tl {\,}
                                 }
                           }
                        {place-and-number}
                           {
                              \tl_if_exist:cT {c_phone_FR_ortsname_#1_tl}
                                 {
                                    \tl_put_right:Nv \l_phone_ausgabetext_tl {c_phone_FR_ortsname_#1_tl}
                                    \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
                                 }
      
                              \phone_gruppierte_ziffernfolge_ausgeben:n {#1}
                              \tl_put_right:NV \l_phone_ausgabetext_tl {\,}
                           }
                     }
               }
         }
         {
            \phone_auslandsvorwahl_ausgeben:x {\phone_FR_ermittle_landeskennzahl:n {#1}}
            \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl

            \str_if_eq:nnF {#1} {0508}   % in Saint-Pierre-et-Miquelon entfällt die Ortsvorwahl
               {
                  \phone_gruppierte_ziffernfolge_ausgeben:x {\str_tail:n {#1}}
                  \tl_put_right:Nn \l_phone_ausgabetext_tl {\,}
               }
         }

      \str_put_right:Nx \l_phone_linktext_str {+\phone_FR_ermittle_landeskennzahl:n {#1}}

      \str_if_eq:nnF {#1} {0508}   % in Saint-Pierre-et-Miquelon entfällt die Ortsvorwahl
         {
            \str_put_right:Nx \l_phone_linktext_str {\str_tail:n {#1}}
         }
   }

\cs_generate_variant:Nn \phone_FR_vorwahl_ausgeben:n {V}


\cs_new:Npn \phone_FR_nummer_ausgeben:n #1
   {
      \int_set:Nn \l_phone_FR_nummerlaenge_int {\str_count:n {#1}}
            
      \int_compare:nNnTF {\l_phone_FR_nummerlaenge_int} < {10}
         {
            \str_if_eq:xnTF {\str_head:n {#1}} {3}
               {
                  \int_compare:nNnTF {\l_phone_FR_nummerlaenge_int} < {4}
                     {
                        \msg_warning:nnnn {phonenumbers} {number~too~short} {French~short} {4}
                        \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
                     }
                     {
                        \int_compare:nNnTF {\l_phone_FR_nummerlaenge_int} > {4}
                           {
                              \msg_warning:nnnn {phonenumbers} {number~too~long} {French~short} {4}
                              \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
                           }
                           {
                              \phone_gruppierte_ziffernfolge_ausgeben:n {#1}
                              \str_put_right:Nn \l_phone_linktext_str {#1}
                           }
                     }
               }
               {
                  \msg_warning:nnnn {phonenumbers} {number~too~short} {French} {10}
                  \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
               }
         }
         {
            \int_compare:nNnTF {\l_phone_FR_nummerlaenge_int} > {10}
               {
                  \msg_warning:nnnn {phonenumbers} {number~too~long} {French} {10}
                  \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
               }
               {
                  \str_if_eq:xnTF {\str_head:n {#1}} {0}
                     {
                        \bool_set_false:N \l_phone_vorwahl_gefunden_bool
            
                        \int_step_inline:nnnn {6} {-1} {2}
                           {
                              \bool_if:nF {\l_phone_vorwahl_gefunden_bool}
                                 {
                                    \int_compare:nT {\l_phone_FR_nummerlaenge_int >= ##1}
                                       {
                                          \str_set:Nx \l_tmpa_str {\str_range:nnn {#1} {1} {##1}}
            
                                          \clist_if_in:NVT \c_phone_FR_vorwahlliste_clist \l_tmpa_str
                                             {
                                                \bool_set_true:N \l_phone_vorwahl_gefunden_bool
            
                                                \phone_FR_vorwahl_ausgeben:V \l_tmpa_str
                                                
                                                \str_set:Nx \l_tmpb_str {\str_range:nnn {#1} {##1 + 1} {-1}}
                                                \phone_gruppierte_ziffernfolge_ausgeben:V \l_tmpb_str
                                                \str_put_right:NV \l_phone_linktext_str \l_tmpb_str
                                             }
                                       }
                                 }
                           }
            
                        \bool_if:nF {\l_phone_vorwahl_gefunden_bool}
                           {
                              \msg_warning:nnn {phonenumbers} {invalid~area~code} {French}
                              \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
                           }
                     }
                     {
                        \msg_warning:nn {phonenumbers/FR} {missing~zero}
                        \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
                     }
               }
         }
   }

\cs_generate_variant:Nn \phone_FR_nummer_ausgeben:n {V}


%%%%%%%%%%%%%%%%%%%% NORDAMERIKA %%%%%%%%%%%%%%%%%%%%

\file_input:n {US_Vorwahlen}
\file_input:n {US_Ortsnamen}

\clist_new:N \c_phone_US_vorwahlliste_clist
\clist_concat:NNN \c_phone_US_vorwahlliste_clist \c_phone_US_ortsvorwahlliste_clist \c_phone_US_sondervorwahlliste_clist

\msg_new:nnn {phonenumbers} {US/illegal~home~area~code}
   {
      10-digit~dialling~is~required~in~\tl_use:c {c_phone_US_ortsname_#1_tl}.~#1~cannot~be~set~as~home~area~code~\msg_line_context:.
   }

\msg_new:nnn {phonenumbers} {US/invalid~area~code}
   {
      unknown~area~code~#1~in~American~phone~number~\msg_line_context:
   }

\msg_new:nnn {phonenumbers} {US/invalid~central~office~code}
   {
      invalid~central~office~code~#1~in~American~phone~number~\msg_line_context:
   }

\bool_new:N \l_phone_US_ferngespraechspraefix_bool

\keys_define:nn {phonenumbers}
   {
      trunk-prefix .choices:nn = {on,off}
         {
            \str_if_eq:VnTF \l_keys_choice_tl {on}
               {
                  \bool_set_true:N \l_phone_US_ferngespraechspraefix_bool
               }
               {
                  \bool_set_false:N \l_phone_US_ferngespraechspraefix_bool
               }
         },
      trunk-prefix .initial:n = off,
      trunk-prefix .default:n = on
   }


% #1: Heimatvorwahl
\cs_new:Npn \phone_US_heimatvorwahl_festlegen:n #1
   {
      \clist_if_in:NnTF {\c_phone_US_ortsvorwahlliste_clist} {#1}
         {
            \clist_if_in:NnTF {\c_phone_US_ortsvorwahlliste_ten_digits_clist} {#1}
               {
                  % 10-Ziffern-Wählen erforderlich:
                  \msg_warning:nnn {phonenumbers/US} {illegal~home~area~code} {#1}
               }
               {
                  % 7-Ziffern-Wählen möglich, Heimatvorwahl setzen:
                  \str_set:Nn \l_phone_heimatland_str {US}
                  \str_set:Nn \l_phone_heimatvorwahl_str {#1}
                  \msg_info:nnnv {phonenumbers} {home~area~code~set} {#1} {c_phone_US_ortsname_#1_tl}
               }
         }
         {
            % keine gültige Ortsvorwahl:
            \msg_warning:nnnn {phonenumbers} {invalid~home~area~code} {#1} {American}
         }
   }

% #1: Vorwahl, #2: Folgt eine Rufnummer?
\cs_new:Npn \phone_US_vorwahl_ausgeben:nN #1 #2
   {
      \str_if_eq:VnTF \l_phone_auslandsvorwahltyp_str {off}
         {
            \bool_if:nF {\str_if_eq_p:Vn \l_phone_heimatland_str {US} && \str_if_eq_p:Vn \l_phone_heimatvorwahl_str {#1}}
               {
                  \bool_if:NTF \l_phone_US_ferngespraechspraefix_bool
                     {
                        \bool_if:NTF #2
                           {
                              \str_if_eq:VnTF \l_phone_vorwahltrennung_str {space}
                                 {
                                    \tl_put_right:Nn \l_phone_ausgabetext_tl {1 \c_space_tl #1 \c_space_tl}
                                 }
                                 {
                                    \tl_put_right:Nn \l_phone_ausgabetext_tl {1 \c_phone_bindestrich_tl #1 \c_phone_bindestrich_tl}
                                 }
                           }
                           {
                              \str_if_eq:VnTF \l_phone_vorwahltrennung_str {space}
                                 {
                                    \tl_put_right:Nn \l_phone_ausgabetext_tl {1 \c_space_tl #1}
                                 }
                                 {
                                    \tl_put_right:Nn \l_phone_ausgabetext_tl {1 \c_phone_bindestrich_tl #1}
                                 }
                           }
                     }
                     {
                        \clist_if_in:NnT \c_phone_US_sondervorwahlliste_clist {#1}
                           {
                              \str_if_eq:VnT \l_phone_vorwahldarstellung_str {place}
                                 {
                                    \str_set:Nn \l_phone_vorwahldarstellung_str {number}
                                 }
                           }
      
                        \tl_put_right:Nx \l_phone_ausgabetext_tl
                           {
                              \str_case:Vn \l_phone_vorwahldarstellung_str
                                 {
                                    {number}
                                       {
                                          \bool_if:NTF #2
                                             {
                                                \str_case:VnF \l_phone_vorwahltrennung_str
                                                   {
                                                      {brackets} {(#1) \c_space_tl}
                                                      {space} {#1 \c_space_tl}
                                                   }
                                                   {
                                                      #1 \c_phone_bindestrich_tl
                                                   }
                                             }
                                             {
                                                #1
                                             }
                                       }
                                    {place}
                                       {
                                          \bool_if:NTF #2
                                             {
                                                \str_case:VnF \l_phone_vorwahltrennung_str
                                                   {
                                                      {brackets}
                                                         {
                                                            (
                                                            \tl_if_exist:cTF {c_phone_US_ortsname_#1_tl}
                                                               {
                                                                  \tl_use:c {c_phone_US_ortsname_#1_tl}
                                                               }
                                                               {
                                                                  #1
                                                               }
                                                            )
                                                            \c_space_tl
                                                         }
                                                   }
                                                   {
                                                      \tl_if_exist:cTF {c_phone_US_ortsname_#1_tl}
                                                         {
                                                            \tl_use:c {c_phone_US_ortsname_#1_tl}
                                                            \c_space_tl
                                                         }
                                                         {
                                                            #1 \c_phone_bindestrich_tl
                                                         }
                                                   }
                                             }
                                             {
                                                \tl_if_exist:cTF {c_phone_US_ortsname_#1_tl}
                                                   {
                                                      \tl_use:c {c_phone_US_ortsname_#1_tl}
                                                   }
                                                   {
                                                      #1
                                                   }
                                             }
                                       }
                                    {place-and-number}
                                       {
                                          \tl_if_exist:cT {c_phone_US_ortsname_#1_tl}
                                             {
                                                \tl_use:c {c_phone_US_ortsname_#1_tl}
                                                \c_space_tl
                                             }
            
                                          \bool_if:NTF #2
                                             {
                                                \str_case:VnF \l_phone_vorwahltrennung_str
                                                   {
                                                      {brackets} {(#1) \c_space_tl}
                                                      {space} {#1 \c_space_tl}
                                                   }
                                                   {
                                                      #1 \c_phone_bindestrich_tl
                                                   }
                                             }
                                             {
                                                \str_if_eq:VnTF \l_phone_vorwahltrennung_str {brackets}
                                                   {
                                                      (#1)
                                                   }
                                                   {
                                                      #1
                                                   }
                                             }
                                       }
                                 }
                           }
                     }
               }
         }
         {
            \phone_auslandsvorwahl_ausgeben:n {1}

            \tl_put_right:Nn \l_phone_ausgabetext_tl {\c_space_tl #1}

            \bool_if:NT #2
               {
                  \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
               }
         }

      % Linktext schreiben, falls eine Rufnummer folgt
      \bool_if:NT #2
         {
            \str_put_right:Nn \l_phone_linktext_str {+1 #1}
         }
   }

\cs_generate_variant:Nn \phone_US_vorwahl_ausgeben:nN {VN}


% #1: Ortsvorwahl, #2: Vermittlungsstellennummer
\cs_new:Npn \phone_US_vermittlungsstellennummer_ausgeben:nn #1 #2
   {
      \str_case:xnTF {\str_head:n {#2}}
         {
            {0} { }
            {1} { }
         }
         {
            \msg_warning:nnn {phonenumbers/US} {invalid~central~office~code} {#2}
         }
         {
            \bool_set_false:N \l_tmpa_bool % Regionalnummer?

            \tl_if_empty:nTF {#1}
               {
                  \bool_set_true:N \l_tmpa_bool
               }
               {
                  \clist_if_in:NnT \c_phone_US_ortsvorwahlliste_clist {#1}
                     {
                        \bool_set_true:N \l_tmpa_bool
                     }
               }

            \bool_if:NTF \l_tmpa_bool
               {
                  \str_if_eq:xnT {\str_range:nnn {#2} {2} {3}} {11}
                     {
                        \msg_warning:nnn {phonenumbers/US} {invalid~central~office~code} {#2}
                     }
               }
               {
                  \str_if_eq:nnT {#2} {911}
                     {
                        \msg_warning:nnn {phonenumbers/US} {invalid~central~office~code} {#2}
                     }
               }
         }

      \tl_put_right:Nn \l_phone_ausgabetext_tl {#2}

      \str_if_eq:VnTF \l_phone_auslandsvorwahltyp_str {off}
         {
            \tl_put_right:NV \l_phone_ausgabetext_tl \c_phone_bindestrich_tl
         }
         {
            \tl_if_empty:nTF {#1}
               {
                  \tl_put_right:NV \l_phone_ausgabetext_tl \c_phone_bindestrich_tl
               }
               {
                  \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl
               }
         }

      % Linktext schreiben, falls eine Vorwahl vorangeht
      \tl_if_empty:nF {#1}
         {
            \str_put_right:Nn \l_phone_linktext_str {#2}
         }
   }

\cs_generate_variant:Nn \phone_US_vermittlungsstellennummer_ausgeben:nn {Vx}


\cs_new:Npn \phone_US_nummer_ausgeben:n #1
   {
      \int_case:nnF {\str_count:n {#1}}
         {
            {3}
               {
                  \clist_if_in:NnTF \c_phone_US_vorwahlliste_clist {#1}
                     {
                        \msg_warning:nnn {phonenumbers} {missing~subscriber~number} {American}
                     }
                     {
                        \msg_warning:nnn {phonenumbers/US} {invalid~area~code} {#1}
                     }

                  \phone_US_vorwahl_ausgeben:nN {#1} \c_false_bool
               }
            {7}
               {
                  \phone_US_vermittlungsstellennummer_ausgeben:Vx \c_empty_tl {\str_range:nnn {#1} {1} {3}}

                  \tl_put_right:Nx \l_phone_ausgabetext_tl {\str_range:nnn {#1} {4} {7}}
               }
            {10}
               {
                  \str_set:Nx \l_tmpa_str {\str_range:nnn {#1} {1} {3}}

                  \clist_if_in:NVF \c_phone_US_vorwahlliste_clist \l_tmpa_str
                     {
                        \msg_warning:nnx {phonenumbers/US} {invalid~area~code} {\l_tmpa_str}
                     }

                  \phone_US_vorwahl_ausgeben:VN \l_tmpa_str \c_true_bool

                  \phone_US_vermittlungsstellennummer_ausgeben:Vx \l_tmpa_str {\str_range:nnn {#1} {4} {6}}

                  \tl_put_right:Nx \l_phone_ausgabetext_tl {\str_range:nnn {#1} {7} {10}}
                  \str_put_right:Nx \l_phone_linktext_str {\str_range:nnn {#1} {7} {10}}
               }
         }
         {
            \int_compare:nNnTF {\str_count:n {#1}} < {10}
               {
                  \msg_warning:nnnn {phonenumbers} {number~too~short} {American} {10}
               }
               {
                  \msg_warning:nnnn {phonenumbers} {number~too~long} {American} {10}
               }

            \tl_put_right:Nn \l_phone_ausgabetext_tl {#1}
         }
   }

\cs_generate_variant:Nn \phone_US_nummer_ausgeben:n {V}


\ProcessKeysPackageOptions {phonenumbers}
