% SPDX-License-Identifier: GPL-2.0-only OR LPPL-1.3c

\usetikzlibrary{arrows,shapes.multipart,backgrounds,fit}

%
% Utilities
%

\def\pgfumlcd@ifx#1#2{%
  \ifx#1#2%
    \expandafter\pgfutil@firstoftwo
  \else
    \expandafter\pgfutil@secondoftwo
  \fi}

\def\pgfumlcd@ifdim#1#2#3{%
  \ifdim\dimexpr#1\relax#2\dimexpr#3\relax
    \expandafter\pgfutil@firstoftwo
  \else
    \expandafter\pgfutil@secondoftwo
  \fi}

\def\pgfumlcd@ifnum#1#2#3{%
  \ifnum\numexpr#1\relax#2\numexpr#3\relax
    \expandafter\pgfutil@firstoftwo
  \else
    \expandafter\pgfutil@secondoftwo
  \fi}

\def\pgfumlcd@newif#1{%
  \csname newif\expandafter\endcsname\csname ifpgfumlcd@#1\endcsname
  \expandafter\def\csname pgfumlcd@if#1\expandafter\endcsname\expandafter{%
    \csname ifpgfumlcd@#1\endcsname
      \expandafter\pgfutil@firstoftwo
    \else
      \expandafter\pgfutil@secondoftwo
    \fi}%
}

\expandafter\let\expandafter\pgfumlcd@xdef\csname\ifcsname protected@xdef\endcsname protected@\fi xdef\endcsname

\def\umltextcolor{black}
\def\umldrawcolor{purple}
\def\umlfillcolor{yellow!20}

\tikzset{%
  help lines/.append style = {blue!50,very thin,dashed},
  umlcolor/.style = {color=\umldrawcolor,fill=\umlfillcolor,text=\umltextcolor},
  umlcd style/.style = {umlcolor, >=angle 90},
  package/.style = {matrix, column sep=1mm, row sep=1cm, node distance=2cm},
  packagename/.style = {rectangle, minimum height=2em},
  umlcd style implement line/.style = {color=\umldrawcolor, open triangle 45-,dashed},
  objectline/.style = {color=\umldrawcolor, diamond->},
  umlcd style inherit line/.style = {color=\umldrawcolor, open triangle 45-},
  splitline/.style = {color=\umldrawcolor, dotted,font=\pgfutil@font@itshape},
  umlcd style class/.style = {rectangle split, rectangle split parts=3, 
    every text node part/.style={text centered},
    draw, minimum height=2em, umlcolor, minimum width=2cm, text width=5cm,
    minimum height=1cm, node distance=2cm},
  umlcd style dashed line/.style = {color=\umldrawcolor, >=angle 90,dashed},
  umlcd style school/.style = {},
}

\pgfumlcd@newif{school}
\pgfumlcd@newif{simplified}

% declare layers
\pgfdeclarelayer{background}
\pgfdeclarelayer{connectionlayers}
\pgfsetlayers{background,connectionlayers,main}

\newcount\pgfumlcd@ClassAttributesNum
\newcount\pgfumlcd@ClassOperationsNum
\newcount\pgfumlcd@ClassAbstractClassNum
\newcount\pgfumlcd@ClassInterfaceNum
\newcount\pgfumlcd@ClassSplitPartNum

\def\pgfumlcd@PackageFit{}

\def\pgfumlcd@class{\pgfutil@ifnextchar[{\pgfumlcd@class@}{\pgfumlcd@class@[]}}
\def\pgfumlcd@class@[#1]#2#3{%
  \pgfumlcd@classAndInterfaceCommon{#1}{#2}{#3}%
}
\def\endpgfumlcd@class{%
    \pgfumlcd@calcuateNumberOfParts{}%
    \node[anchor=north,this umlcd style] (\pgfumlcd@ClassName) at (\pgfumlcd@ClassPos) {%
      {\pgfutil@font@bfseries\pgfumlcd@ClassName} % <-- explicit space
      \pgfumlcd@insertAttributesAndOperations{}%
    };%
  \endpgfumlcd@classAndInterfaceCommon
}

\def\pgfumlcd@interface{\pgfutil@ifnextchar[{\pgfumlcd@interface@}{\pgfumlcd@interface@[]}}
\def\pgfumlcd@interface@[#1]#2#3{%
  \pgfumlcd@classAndInterfaceCommon{#1}{#2}{#3}%
}
\def\endpgfumlcd@interface{%
    \pgfumlcd@calcuateNumberOfParts{}%
    \node[anchor=north,this umlcd style] (\pgfumlcd@ClassName) at (\pgfumlcd@ClassPos) {%
      $<<$interface$>>$\break
      {\pgfutil@font@bfseries\pgfumlcd@ClassName} % <-- explicit space
      \pgfumlcd@insertAttributesAndOperations{}%
    };%
  \endpgfumlcd@classAndInterfaceCommon
}

\def\pgfumlcd@abstractclass{\pgfutil@ifnextchar[{\pgfumlcd@abstractclass@}{\pgfumlcd@abstractclass@[]}}
\def\pgfumlcd@abstractclass@[#1]#2#3{%
  \pgfumlcd@classAndInterfaceCommon{#1}{#2}{#3}%
}
\def\endpgfumlcd@abstractclass{%
    \pgfumlcd@calcuateNumberOfParts{}
    \node[anchor=north,this umlcd style] (\pgfumlcd@ClassName) at (\pgfumlcd@ClassPos) {%
      $<<$abstract$>>$\break
      {\pgfutil@font@bfseries\pgfumlcd@ClassName} % <-- explicit space
      \pgfumlcd@insertAttributesAndOperations{}%
    };%
  \endpgfumlcd@classAndInterfaceCommon
}

\def\pgfumlcd@staticclass{\pgfutil@ifnextchar[{\pgfumlcd@staticclass@}{\pgfumlcd@staticclass@[]}}
\def\pgfumlcd@staticclass@[#1]#2#3{%
  \pgfumlcd@classAndInterfaceCommon{#1}{#2}{#3}%
}
\def\endpgfumlcd@staticclass{%
    \pgfumlcd@calcuateNumberOfParts{}
    \node[anchor=north,this umlcd style] (\pgfumlcd@ClassName) at (\pgfumlcd@ClassPos) {%
      $<<$static$>>$\break
      {\pgfutil@font@bfseries\pgfumlcd@ClassName} % <-- explicit space
      \pgfumlcd@insertAttributesAndOperations{}%
    };%
  \endpgfumlcd@classAndInterfaceCommon
}

% TODO: here the name of \pgfumlcd@ClassName and \umlObjectName should be
% switched, it is only for reusing \classAndInterfaceCommon at the
% moment.
\def\pgfumlcd@object{\pgfutil@ifnextchar[{\pgfumlcd@object@}{\pgfumlcd@object@[]}}
\def\pgfumlcd@object@[#1]#2#3{%
  \pgfumlcd@classAndInterfaceCommon{#1}{#2}{#3}%
    \def\pgfumlcd@@instanceOf{}
}
\def\endpgfumlcd@object{%
    % customized
    \pgfumlcd@ifsimplified{%
      \pgfumlcd@calcuateNumberOfParts{}%
    }{%
      \pgfumlcd@ifnum{\pgfumlcd@ClassOperationsNum}{>}{0}{%
        \pgfumlcd@ClassSplitPartNum=3
        \pgfumlcd@xdef\pgfumlcd@SplitPart{3}%
      }{%
        \pgfumlcd@ClassSplitPartNum=2
        \pgfumlcd@xdef\pgfumlcd@SplitPart{2}%
      }%
    }%
    \pgfumlcd@ifx{\pgfumlcd@@instanceOf}{\pgfutil@empty}{%
      \def\pgfumlcd@ObjectName{\pgfumlcd@ClassName}%
    }{%
      \def\pgfumlcd@ObjectName{\pgfumlcd@ClassName : \pgfumlcd@@instanceOf}%
    }%
    \node[anchor=north,this umlcd style,umlcd style school] (\pgfumlcd@ClassName) at (\pgfumlcd@ClassPos) {%
      \pgfumlcd@ifschool{%
        {\pgfutil@font@bfseries\pgfumlcd@ObjectName}%
      }{%
        \underline{\pgfutil@font@bfseries\pgfumlcd@ObjectName}%
      } % <-- explicit space
      \pgfumlcd@insertAttributesAndOperations{}%
    };%
  \endpgfumlcd@classAndInterfaceCommon
}

\def\pgfumlcd@insertAttributesAndOperations{%
  \pgfumlcd@ifnum{\pgfumlcd@ClassSplitPartNum}{>}{1}{%
    \nodepart{second}%
  }{}%
  \pgfumlcd@ClassAttributes
  \pgfumlcd@ifnum{\pgfumlcd@ClassSplitPartNum}{>}{2}{%
    \nodepart{third}%
  }{}%
  \pgfumlcd@ClassOperations
}

\def\pgfumlcd@calcuateNumberOfParts{%
  % calcuate the number of parts
  \pgfumlcd@ifsimplified{%
    \pgfumlcd@ClassSplitPartNum=1
    \pgfumlcd@ifnum{\pgfumlcd@ClassAttributesNum}{>}{0}{%
      \advance\pgfumlcd@ClassSplitPartNum by 1
    }{}%
    \pgfumlcd@ifnum{\pgfumlcd@ClassOperationsNum}{>}{0}{%
      \advance\pgfumlcd@ClassSplitPartNum by 1
    }{}%
  }{%
    \pgfumlcd@ClassSplitPartNum=3 % three parts by default
  }%
  \pgfumlcd@xdef\pgfumlcd@SplitPart{3}
  \pgfumlcd@ifnum{\pgfumlcd@ClassSplitPartNum}{=}{1}{%
    \pgfumlcd@xdef\pgfumlcd@SplitPart{1}%
  }{}%
  \pgfumlcd@ifnum{\pgfumlcd@ClassSplitPartNum}{=}{2}{%
    \pgfumlcd@xdef\pgfumlcd@SplitPart{2}%
  }{}%
}

\def\pgfumlcd@classAndInterfaceCommon#1#2#3{%
  \def\pgfumlcd@ClassName{#2}%
  \def\pgfumlcd@ClassPos{#3}
  \def\pgfumlcd@ClassAttributes{}%
  \def\pgfumlcd@ClassOperations{}%
  \def\pgfumlcd@ClassAbstractClass{}%
  \def\pgfumlcd@ClassInterface{}%
  \pgfumlcd@ClassAttributesNum=0
  \pgfumlcd@ClassOperationsNum=0
  \pgfumlcd@ClassAbstractClassNum=0
  \pgfumlcd@ClassInterfaceNum=0
  \tikzset{%
    this umlcd style/.style={%
      umlcd style class,%
      rectangle split parts=\pgfumlcd@SplitPart,%
      #1}%
  }
}%
\def\endpgfumlcd@classAndInterfaceCommon{%
  %% connections
  \pgfonlayer{connectionlayers}%
    \pgfumlcd@ifnum{\pgfumlcd@ClassAbstractClassNum}{>}{0}{%
      \foreach \c in \pgfumlcd@ClassAbstractClass {%
        \draw [umlcd style inherit line] (\c) -- (\pgfumlcd@ClassName);%
      }%
    }{}%
    \pgfumlcd@ifnum{\pgfumlcd@ClassInterfaceNum}{>}{0}{%
      \foreach \c in \pgfumlcd@ClassInterface {%
        \draw [umlcd style implement line] (\c) -- (\pgfumlcd@ClassName);%
      }%
    }{}%
  \endpgfonlayer
  %% add to fit
  \let\pgfumlcd@PackageFitOld\pgfumlcd@PackageFit
  \pgfumlcd@xdef\pgfumlcd@PackageFit{\pgfumlcd@PackageFitOld (\pgfumlcd@ClassName)}%
}

\def\pgfumlcd@attribute#1{%
  \pgfumlcd@ifnum{\pgfumlcd@ClassAttributesNum}{=}{0}{%
    \pgfumlcd@xdef\pgfumlcd@ClassAttributes{#1}%
  }{%
    \let\pgfumlcd@ClassAttributesOld\pgfumlcd@ClassAttributes
    \pgfumlcd@xdef\pgfumlcd@ClassAttributes{\pgfumlcd@ClassAttributesOld\break#1}%
  }%
  \advance\pgfumlcd@ClassAttributesNum by 1
}

\def\pgfumlcd@operation{\pgfutil@ifnextchar[{\pgfumlcd@operation@}{\pgfumlcd@operation@[1]}}
\def\pgfumlcd@operation@[#1]#2{%
  \advance\pgfumlcd@ClassOperationsNum by 1
  \def\pgfumlcd@virtualoperation{#2}
  \pgfumlcd@ifnum{0}{=}{#1}{%
    \def\pgfumlcd@virtualoperation{{\pgfutil@font@itshape#2}}%
  }{}%
  \pgfumlcd@ifnum{\pgfumlcd@ClassOperationsNum}{=}{1}{%
    \pgfumlcd@xdef\pgfumlcd@ClassOperations{\pgfumlcd@virtualoperation}%
  }{%
    \let\pgfumlcd@ClassOperationsOld\pgfumlcd@ClassOperations
    \pgfumlcd@xdef\pgfumlcd@ClassOperations{\pgfumlcd@ClassOperationsOld\break\pgfumlcd@virtualoperation}%
  }%
}

\def\pgfumlcd@inherit#1{%
  \advance\pgfumlcd@ClassAbstractClassNum by 1
  \pgfumlcd@ifnum{\pgfumlcd@ClassAbstractClassNum}{=}{1}{%
    \pgfumlcd@xdef\pgfumlcd@ClassAbstractClass{#1}%
  }{%
    \let\pgfumlcd@ClassAbstractClassOld\pgfumlcd@ClassAbstractClass
    \pgfumlcd@xdef\pgfumlcd@ClassAbstractClass{\pgfumlcd@ClassAbstractClassOld, #1}%
  }%
}

\def\pgfumlcd@implement#1{%
  \advance\pgfumlcd@ClassInterfaceNum by 1
  \pgfumlcd@ifnum{\pgfumlcd@ClassInterfaceNum}{=}{1}{%
    \pgfumlcd@xdef\pgfumlcd@ClassInterface{#1}
  }{%
    \let\pgfumlcd@ClassInterfaceOld\pgfumlcd@ClassInterface
    \pgfumlcd@xdef\pgfumlcd@ClassInterface{\pgfumlcd@ClassInterfaceOld, #1}
  }%
}

\def\pgfumlcd@instanceOf#1{\def\pgfumlcd@@instanceOf{#1}}

\def\pgfumlcd@association{\pgfutil@ifnextchar[{\pgfumlcd@association@}{\pgfumlcd@association@[]}}
\def\pgfumlcd@association@[#1]#2#3#4#5#6#7{%
  \draw [umlcd style,#1] (#2) -- (#5)
    node[near start, auto]{#3}
    node[near start, auto, swap]{#4}
    node[near end, auto]{#6}
    node[near end, auto, swap]{#7};%
}

\def\pgfumlcd@unidirectionalAssociation{%
  \pgfutil@ifnextchar[{\pgfumlcd@unidirectionalAssociation@}{\pgfumlcd@unidirectionalAssociation@[]}}
\def\pgfumlcd@unidirectionalAssociation@[#1]#2#3#4#5{%
  \draw [umlcd style,->,#1] (#2) -- (#5)
    node[near end, auto]{#3}
    node[near end, auto, swap]{#4};%
}

\def\pgfumlcd@aggregation{\pgfutil@ifnextchar[{\pgfumlcd@aggregation@}{\pgfumlcd@aggregation@[]}}
\def\pgfumlcd@aggregation@[#1]#2#3#4#5{%
  \draw[umlcd style,open diamond->,#1] (#2) -- (#5)
    node[near end, auto]{#3}
    node[near end, auto, swap]{#4};%
}

\def\pgfumlcd@composition{\pgfutil@ifnextchar[{\pgfumlcd@composition@}{\pgfumlcd@composition@[]}}
\def\pgfumlcd@composition@[#1]#2#3#4#5{%
  \draw[umlcd style,fill=\umldrawcolor,diamond->,#1] (#2) -- (#5)
    node[near end, auto]{#3}
    node[near end, auto, swap]{#4};%
}

\def\pgfumlcd@package#1{%
  \def\pgfumlcd@PackageFit{}%
  \def\pgfumlcd@PackageName{#1}%
}
\def\endpgfumlcd@package{%
  \pgfonlayer{background}%
    \node[umlcd style,draw,inner sep=0.5cm,fit=\pgfumlcd@PackageFit] (\pgfumlcd@PackageName) {};%
    \node[umlcd style,draw,outer ysep=-0.5,anchor=south west] (\pgfumlcd@PackageName caption) at
    (\pgfumlcd@PackageName.north west) {\pgfumlcd@PackageName};%
  \endpgfonlayer
}

\def\switchUmlcdSchool{%
  \pgfumlcd@ifschool{%
    \tikzset{umlcd style school/.style={}}%
    \pgfumlcd@schoolfalse
  }{%
    \tikzset{umlcd style school/.style = {rounded corners}}%
    \pgfumlcd@schooltrue
  }%
}

\pgfdeclareshape{umlcdnote}{%
  \inheritsavedanchors[from=rectangle]% this is nearly a rectangle
  \inheritanchorborder[from=rectangle]%
  \inheritanchor[from=rectangle]{center}%
  \inheritanchor[from=rectangle]{north}%
  \inheritanchor[from=rectangle]{south}%
  \inheritanchor[from=rectangle]{west}%
  \inheritanchor[from=rectangle]{east}%
  % ... and possibly more
  \backgroundpath{% this is new
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    % compute corner of flipped page
    \pgf@xc=\pgf@xb \advance\pgf@xc by-10pt % this should be a parameter
    \pgf@yc=\pgf@yb \advance\pgf@yc by-10pt
    % construct main path
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}%
    \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}%
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}}%
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}%
    \pgfpathclose
    % add little corner
    \pgfpathmoveto{\pgfpoint{\pgf@xc}{\pgf@yb}}%
    \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}%
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}}%
    \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}%
  }%
}

\def\pgfumlcd@umlnote{\pgfutil@ifnextchar[{\pgfumlcd@umlnote@}{\pgfumlcd@umlnote@[]}}
\def\pgfumlcd@umlnote@[#1]{%
  \node[anchor=north,draw,shape=umlcdnote,text width=4cm,umlcd style,#1]%
}

\tikzaddtikzonlycommandshortcutlet{\class}{\pgfumlcd@class}
\tikzaddtikzonlycommandshortcutlet{\endclass}{\endpgfumlcd@class}
\tikzaddtikzonlycommandshortcutlet{\interface}{\pgfumlcd@interface}
\tikzaddtikzonlycommandshortcutlet{\endinterface}{\endpgfumlcd@interface}
\tikzaddtikzonlycommandshortcutlet{\abstractclass}{\pgfumlcd@abstractclass}
\tikzaddtikzonlycommandshortcutlet{\endabstractclass}{\endpgfumlcd@abstractclass}
\tikzaddtikzonlycommandshortcutlet{\staticclass}{\pgfumlcd@staticclass}
\tikzaddtikzonlycommandshortcutlet{\endstaticclass}{\endpgfumlcd@staticclass}
\tikzaddtikzonlycommandshortcutlet{\object}{\pgfumlcd@object}
\tikzaddtikzonlycommandshortcutlet{\endobject}{\endpgfumlcd@object}
\tikzaddtikzonlycommandshortcutlet{\classAndInterfaceCommon}{\pgfumlcd@classAndInterfaceCommon}
\tikzaddtikzonlycommandshortcutlet{\endclassAndInterfaceCommon}{\endpgfumlcd@classAndInterfaceCommon}
\tikzaddtikzonlycommandshortcutlet{\package}{\pgfumlcd@package}
\tikzaddtikzonlycommandshortcutlet{\endpackage}{\endpgfumlcd@package}

\tikzaddtikzonlycommandshortcutlet{\attribute}{\pgfumlcd@attribute}
\tikzaddtikzonlycommandshortcutlet{\operation}{\pgfumlcd@operation}
\tikzaddtikzonlycommandshortcutlet{\inherit}{\pgfumlcd@inherit}
\tikzaddtikzonlycommandshortcutlet{\implement}{\pgfumlcd@implement}
\tikzaddtikzonlycommandshortcutlet{\instanceOf}{\pgfumlcd@instanceOf}
\tikzaddtikzonlycommandshortcutlet{\association}{\pgfumlcd@association}
\tikzaddtikzonlycommandshortcutlet{\unidirectionalAssociation}{\pgfumlcd@unidirectionalAssociation}
\tikzaddtikzonlycommandshortcutlet{\aggregation}{\pgfumlcd@aggregation}
\tikzaddtikzonlycommandshortcutlet{\composition}{\pgfumlcd@composition}
\tikzaddtikzonlycommandshortcutlet{\umlnote}{\pgfumlcd@umlnote}
