% 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.
%

\unless\ifcsname tikzextset\endcsname
  \input tikzext-util.tex
\fi

\def\tikzext@nf@write#1{%
  \immediate\write\pgfutil@auxout{%
    \noexpand\expandafter\noexpand\gdef\noexpand\csname tikzext@nf@#1@previous\endcsname
      {\csname tikzext@nf@#1@next\endcsname}%
  }%
}
\pgfkeyssetvalue{/tikz/ext/node family/prefix}{\pgfpictureid-}% no md5
\pgfutil@IfUndefined{mmz@mode}{% \mmz@mode is only defined with memoizable, not with memoizable or nomemoize
  \let\tikzext@nf@save\tikzext@nf@write
}{%
  % #1 = family type + name
  \def\tikzext@nf@save#1{%
    \pgfutil@IfUndefined{tikzext@nf@#1@previous}{%
      \mmzAbort
      \ifmemoize
        \mmzset{after memoization=\tikzext@nf@write{#1}}%
      \else
        \tikzext@nf@write{#1}%
      \fi
    }{%
      \ifdim\csname tikzext@nf@#1@previous\expandafter\endcsname=%
            \csname tikzext@nf@#1@next\endcsname
        \ifmemoize
          \mmzset{after memoization=\tikzext@nf@write{#1}}%
        \else
          \tikzext@nf@write{#1}%
        \fi
      \else
        \mmzAbort
        \ifmemoize
          \mmzset{after memoization=\tikzext@nf@write{#1}}%
        \else
          \tikzext@nf@write{#1}%
        \fi
      \fi
    }%
  }%
}

\def\tikzext@nf@align@left#1{\unhbox#1\hfil}
\def\tikzext@nf@align@center#1{\hfil\unhbox#1\hfil}
\def\tikzext@nf@align@right#1{\hfil\unhbox#1}

\pgfqkeys{/tikz/ext/node family}{
  width/.initial=,
  width/.append style={/pgf/minimum width=ext_nf_width},
  height/.initial=,
  height/.append style={/pgf/minimum height=ext_nf_height},
  size/.code=\pgfqkeys{/tikz/ext/node family}{width={#1},height={#1}},
  text depth/.initial=,
  text height/.initial=,
  text width align/.is choice,
  text width align/left/.code=\let\tikzext@nf@align@action\tikzext@nf@align@left,
  text width align/center/.code=\let\tikzext@nf@align@action\tikzext@nf@align@center,
  text width align/right/.code=\let\tikzext@nf@align@action\tikzext@nf@align@right,
  text width align=center,
  text width/.initial=,
  text/.code=\pgfqkeys{/tikz/ext/node family}{text depth={#1},text height={#1},text width={#1}},
}
\tikzextset{node family/.code=\pgfqkeys{/tikz/ext/node family}{#1}}

% #1 = value to set
% #2 = family type
% #3 = return dimen
\def\tikzext@nf@getandset#1#2#3{%
    % what's our family's name?
    #3=0pt\relax
    \pgfkeysgetvalue{/tikz/ext/node family/#2}\tikzext@nf@familyname
    \pgfutil@ifxempty\tikzext@nf@familyname{% no family to deal with
    }{%
      \edef\tikzext@nf@familyname{\pgfkeysvalueof{/tikz/ext/node family/prefix}\tikzext@nf@familyname}%
      % we need to save the value for the next run
      \pgfutil@IfUndefined{tikzext@nf@#2@\tikzext@nf@familyname @next}{%
        % first time: define first value and install hook at end of picture
        \expandafter\xdef\csname tikzext@nf@#2@\tikzext@nf@familyname @next\endcsname{#1}%
        \edef\tikz@temp{\noexpand\tikzext@nf@save{#2@\tikzext@nf@familyname}}%
        %\expandafter\AtVeryEndDocument\expandafter{\tikz@temp}%
        \expandafter\pgfutil@g@addto@macro\expandafter\tikz@atend@picture\expandafter{\tikz@temp}%
      }{%
        \ifdim\csname tikzext@nf@#2@\tikzext@nf@familyname @next\endcsname<#1\relax
          \expandafter\xdef\csname tikzext@nf@#2@\tikzext@nf@familyname @next\endcsname{#1}%
        \fi
      }%
      \pgfutil@IfUndefined{tikzext@nf@#2@\tikzext@nf@familyname @previous}{% first run, ignore
      }{% set previous value
        #3=\csname tikzext@nf@#2@\tikzext@nf@familyname @previous\endcsname\relax
      }%
    }%
}

% #1 = family type
% #2 = family
\def\tikzext@nf@get#1#2{%
  \pgfutil@IfUndefined{tikzext@nf@#1@\pgfkeysvalueof{/tikz/ext/node family/prefix}#2@previous}
                      {0pt}
                      {\csname tikzext@nf@#1@\pgfkeysvalueof{/tikz/ext/node family/prefix}#2@previous\endcsname}%
}
\def\tikzextnodefamiliesgetwidth{\tikzext@nf@get{width}}
\def\tikzextnodefamiliesgetheight{\tikzext@nf@get{height}}
\def\tikzextnodefamiliesgettextwidth{\tikzext@nf@get{text width}}
\def\tikzextnodefamiliesgettextdepth{\tikzext@nf@get{text depth}}
\def\tikzextnodefamiliesgettextheight{\tikzext@nf@get{text height}}

\pgfdeclareshape{Rectangle}{%
  \savedanchor\northeast{%
    % Calculate x
    %
    % First, is width < minimum width?
    \pgf@x=\the\wd\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
    \advance\pgf@x by 2\pgf@xc%
    % Qrr: family width
    \tikzext@nf@getandset{\the\pgf@x}{width}{\pgfutil@tempdima}%
    \ifdim\pgf@x<\pgfutil@tempdima
      \pgf@x=\pgfutil@tempdima
    \fi
    %
    \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}%
    \ifdim\pgf@x<\pgf@xb%
      % yes, too small. Enlarge...
      \pgf@x=\pgf@xb%
    \fi%
    % Now, calculate right border: .5\wd\pgfnodeparttextbox + .5 \pgf@x + outer sep
    \pgf@x=.5\pgf@x%
    \advance\pgf@x by.5\wd\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}%
    \advance\pgf@x by\pgf@xa%
    % Calculate y
    %
    % First, is height+depth < minimum height?
    \pgf@y=\ht\pgfnodeparttextbox%
    \advance\pgf@y by\dp\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/inner ysep}}%
    \advance\pgf@y by 2\pgf@yc%
    % Qrr: family height
    \tikzext@nf@getandset{\the\pgf@y}{height}{\pgfutil@tempdima}%
    \ifdim\pgf@y<\pgfutil@tempdima
      \pgf@y=\pgfutil@tempdima
    \fi
    %
    \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}%
    \ifdim\pgf@y<\pgf@yb%
      % yes, too small. Enlarge...
      \pgf@y=\pgf@yb%
    \fi%
    % Now, calculate upper border: .5\ht-.5\dp + .5 \pgf@y + outer sep
    \pgf@y=.5\pgf@y%
    \advance\pgf@y by-.5\dp\pgfnodeparttextbox%
    \advance\pgf@y by.5\ht\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}%
    \advance\pgf@y by\pgf@ya%
  }%

  \savedanchor\southwest{%
    % Calculate x
    %
    % First, is width < minimum width?
    \pgf@x=\wd\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
    \advance\pgf@x by 2\pgf@xc%
    % Qrr: family width
    \tikzext@nf@getandset{\the\pgf@x}{width}{\pgfutil@tempdima}%
    \ifdim\pgf@x<\pgfutil@tempdima
      \pgf@x=\pgfutil@tempdima
    \fi
    %
    \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}%
    \ifdim\pgf@x<\pgf@xb%
    % yes, too small. Enlarge...
    \pgf@x=\pgf@xb%
    \fi%
    % Now, calculate left border: .5\wd\pgfnodeparttextbox - .5 \pgf@x - outer sep
    \pgf@x=-.5\pgf@x%
    \advance\pgf@x by.5\wd\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}%
    \advance\pgf@x by-\pgf@xa%
    % Calculate y
    %
    % First, is height+depth < minimum height?
    \pgf@y=\ht\pgfnodeparttextbox%
    \advance\pgf@y by\dp\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/inner ysep}}%
    \advance\pgf@y by 2\pgf@yc%
    % Qrr: family height
    \tikzext@nf@getandset{\the\pgf@y}{height}{\pgfutil@tempdima}%
    \ifdim\pgf@y<\pgfutil@tempdima
      \pgf@y=\pgfutil@tempdima
    \fi
    %
    \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}%
    \ifdim\pgf@y<\pgf@yb%
    % yes, too small. Enlarge...
    \pgf@y=\pgf@yb%
    \fi%
    % Now, calculate upper border: .5\ht-.5\dp - .5 \pgf@y - outer sep
    \pgf@y=-.5\pgf@y%
    \advance\pgf@y by-.5\dp\pgfnodeparttextbox%
    \advance\pgf@y by.5\ht\pgfnodeparttextbox%
    \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}%
    \advance\pgf@y by-\pgf@ya%
  }%
  \inheritbackgroundpath[from=rectangle]
  \inheritbeforebackgroundpath[from=rectangle]
  \inheritbehindforegroundpath[from=rectangle]
  \inheritforegroundpath[from=rectangle]
  \inheritbeforeforegroundpath[from=rectangle]
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{mid}
  \inheritanchor[from=rectangle]{base}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{mid west}
  \inheritanchor[from=rectangle]{base west}
  \inheritanchor[from=rectangle]{north west}
  \inheritanchor[from=rectangle]{south west}
  \inheritanchor[from=rectangle]{east}
  \inheritanchor[from=rectangle]{mid east}
  \inheritanchor[from=rectangle]{base east}
  \inheritanchor[from=rectangle]{north east}
  \inheritanchor[from=rectangle]{south east}
  \inheritanchorborder[from=rectangle]
}

\pgfdeclareshape{Circle}{%
  \savedanchor\centerpoint{% tex/generic/pgf/modules/pgfmoduleshapes.code.tex
    \pgf@x=.5\wd\pgfnodeparttextbox
    \pgf@y=.5\ht\pgfnodeparttextbox
    \advance\pgf@y by-.5\dp\pgfnodeparttextbox
  }%
  \saveddimen\radius{% tex/generic/pgf/modules/pgfmoduleshapes.code.tex
    % Calculate ``height radius''
    \pgf@ya=.5\ht\pgfnodeparttextbox
    \advance\pgf@ya by.5\dp\pgfnodeparttextbox
    \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}%
    \advance\pgf@ya by\pgf@yb
    % Calculate ``width radius''
    \pgf@xa=.5\wd\pgfnodeparttextbox
    \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
    \advance\pgf@xa by\pgf@xb
    % Calculate length of radius vector:
    \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}%
    \ifdim\pgf@x>\pgf@y
        \c@pgf@counta=\pgf@x
        \ifnum\c@pgf@counta=0\relax
        \else
          \divide\c@pgf@counta by 255\relax
          \pgf@xa=16\pgf@xa\relax
          \divide\pgf@xa by\c@pgf@counta
          \pgf@xa=16\pgf@xa\relax
        \fi
      \else
        \c@pgf@counta=\pgf@y
        \ifnum\c@pgf@counta=0\relax
        \else
          \divide\c@pgf@counta by 255\relax
          \pgf@ya=16\pgf@ya\relax
          \divide\pgf@ya by\c@pgf@counta
          \pgf@xa=16\pgf@ya\relax
        \fi
    \fi
    \pgf@x=\pgf@xa%
    % Qrr: check for families
    \tikzext@nf@getandset{\the\dimexpr2\pgf@x\relax}{width}{\pgfutil@tempdima}%
    \tikzext@nf@getandset{\the\dimexpr2\pgf@x\relax}{height}{\pgfutil@tempdimb}%
    % Qrr: and adjust like minimum width and minimum height
    \ifdim\pgf@x<.5\pgfutil@tempdima
      \pgf@x=.5\pgfutil@tempdima
    \fi
    \ifdim\pgf@x<.5\pgfutil@tempdimb
      \pgf@x=.5\pgfutil@tempdimb
    \fi
    % If necessary, adjust radius so that the size requirements are met:
    \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/minimum width}}%
    \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/minimum height}}%
    \ifdim\pgf@x<.5\pgf@xb
        \pgf@x=.5\pgf@xb
    \fi
    \ifdim\pgf@x<.5\pgf@yb
        \pgf@x=.5\pgf@yb
    \fi
    % Now, add larger of outer separations.
    \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
    \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
    \ifdim\pgf@xb<\pgf@yb
      \advance\pgf@x by\pgf@yb
    \else
      \advance\pgf@x by\pgf@xb
    \fi
  }%
  \inheritbackgroundpath[from=circle]
  \inheritbeforebackgroundpath[from=circle]
  \inheritbehindforegroundpath[from=circle]
  \inheritforegroundpath[from=circle]
  \inheritbeforeforegroundpath[from=circle]
  \inheritanchor[from=circle]{center}
  \inheritanchor[from=circle]{mid}
  \inheritanchor[from=circle]{base}
  \inheritanchor[from=circle]{north}
  \inheritanchor[from=circle]{south}
  \inheritanchor[from=circle]{west}
  \inheritanchor[from=circle]{mid west}
  \inheritanchor[from=circle]{base west}
  \inheritanchor[from=circle]{north west}
  \inheritanchor[from=circle]{south west}
  \inheritanchor[from=circle]{east}
  \inheritanchor[from=circle]{mid east}
  \inheritanchor[from=circle]{base east}
  \inheritanchor[from=circle]{north east}
  \inheritanchor[from=circle]{south east}
  \inheritanchorborder[from=circle]
}

\def\pgfutil@prefixto@macro#1#2{%
  \def\pgf@temp{#2}%
  \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter#1%
  \expandafter\expandafter\expandafter{\expandafter\pgf@temp#1}%
}

\pgfqkeys{/tikz/ext/node family}{
  setup shape/.code={%
    \expandafter\pgfutil@prefixto@macro\csname pgf@sh@s@#1\endcsname{%
      \tikzext@nf@getandset{\the\wd\pgfnodeparttextbox}{text width}{\pgfutil@tempdima}%
      \ifdim\wd\pgfnodeparttextbox<\pgfutil@tempdima
        \setbox\pgfnodeparttextbox=\hbox to \pgfutil@tempdima{\tikzext@nf@align@action\pgfnodeparttextbox}%
      \fi
      \tikzext@nf@getandset{\the\dp\pgfnodeparttextbox}{text depth}{\pgfutil@tempdima}%
      \ifdim\dp\pgfnodeparttextbox<\pgfutil@tempdima
          \dp\pgfnodeparttextbox=\pgfutil@tempdima
      \fi
      \tikzext@nf@getandset{\the\ht\pgfnodeparttextbox}{text height}{\pgfutil@tempdima}%
      \ifdim\ht\pgfnodeparttextbox<\pgfutil@tempdima
          \ht\pgfnodeparttextbox=\pgfutil@tempdima
      \fi
    }%
  },
  setup shape/.list={rectangle,circle,Rectangle,Circle}
}

%% nf functions
\def\tikzext@nf@function@default{{\the\pgf@x}{\the\pgf@y}}
\def\tikzext@nf@function@default@double{{\the\dimexpr2\pgf@x\relax}{\the\dimexpr2\pgf@y\relax}}
\def\tikzext@nf@function@circle{{\the\pgf@x}{\the\pgf@x}}
\def\tikzext@nf@function@circle@double{{\the\dimexpr2\pgf@x\relax}{\the\dimexpr2\pgf@x\relax}}

\pgfmathdeclarefunction{ext_nf_width}{0}{%
  \begingroup
    \pgfutil@IfUndefined{tikzext@nf@function@\pgf@sm@shape@name}{%
      \let\tikzext@nf@function\tikzext@nf@function@default
    }{%
      \pgfutil@IfUndefined{tikzext@nf@function@\pgf@sm@shape@name @extra}{}{\csname tikzext@nf@function@\pgf@sm@shape@name @extra\endcsname}%
      \expandafter\let\expandafter\tikzext@nf@function\csname tikzext@nf@function@\pgf@sm@shape@name\endcsname
    }%
    \tikzext@nf@getandset{\expandafter\pgfutil@firstoftwo\tikzext@nf@function}{width}{\pgfutil@tempdima}%
    \edef\pgfmathresult{\pgf@sys@tonumber\pgfutil@tempdima}%
    \pgfmath@smuggleone\pgfmathresult
  \endgroup
}
\pgfmathdeclarefunction{ext_nf_height}{0}{%
  \begingroup
    \pgfutil@IfUndefined{tikzext@nf@function@\pgf@sm@shape@name}{%
      \let\tikzext@nf@function\tikzext@nf@function@default
    }{%
      \pgfutil@IfUndefined{tikzext@nf@function@\pgf@sm@shape@name @extra}{}{\csname tikzext@nf@function@\pgf@sm@shape@name @extra\endcsname}%
      \expandafter\let\expandafter\tikzext@nf@function\csname tikzext@nf@function@\pgf@sm@shape@name\endcsname
    }%
    \tikzext@nf@getandset{\expandafter\pgfutil@secondoftwo\tikzext@nf@function}{height}{\pgfutil@tempdima}%
    \edef\pgfmathresult{\pgf@sys@tonumber\pgfutil@tempdima}%
    \pgfmath@smuggleone\pgfmathresult
  \endgroup
}

%%% Compatibility
\tikzextset{
  /tikz-ext/compat/add library={node-families}{pre 0.6},
  compat/node-families/warn/.append code=%
    \tikzextutil@compatwarning@valuekey{node-families}{pre 0.6}{/tikz/node family/prefix}          {/tikz/ext/node family/prefix}%
    \tikzextutil@compatwarning@valuekey{node-families}{pre 0.6}{/tikz/node family/text height}     {/tikz/ext/node family/text height}%
    \tikzextutil@compatwarning@valuekey{node-families}{pre 0.6}{/tikz/node family/text depth}      {/tikz/ext/node family/text depth}%
    \tikzextutil@compatwarning@valuekey{node-families}{pre 0.6}{/tikz/node family/text width}      {/tikz/ext/node family/text width}%
    \tikzextutil@compatwarning@key     {node-families}{pre 0.6}{/tikz/node family/text}            {/tikz/ext/node family/text}%
    \tikzextutil@compatwarning@key     {node-families}{pre 0.6}{/tikz/node family/text width align}{/tikz/ext/node family/text width align}%
    \tikzextutil@compatwarning@key     {node-families}{pre 0.6}{/tikz/node family/setup shape}     {/tikz/ext/node family/setup shape}%
    \tikzextutil@compatwarning@key     {node-families}{pre 0.6}{/tikz/node family/width}           {/tikz/ext/node family/width}%
    \tikzextutil@compatwarning@key     {node-families}{pre 0.6}{/tikz/node family/height}          {/tikz/ext/node family/height}%
    \tikzextutil@compatwarning@key     {node-families}{pre 0.6}{/tikz/node family/size}            {/tikz/ext/node family/size},
  compat/node-families/pre 0.6/.append code=%
    \pgfkeysdef{/tikz/node family/prefix}          {\pgfkeyssetvalue{/tikz/ext/node family/prefix}{##1}}%
    \pgfkeysdef{/tikz/node family/text height}     {\pgfkeyssetvalue{/tikz/ext/node family/text height}{##1}}%
    \pgfkeysdef{/tikz/node family/text depth}      {\pgfkeyssetvalue{/tikz/ext/node family/text depth}{##1}}%
    \pgfkeysdef{/tikz/node family/text width}      {\pgfkeyssetvalue{/tikz/ext/node family/text width}{##1}}%
    \pgfkeysdef{/tikz/node family/text}            {\pgfkeysvalueof{/tikz/ext/node family/text/.@cmd}##1\pgfeov}%
    \pgfkeysdef{/tikz/node family/text width align}{\pgfkeysvalueof{/tikz/ext/node family/text width align/.@cmd}##1\pgfeov}%
    \pgfkeysdef{/tikz/node family/setup shape}     {\pgfkeysvalueof{/tikz/ext/node family/setup shape/.@cmd}##1\pgfeov}%
    \pgfkeysdef{/tikz/node family/width}           {\pgfkeysvalueof{/tikz/ext/node family/width/.@cmd}##1\pgfeov}%
    \pgfkeysdef{/tikz/node family/height}          {\pgfkeysvalueof{/tikz/ext/node family/height/.@cmd}##1\pgfeov}%
    \pgfkeysdef{/tikz/node family/size}            {\pgfkeysvalueof{/tikz/ext/node family/size/.@cmd}##1\pgfeov},
  compat/node-families/\pgfkeysvalueof{/tikz/ext/compat/node-families}%
}