% --------------------------------------------------------------------------
% the BOHR package
% 
%   simple atom representation according to the Bohr model
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://bitbucket.org/cgnieder/bohr/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2012-2015 Clemens Niederberger
% 
% 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.
% 
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
\newcommand*\@bohr@date{2015/06/24}
\newcommand*\@bohr@version{v1.0}
\newcommand*\@bohr@description{simple atom representation according to the Bohr model}

\ProvidesPackage{bohr}[\@bohr@date\space \@bohr@version\space \@bohr@description]
\RequirePackage{tikz,pgfopts,elements}

% --------------------------------------------------------------------------
% message handling
\newcommand*\@bohr@error@message{%
  For details have a look at the `bohr' manual.%
}

\newrobustcmd*\@bohr@error[1]{\PackageError{bohr}{#1}{#1 \@bohr@error@message}}
\newrobustcmd*\@bohr@warning[1]{\PackageWarning{bohr}{#1}}
\newrobustcmd*\@bohr@warningnoline[1]{\PackageWarningNoLine{bohr}{#1}}
\newrobustcmd*\@bohr@info[1]{\PackageInfo{bohr}{#1}}

\newrobustcmd*\@bohr@expand@arg[2]{%
  \edef\@bohr@tmpa{{#2}}%
  \expandafter#1\@bohr@tmpa
}

\newrobustcmd*\@bohr@expand@second@arg[3]{%
  \edef\@bohr@tmpa{{#3}}%
  \def\@bohr@tmpb{{#2}}%
  \expandafter\expandafter\expandafter#1\expandafter\@bohr@tmpb\@bohr@tmpa
}

% --------------------------------------------------------------------------
% options
\newcommand*\@bohr@name@options{}
\newcommand*\@bohr@write@atom[1]{#1}
\newcommand*\@bohr@nucleus@radius{1em}
\newcommand*\@bohr@electron@options{blue!50!black!50}
\newcommand*\@bohr@electron@radius{1.5pt}
\newcommand*\@bohr@shell@dist{1em}
\newcommand*\@bohr@nucleus@options{draw=black!80,fill=black!10,opacity=.25}
\newcommand*\@bohr@shell@options{draw=blue!75,thin}

\newbool{bohr@insert@symbol}
\newbool{bohr@insert@number}

\newcommand*\@bohr@insert@symbol[2]{%
  \ifbool{bohr@insert@symbol}
    {%
      \ifblank{#2}
        {\@elements@get@atom@symbol{#1}}
        {\@bohr@write@atom{#2}}%
    }
    {\@bohr@write@atom{#2}}%
}

\newcommand\@bohr@add@options@to[2]{%
  \edef#1{\expandonce#1,\unexpanded{#2}}%
}

\newcommand*\@bohr@option@deprecated[2]{%
  \@bohr@warning{option `#1' has deprecated, use `#2' instead}%
}

\pgfkeys{
  bohr/.cd,
    insert-symbol/.is if       = bohr@insert@symbol ,
    insert-number/.is if       = bohr@insert@number ,
    insert-missing/.is choice,
    insert-missing/true/.code  =
      \booltrue{bohr@insert@symbol}\booltrue{bohr@insert@number} ,
    insert-missing/false/.code =
      \boolfalse{bohr@insert@symbol}\boolfalse{bohr@insert@number} ,
    insert-missing/.default    = true ,
    atom-style/.code           = \def\@bohr@write@atom{#1} ,
    name-options-set/.code     = \def\@bohr@name@options{#1} ,
    name-options-add/.code     =
      \@bohr@add@options@to\@bohr@name@options{#1} ,
    nucleus-radius/.code       = \def\@bohr@nucleus@radius{#1} ,
    nucleus-options-set/.code  = \def\@bohr@nucleus@options{#1} ,
    nucleus-options-add/.code  =
      \@bohr@add@options@to\@bohr@nucleus@options{#1} ,
    electron-radius/.code      = \def\@bohr@electron@radius{#1} ,
    electron-options-set/.code = \def\@bohr@electron@options{#1} ,
    electron-options-add/.code =
      \@bohr@add@options@to\@bohr@electron@options{#1} ,
    shell-dist/.code           = \def\@bohr@shell@dist{#1} ,
    shell-options-set/.code    = \def\@bohr@shell@options{#1} ,
    shell-options-add/.code    =
      \@bohr@add@options@to\@bohr@shell@options{#1} ,
    german/.code               = \def\@bohr@language{german} ,
    ngerman/.code              = \def\@bohr@language{german} ,
    french/.code               = \def\@bohr@language{french} ,
    frenchb/.code              = \def\@bohr@language{french} ,
    language/.code             = \def\@bohr@language{#1} ,
    distribution-method/.is choice ,
    distribution-method/periodic/.code =
      \def\@bohr@draw@electrons{\@bohr@draw@electrons@periodic}
      \def\@bohr@get@shell@num{\@bohr@get@shell@num@periodic} ,
    distribution-method/quantum/.code =
      \def\@bohr@draw@electrons{\@bohr@draw@electrons@quantum}
      \def\@bohr@get@shell@num{\@bohr@get@shell@num@quantum}
}

\newrobustcmd\setbohr[1]{\pgfqkeys{/bohr}{#1}}

\setbohr{distribution-method=quantum}

\ProcessPgfOptions*

% --------------------------------------------------------------------------
% the \bohr command
%   optional #1: number of shells
%   #2: number of electrons
%   #3: atom name
\newrobustcmd*\bohr[3][]{\@bohr{#1}{#2}{#3}}

\newcommand*\@bohr[3]{%
  \ifblank{#2}% electron number given ?
    {% no
      \ifboolexpr{ bool {bohr@insert@number} and test {\ifblank{#3}} }
        {%
          \@bohr@error{I can't insert the electron number. You haven't
            specified the element.}%
        }{%
          \ifboolexpr
            {
              bool {bohr@insert@number} and not
              test {\lowercase{\ifcsvoid{@elements@atom@number@#3}}}
            }
            {%
              \lowercase{%
                \def\@bohr@electron@current@number{\csuse{@elements@atom@number@#3}}}%
            }{%
              \@bohr@error{You must specify an electron number, possibly 0.}%
            }%
        }%
    }{% yes
      \ifnum#2<0\relax
        \@bohr@error{The electron number cannot be negative!}%
      \else
        \ifnum#2>112\relax
          \@bohr@warning{I only know atoms up to 112 (Copernicium). You
            gave me #2 so I am using 112 instead.}
          \def\@bohr@electron@current@number{112}%
        \else
          \def\@bohr@electron@current@number{#2}%
        \fi
      \fi
    }%
  \ifblank{#1}
    {\@bohr@get@shell@num{\@bohr@electron@current@number}}
    {
      \@bohr@get@shell@num{\@bohr@electron@current@number}%
      \ifnum#1<\@bohr@shell@num
        \@bohr@warning{The shell number you provided (#1) is too small for the
          electron number you provided (\@bohr@electron@current@number)! I'll
          use \@bohr@shell@num\space shells.}%
      \else
        \ifnum#1>7\relax
          \@bohr@warning{I know only of 7 electron shells. You gave me #1 so I'll
            be using 7 instead.}
          \def\@bohr@shell@num{7}%
        \else
          \def\@bohr@shell@num{#1}%
        \fi
      \fi
    }%
  \tikzpicture[baseline=(nucleus.base)]
    \expandafter\node\expandafter[\@bohr@name@options]
      (nucleus) at (0,0) {\@bohr@insert@symbol{\@bohr@electron@current@number}{#3}} ;
    \expandafter\draw\expandafter[\@bohr@nucleus@options]
      (nucleus) circle (\@bohr@nucleus@radius) ;
    \foreach\@bohr@current@shell@num in {1,...,\@bohr@shell@num}
      {
        \expandafter\draw\expandafter[\@bohr@shell@options]
          (nucleus) circle (\@bohr@nucleus@radius+\@bohr@current@shell@num*\@bohr@shell@dist) ;
      }
    \@bohr@draw@electrons{\@bohr@electron@current@number}
  \endtikzpicture
}

\newcommand*\@bohr@get@shell@num@periodic[1]{%
  \ifnum#1<3\relax
    \def\@bohr@shell@num{1}%
  \else
    \ifnum#1<11\relax
      \def\@bohr@shell@num{2}%
    \else
      \ifnum#1<19\relax
        \def\@bohr@shell@num{3}%
      \else
        \ifnum#1<37\relax
          \def\@bohr@shell@num{4}%
        \else
          \ifnum#1<55\relax
            \def\@bohr@shell@num{5}%
          \else
            \ifnum#1<87\relax
              \def\@bohr@shell@num{6}%
            \else
              \def\@bohr@shell@num{7}%
            \fi
          \fi
        \fi
      \fi
    \fi
  \fi
}

\newrobustcmd*\@bohr@distribute@electrons[4]{%
  \pgfmathparse{int(#2)}%
  \let\@bohr@last@electron\pgfmathresult
  \ifnum\@bohr@last@electron=0\relax
  \else
    \foreach\@bohr@electron@number in {#1,...,\@bohr@last@electron}
      {
        \expandafter\fill\expandafter[\@bohr@electron@options] (nucleus)
          ++(#3*\@bohr@electron@number-#3:\@bohr@nucleus@radius+#4*\@bohr@shell@dist)
          circle (\@bohr@electron@radius) ;
      }
  \fi
}

% the simple model according to periods:
\newcommand*\@bohr@draw@electrons@periodic[1]{%
  \ifnum#1<1\relax\else
    \ifnum#1<3\relax
      \@bohr@distribute@electrons{1}{#1}{180}{1}%
    \else
      \ifnum#1<11\relax
        \@bohr@distribute@electrons{1}{2}{180}{1}%
        \@bohr@distribute@electrons{1}{#1-2}{45}{2}%
      \else
        \ifnum#1<19\relax
          \@bohr@distribute@electrons{1}{2}{180}{1}%
          \@bohr@distribute@electrons{1}{8}{45}{2}%
          \@bohr@distribute@electrons{1}{#1-10}{45}{3}%
        \else
          \ifnum#1<37\relax
            \@bohr@distribute@electrons{1}{2}{180}{1}%
            \@bohr@distribute@electrons{1}{8}{45}{2}%
            \@bohr@distribute@electrons{1}{8}{45}{3}%
            \@bohr@distribute@electrons{1}{#1-18}{20}{4}%
          \else
            \ifnum#1<55\relax
              \@bohr@distribute@electrons{1}{2}{180}{1}%
              \@bohr@distribute@electrons{1}{8}{45}{2}%
              \@bohr@distribute@electrons{1}{8}{45}{3}%
              \@bohr@distribute@electrons{1}{18}{20}{4}%
              \@bohr@distribute@electrons{1}{#1-36}{20}{5}%
            \else
              \ifnum#1<87\relax
                \@bohr@distribute@electrons{1}{2}{180}{1}%
                \@bohr@distribute@electrons{1}{8}{45}{2}%
                \@bohr@distribute@electrons{1}{8}{45}{3}%
                \@bohr@distribute@electrons{1}{18}{20}{4}%
                \@bohr@distribute@electrons{1}{18}{20}{5}%
                \@bohr@distribute@electrons{1}{#1-54}{11.25}{6}%
              \else
                \@bohr@distribute@electrons{1}{2}{180}{1}%
                \@bohr@distribute@electrons{1}{8}{45}{2}%
                \@bohr@distribute@electrons{1}{8}{45}{3}%
                \@bohr@distribute@electrons{1}{18}{20}{4}%
                \@bohr@distribute@electrons{1}{18}{20}{5}%
                \@bohr@distribute@electrons{1}{32}{11.25}{6}%
                \ifnum#1<113\relax
                  \@bohr@distribute@electrons{1}{#1-86}{11.25}{7}%
                \else
                  \@bohr@distribute@electrons{1}{26}{11.25}{7}%
                  \@bohr@warning{%
                    I only know atoms up to 112 (Copernicium). You gave me
                    #1 so I am using 112 instead.%
                  }%
                \fi
              \fi
            \fi
          \fi
        \fi
      \fi
    \fi
  \fi
}

% --------------------------------------------------------------------------
% electron distribution per electron number
\newcounter{@bohr@shell@number}

\newrobustcmd*\@bohr@get@shell@num@quantum[1]{%
  \setcounter{@bohr@shell@number}{0}%
  \@bohr@expand@second@arg\forcsvlist
    {\stepcounter{@bohr@shell@number}\@gobble}
    {\csuse{@elements@electron@distribution@\romannumeral#1}}%
  \edef\@bohr@shell@num{\arabic{@bohr@shell@number}}%
}

\newrobustcmd*\@bohr@draw@electrons@quantum[1]{%
  \@bohr@expand@arg\@bohr@get@shell@electrons
    {\csuse{@elements@electron@distribution@\romannumeral#1}}%
}

\newrobustcmd*\@bohr@get@shell@electrons[1]{%
  \setcounter{@bohr@shell@number}{0}%
  \forcsvlist{\@bohr@draw@shell@electrons}{#1}%
}

\newrobustcmd*\@bohr@draw@shell@electrons[1]{%
  \stepcounter{@bohr@shell@number}%
  \ifnum\value{@bohr@shell@number}=1\relax % n=1
    \@bohr@distribute@electrons{1}{#1}{180}{1}%
  \fi
  \ifnum\value{@bohr@shell@number}=2\relax % n=2
    \@bohr@distribute@electrons{1}{#1}{45}{2}%
  \fi
  \ifnum\value{@bohr@shell@number}=3\relax % n=3
    \ifnum\numexpr#1\relax<9\relax
      \@bohr@distribute@electrons{1}{#1}{45}{3}%
    \else
      \@bohr@distribute@electrons{1}{#1}{20}{3}%
    \fi
  \fi
  \ifnum\value{@bohr@shell@number}=4\relax % n=4
    \ifnum\numexpr#1\relax<9\relax
      \@bohr@distribute@electrons{1}{#1}{45}{4}%
    \else
      \ifnum\numexpr#1\relax<18\relax
        \@bohr@distribute@electrons{1}{#1}{20}{4}%
      \else
        \@bohr@distribute@electrons{1}{#1}{11.25}{4}%
      \fi
    \fi
  \fi
  \ifnum\value{@bohr@shell@number}=5\relax % n=5
    \ifnum\numexpr#1\relax<9\relax
      \@bohr@distribute@electrons{1}{#1}{45}{5}%
    \else
      \ifnum\numexpr#1\relax<18\relax
        \@bohr@distribute@electrons{1}{#1}{20}{5}%
      \else
        \@bohr@distribute@electrons{1}{#1}{11.25}{5}%
      \fi
    \fi
  \fi
  \ifnum\value{@bohr@shell@number}=6\relax % n=6
    \ifnum\numexpr#1\relax<9\relax
      \@bohr@distribute@electrons{1}{#1}{45}{6}%
    \else
      \ifnum\numexpr#1\relax<18\relax
        \@bohr@distribute@electrons{1}{#1}{20}{6}%
      \else
        \@bohr@distribute@electrons{1}{#1}{11.25}{6}%
      \fi
    \fi
  \fi
  \ifnum\value{@bohr@shell@number}=7\relax % n=7
    \@bohr@distribute@electrons{1}{#1}{180}{7}%
  \fi
}

% --------------------------------------------------------------------------

\endinput

% HISTORY
2012/09/21 v0.1a - first version on bitbucket
2012/09/22 v0.2  - added compatibility up to atomic number 112
                 - added the commands \elementname and \elementsymbol with
                   language support German and English
                 - improved error checking
2012/12/30 v0.2c - bug fixes in error checking
2013/07/25 v0.2d - bug fix in warning message
                 - added missing \@bohr@write@atom to \@bohr@insert@symbol
                 - extended language support, added french element names
                 - corrected name of Praseodynium
2013/11/05 v0.3  - draw shell electrons according to main quantum number
                 - French language file
2013/11/10 v0.4  - allow `0' as value in electron distribution => this enables
                   to draw excited states
                 - new commands \setatomname, \setatomsymbol,
                   \setelectrondistribution
                 - new commands \elconf and \writeelconf
                 - \elementsymbol prints symbols according to option
                   `atom-style'
2014/09/29 v0.4a - alias options for `language=german' and `language=french'
2014/11/06 v0.4b - corrected wrong element symbol for Rhenium
2015/06/14 v1.0  -