% Copyright 2022 by Qrrbrbirlbel
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Free Documentation License.
%
\pgfqkeys{/pgf/calendar}{
    style/.style={#1},
    yesterday/.value required,
    yesterday/.code={%
      \begingroup
        \pgfutil@tempcnta=\pgfcalendarifdatejulian\relax
        \advance\pgfutil@tempcnta by -1\relax
        \pgfcalendarjuliantodate{\pgfutil@tempcnta}{\pgfcalendarifdateyear}{\pgfcalendarifdatemonth}{\pgfcalendarifdateday}%
        \edef\pgfcalendarifdatejulian{\the\pgfutil@tempcnta}%
        \pgfcalendarjuliantoweekday\pgfutil@tempcnta\pgfutil@tempcntb
        \edef\pgfcalendarifdateweekday{\the\pgfutil@tempcntb}%
        \pgfcalendarjulianyeartoweek\pgfutil@tempcnta\pgfcalendarifdateyear\pgfutil@tempcntb
        \edef\pgfcalendarifdateweek{\the\pgfutil@tempcntb}%
        \pgfcalendar@launch@ifdate{#1}{%
          \def\pgf@cal@temp{\pgfcalendarmatchestrue}%
        }{%
          \let\pgf@cal@temp\pgfutil@empty
        }%
        \expandafter
      \endgroup\pgf@cal@temp
    },
    Jan/.code={\ifnum\pgfcalendarifdatemonth=1 \expandafter\pgfcalendarmatchestrue\fi},Jan/.value forbidden,
    Feb/.code={\ifnum\pgfcalendarifdatemonth=2 \expandafter\pgfcalendarmatchestrue\fi},Feb/.value forbidden,
    Mar/.code={\ifnum\pgfcalendarifdatemonth=3 \expandafter\pgfcalendarmatchestrue\fi},Mar/.value forbidden,
    Apr/.code={\ifnum\pgfcalendarifdatemonth=4 \expandafter\pgfcalendarmatchestrue\fi},Apr/.value forbidden,
    May/.code={\ifnum\pgfcalendarifdatemonth=5 \expandafter\pgfcalendarmatchestrue\fi},May/.value forbidden,
    Jun/.code={\ifnum\pgfcalendarifdatemonth=6 \expandafter\pgfcalendarmatchestrue\fi},Jun/.value forbidden,
    Jul/.code={\ifnum\pgfcalendarifdatemonth=7 \expandafter\pgfcalendarmatchestrue\fi},Jul/.value forbidden,
    Aug/.code={\ifnum\pgfcalendarifdatemonth=8 \expandafter\pgfcalendarmatchestrue\fi},Aug/.value forbidden,
    Sep/.code={\ifnum\pgfcalendarifdatemonth=9 \expandafter\pgfcalendarmatchestrue\fi},Sep/.value forbidden,
    Oct/.code={\ifnum\pgfcalendarifdatemonth=10 \expandafter\pgfcalendarmatchestrue\fi},Oct/.value forbidden,
    Nov/.code={\ifnum\pgfcalendarifdatemonth=11 \expandafter\pgfcalendarmatchestrue\fi},Nov/.value forbidden,
    Dec/.code={\ifnum\pgfcalendarifdatemonth=12 \expandafter\pgfcalendarmatchestrue\fi},Dec/.value forbidden,
    %
    difference between/.code args={#1and#2 #3 #4}{%
      \pgfcalendardatetojulian{#1}\pgfutil@tempcnta
      \pgfcalendardatetojulian{#2}\pgfutil@tempcntb
      \advance\pgfutil@tempcntb by -\pgfutil@tempcnta
      \ifnum\pgfutil@tempcntb#3#4\relax
        \pgfcalendarmatchestrue
      \fi},
    weekday before or same/.code args={#1and#2}{%
      \pgfcalendarjuliantoweekday{#1}\pgfutil@tempcnta
      \pgfcalendarjuliantoweekday{#2}\pgfutil@tempcntb
      \ifnum\pgfutil@tempcntb<\pgfutil@tempcnta
        \pgfcalendarmatchestrue
      \fi
    },
    leap year/.code={%
        \pgfutil@tempcnta=#1\relax
        \divide\pgfutil@tempcnta4
        \multiply\pgfutil@tempcnta4
        \ifnum\pgfutil@tempcnta=#1\relax
            \divide\pgfutil@tempcnta100
            \multiply\pgfutil@tempcnta100
            \ifnum\pgfutil@tempcnta=#1\relax
                \divide\pgfutil@tempcnta400
                \multiply\pgfutil@tempcnta400
                \ifnum\pgfutil@tempcnta=#1\relax
                    \pgfcalendarmatchestrue
                \fi
            \else
                \pgfcalendarmatchestrue
            \fi
        \fi},
    leap year/.default=\pgfcalendarifdateyear,
    between days/.code args={#1and#2}{%
        \pgfutil@tempcnta=#1\relax
        \ifnum\pgfcalendarifdateday<\pgfutil@tempcnta\else
            \pgfutil@tempcnta=#2\relax
            \ifnum\pgfcalendarifdateday>\pgfutil@tempcnta\else
                \pgfcalendarmatchestrue\fi\fi},
    week of month/.code={%
        \pgfutil@tempcnta=#1\relax
        \multiply\pgfutil@tempcnta7
        \ifnum\pgfcalendarifdateday>\pgfutil@tempcnta\else
            \advance\pgfutil@tempcnta-7
            \ifnum\pgfcalendarifdateday>\pgfutil@tempcnta
                \pgfcalendarmatchestrue
            \fi
        \fi},
    week of month'/.code={%
        \pgfcalendar@getlastYMX\pgfcalendarifdateyear\pgfcalendarifdatemonth\pgfutil@tempcnta
        \advance\pgfutil@tempcnta1
        \pgfutil@tempcntb=#1\relax
        \multiply\pgfutil@tempcntb7
        \advance\pgfutil@tempcnta-\pgfutil@tempcntb
        \ifnum\pgfcalendarifdateday<\pgfutil@tempcnta\else
            \advance\pgfutil@tempcnta+7
            \ifnum\pgfcalendarifdateday<\pgfutil@tempcnta
                \pgfcalendarmatchestrue
            \fi
        \fi},
    first/.code={\pgfutil@in@:{#1}\ifpgfutil@in@
        \pgfcalendar@ifdate@first{}#1\pgf@stop\else
        \pgfcalendar@ifdate@first{}1:#1\pgf@stop\fi},
    last/.code={\pgfutil@in@:{#1}\ifpgfutil@in@
        \pgfcalendar@ifdate@first'#1\pgf@stop\else
        \pgfcalendar@ifdate@first'1:#1\pgf@stop\fi},
    % logic
    not/.value required,
    not/.code=%
        \begingroup
            \let\pgf@cal@tempa\pgfutil@empty
            \pgfcalendar@launch@ifdate{#1}{}{\def\pgf@cal@tempa{\pgfcalendarmatchestrue}}%
        \expandafter\endgroup\pgf@cal@tempa,
    and/.value required,
    and/.code=% and = {<cond 1>, <cond 2>, <cond 3>, …}
      \begingroup
        \pgfcalendarmatchestrue
        \pgfqkeys{/pgf/calendar/and}{#1}%
        \ifpgfcalendarmatches % is it still true?
          \expandafter\pgfutil@firstoftwo
        \else
          \expandafter\pgfutil@secondoftwo
        \fi
        {\def\pgf@cal@temp{\pgfcalendarmatchestrue}}%
        {\let\pgf@cal@temp\pgfutil@empty}%
      \expandafter\endgroup\pgf@cal@temp,
    and/.unknown/.code=% only inside the group of and/.code
      \ifpgfcalendarmatches
        \expandafter\pgfutil@firstofone
      \else
        \expandafter\pgfutil@gobble
      \fi
      {%
        \begingroup
          \pgfcalendar@launch@ifdate{\pgfkeyscurrentname={#1}}%
          {\let\pgf@cal@temp\pgfutil@empty}{\def\pgf@cal@temp{\pgfcalendarmatchesfalse}}
        \expandafter\endgroup\pgf@cal@temp
      }%
}

\def\pgfcalendar@ifdate@first#1#2:#3\pgf@stop{%
    \pgfqkeys{/pgf/calendar}{and={#3, week of month#1={#2}}}}
\def\pgfcalendar@getlastYMX#1#2#3{% #1 = year, #2 = month, #3 := last day
    \begingroup
        \ifnum#2=2 % stupid February
            \pgfcalendarmatchesfalse
            \pgfqkeys{/pgf/calendar}{leap year={#1}}%
            \ifpgfcalendarmatches
              #3=29
            \else
              #3=28
            \fi
        \else
            #3=\ifcase#2\relax\or
            31\or\or31\or30\or31\or30\or31\or31\or30\or31\or30\or31\fi
        \fi
        \edef\pgf@cal@temp{#3=\the#3\relax}
      \expandafter
    \endgroup\pgf@cal@temp}

%
% weeks
%
\def\pgfcalendar@week@setup#1{%
  \pgfutil@IfUndefined{pgfcalendar@week@#1}{%
    \begingroup
      \pgfcalendardatetojulian{#1-01-01}\pgfutil@tempcnta
      \pgfcalendarjuliantoweekday\pgfutil@tempcnta\pgfutil@tempcntb
      %
      % tempcnta holds the julian number for first day of the current year
      % tempcntb holds the weekday for the first day of the current year
      %
      % set tempcnta to the Monday of the week with first day of current year
      \advance\pgfutil@tempcnta by -\pgfutil@tempcntb
      %
      % if the first week starts at Fri, Sat or Sun, next week is the 1st week
      \ifnum\pgfutil@tempcntb>3\relax
        \advance\pgfutil@tempcnta by 7\relax
      \fi
      % setup macro for year with {Julian number for day of first week}{weekday of -01-01}
      \edef\pgf@cal@temp{\def\expandafter\noexpand\csname pgfcalendar@week@#1\endcsname
        {{\the\pgfutil@tempcnta}{\the\pgfutil@tempcntb}}}%
      \expandafter\endgroup\pgf@cal@temp
  }{}%
}

\def\pgfcalendarjulianyeartoweek#1#2#3{\pgfcalendarjulianyeartoweek@{#1}{#2}{#3}{\iftrue}}
\def\pgfcalendarjulianyeartoweek@#1#2#3#4{%
  % #1 = julian date (count)
  % #2 = year
  % #3 = count that holds the week at the end
  % #4 = \iftrue or \iffalse: whether week 53 needs to be checked (\iffalse when determing week from next year)
  \begingroup
    \pgfcalendar@week@setup{#2}%
    #3=#1\relax
    %
    % calculate difference of days between current date and start of week 1
    %
    \advance#3 by -\expandafter\expandafter\expandafter\pgfutil@firstoftwo\csname pgfcalendar@week@#2\endcsname\relax
    \ifnum#3<0\relax % whoops, we are in the week of the previous year
      \expandafter\pgfutil@firstoftwo
    \else
      \expandafter\pgfutil@secondoftwo
    \fi
    {% if first day of the year is Fri, Sat or Sun
      \ifnum\expandafter\expandafter\expandafter\pgfutil@secondoftwo\csname pgfcalendar@week@#2\endcsname>3\relax
        \expandafter\pgfutil@firstoftwo
      \else
        \expandafter\pgfutil@secondoftwo
      \fi
      {% we need to check the week of the previous year
        #3=#2\relax
        \advance#3 by -1
        \edef\pgf@cal@temp{\noexpand\pgfcalendarjulianyeartoweek@#1{\the#3}#3\noexpand\iffalse}%
        \pgf@cal@temp
      }{% yeah, it's weird
        \divide#3 by 7
        \advance#3 by 1        
      }
    }{%
      \divide#3 by 7
      \advance#3 by 1
      #4%
        \expandafter\pgfutil@firstofone
      \else
        \expandafter\pgfutil@gobble
      \fi
      {%
        \ifnum#3=53\relax % whoops, we are possibly in the first week of the next year
            \expandafter\pgfutil@firstofone
        \else
            \expandafter\pgfutil@gobble
        \fi
        {%
          \begingroup
            % check whether we're already in week 1 of the next year
            #3=#2\relax
            \advance#3 by 1
            \expandafter\pgfcalendar@week@setup\expandafter{\the#3}%
            \ifnum#1<\expandafter\expandafter\expandafter\pgfutil@firstoftwo\csname pgfcalendar@week@\the#3\endcsname\relax
              #3=53
            \else
              #3=1
            \fi
            \expandafter
          \endgroup\expandafter#3\the#3\relax
        }%
      }%
    }%
    \expandafter
  \endgroup\expandafter
  #3\the#3\relax
}

%
% shorthands for weeks (n)
%
% n-: shortest
% n=: shortest but prepends whitespace
% n0: leading zero
%
\expandafter\def\csname pgfcalendar@shorthand@n-\endcsname{%
  \if0\pgfcalendarcurrentweek\else\pgfcalendarcurrentweek\fi}
\expandafter\def\csname pgfcalendar@shorthand@n=\endcsname{%
  {\pgfutil@tempcnta=\pgfcalendarcurrentweek\relax\ifnum\pgfutil@tempcnta<10\relax\setbox0=\hbox{1}\kern\wd0\relax\fi\the\pgfutil@tempcnta}}
\expandafter\def\csname pgfcalendar@shorthand@n0\endcsname{%
  \pgfcalendarcurrentweek}

%
% Overwriting original \pgfcalendar
%
\long\def\pgfcalendar#1#2#3#4{%
  \begingroup%
    % Setup local \ifdate
    \let\ifdate=\pgfcalendar@local@ifdate%
    % Let's start with computing start and end dates...
    \def\pgfcalendarprefix{#1}%
    \pgfcalendardatetojulian{#2}{\pgfcalendarcurrentjulian}%
    \edef\pgfcalendarbeginjulian{\the\pgfcalendarcurrentjulian}%
    \edef\pgfcalendarbeginiso{#2}%
    \pgfcalendardatetojulian{#3}{\pgfutil@tempcnta}%
    \edef\pgfcalendarendjulian{\the\pgfutil@tempcnta}%
    \advance\pgfutil@tempcnta by1\relax%
    \edef\pgfcalendarendjulianplus{\the\pgfutil@tempcnta}%
    \edef\pgfcalendarendiso{#3}%
    %
    % Start main loop
    %
    \loop%
    \ifnum\pgfcalendarcurrentjulian<\pgfcalendarendjulianplus\relax%
      % Setup information about current date
      \pgfcalendarjuliantodate{\pgfcalendarcurrentjulian}%
        {\pgfcalendarcurrentyear}{\pgfcalendarcurrentmonth}{\pgfcalendarcurrentday}%
      \pgfcalendarjuliantoweekday{\pgfcalendarcurrentjulian}{\pgfutil@tempcntb}%
      \edef\pgfcalendarcurrentweekday{\the\pgfutil@tempcntb}%
      \pgfcalendarjulianyeartoweek{\pgfcalendarcurrentjulian}{\pgfcalendarcurrentyear}{\pgfutil@tempcntb}%
      \edef\pgfcalendarcurrentweek{\ifnum\pgfutil@tempcntb<10 0\fi\the\pgfutil@tempcntb}%
      % Render:
      #4%
      % Advance day:
      \advance\pgfcalendarcurrentjulian by1\relax%
    \repeat%
  \endgroup%
}

%
% Overwriting original \pgfcalendar@local@ifdate
%
\def\pgfcalendar@local@ifdate{%
  \let\pgfcalendarifdatejulian=\pgfcalendarcurrentjulian
  \let\pgfcalendarifdateyear=\pgfcalendarcurrentyear
  \let\pgfcalendarifdatemonth=\pgfcalendarcurrentmonth
  \let\pgfcalendarifdateday=\pgfcalendarcurrentday
  \let\pgfcalendarifdateweekday=\pgfcalendarcurrentweekday
  \let\pgfcalendarifdateweek=\pgfcalendarcurrentweek
  \pgfcalendar@launch@ifdate%
}

\pgfqkeys{/pgf/calendar/week}{.value required,.code=\ifnum#1=\pgfcalendarifdateweek\relax\expandafter\pgfcalendarmatchestrue\fi}

% Overwriting shorthands of pgfcalendar
\expandafter\def\csname pgfcalendar@shorthand@d-\endcsname{%
  \if0\pgfcalendarcurrentday\else\pgfcalendarcurrentday\fi}
\expandafter\def\csname pgfcalendar@shorthand@m-\endcsname{%
  \if0\pgfcalendarcurrentmonth\else\pgfcalendarcurrentmonth\fi}

\endinput