%<–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––>
%
%  tkz-orm.sty - Object-Role Modeling Diagrams in LaTeX
%
%<–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––>
% This is file may be be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% Copyright 2009-2016 by Jakob Voss, Camil Staps
%<–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––>
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{tkz-orm}[2016/01/15 v0.1.4 Object-Role Modeling]
%<–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––>
\RequirePackage{tikz}[2009/09/04]

%%%% Required pgf/TikZ libraries
%\usetikzlibrary{calc}
\usepgflibrary{shapes.multipart}
\usetikzlibrary{shadows}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}
\usetikzlibrary{fit}

\makeatletter

%%%% Options

%\DeclareOption*{%
%   \PackageWarning{tkz-orm}{Unknown option ‘\CurrentOption’}%
%}

\def\orm@error#1{\relax}% TODO
%\def\orm@error#1{\PackageWarning{tkz-orm}{#1}}%

%\pgfkeysdefargs{/tikz/ormcolorlet}{#1}{\colorlet{#2}{#1}}
% \pgfkeys{/orm/.is family} % TODO

\def\tkzorm{\textsf{tkz-orm}}

%%%% ORM color constants
\colorlet{constraintcolor}{magenta!100}
\colorlet{ormconstraintcolor}{magenta!100}
\colorlet{ormdeonticcolor}{blue!100}
\colorlet{ormimpliedcolor}{gray!100}

\def\orm@constraint@stroke{magenta}
\def\orm@constraint@fill{magenta}

\pgfkeysdefargs{/tikz/constraintcolor}{#1}{\colorlet{constraintcolor}{#1}}

%%%% ORM width and length
\newlength{\orm@linewidth}
\setlength{\orm@linewidth}{0.25mm}

%%%% ORM fonts
\newcommand{\orm@font}{\sffamily\small}
\newcommand{\orm@font@bold}{\bfseries\sffamily\small}
\newcommand{\orm@font@tiny}{\sffamily\tiny}
\newcommand{\orm@font@scriptsize}{\sffamily\scriptsize}
\newcommand{\orm@font@bold@scriptsize}{\bfseries\sffamily\scriptsize}

%%%% Text markup

% textsubscript may not be defined like textsuperscript
\newcommand{\orm@textsubscript}[1]{%
 {\m@th\ensuremath{_{\mbox{\fontsize\sf@size\z@#1}}}}}

% similar to \blacktriangle (could better be implemented directly in pgf)
\def\orm@blacktriangle#1{
 \tikz \node[draw=none,inner sep=.2ex] {
   \tikz [#1]\path[fill=black]
   (0,0) -- (.6ex,1.3ex) -- (1.2ex,0) -- cycle;};
}
\def\ormarrowup{\orm@blacktriangle{rotate=0}}
\def\ormarrowdown{\orm@blacktriangle{rotate=180}}
\def\ormarrowleft{\orm@blacktriangle{rotate=90}}
\def\ormarrowright{\orm@blacktriangle{rotate=-90}}

\def\ormtext{\orm@font}
\def\ormbf{\orm@font@bold}
\def\ormc{\orm@font\color{constraintcolor}}
\def\ormsup#1{\textsuperscript{\orm@font@scriptsize #1}}
\def\ormsub#1{\orm@textsubscript{\orm@font@scriptsize #1}}
\def\ormind#1{\textsuperscript{\orm@font@bold@scriptsize\color{constraintcolor} #1}}
\def\ormbraces#1{{\orm@font\textbraceleft#1\textbraceright}}
\def\ormvalues#1{\ormc{\ormbraces{#1}}}

\def\ormleft#1{{\ormarrowleft\ormtext #1}}
\def\ormup#1{{\ormtext #1\ormarrowup}}

% TODO: add '*' variant in constraint color for each command

%%% Sizes
\def\orm@role@linewidth{\orm@linewidth} % 0.25mm
\def\orm@role@width{4mm}
\def\orm@role@height{2.5mm}


%%%% ORM styles

\pgfkeys{/tikz/constraint stroke/.store in=\orm@constraint@stroke}
\pgfkeys{/tikz/constraint fill/.store in=\orm@constraint@fill}
\pgfkeys{/tikz/constraint color/.style={constraint stroke=#1,constraint fill=#1}}


\tikzstyle{every orm line}=         [solid,draw=black,line width=\orm@linewidth,-]
\tikzstyle{orm}=                    [font=\orm@font,node distance=4mm,
                                    %label distance=1.5mm,
                                    %line width=\orm@linewidth,
                                    label distance=1.25mm
                                   ]
\tikzstyle{orm-spacious}=           [orm,
                                    every object/.style={shape=circle}
                                   ]

\tikzstyle{every orm}=              [every orm line,fill=white,orm]

\tikzstyle{zoomed}=                 [line width=\orm@linewidth*1.5]

\tikzstyle{every object}=           []
\tikzstyle{every entity}=           []
\tikzstyle{entity}=                 [every orm,
                                    shape=rectangle,rounded corners,
                                    align=center,minimum size=6mm,
                                    every object,every entity]

\tikzstyle{every value}=            []
\tikzstyle{value}=                  [every orm,
                                    shape=rectangle,rounded corners,densely dashed,
                                    align=center,minimum size=6mm,
                                    every object,every value]


\tikzstyle{relationship}=           [every orm line,every relationship]
\tikzstyle{relation}=               [relationship]
\tikzstyle{plays}=                  [relationship]
\tikzstyle{every relationship}=     []


\tikzstyle{role index}=             [font=\orm@font@tiny,inner sep=0,minimum width=\orm@role@width]


\tikzstyle{every predicate}=        []

%%% Shortcuts in tikzpicture
\tikzaddtikzonlycommandshortcutdef{\entity}{\node[entity]}
\tikzaddtikzonlycommandshortcutdef{\value}{\node[value]}

\tikzaddtikzonlycommandshortcutdef{\unary}{\node[role]}
\tikzaddtikzonlycommandshortcutdef{\role}{\node[role]}
\tikzaddtikzonlycommandshortcutdef{\binary}{\node[roles]}
\tikzaddtikzonlycommandshortcutdef{\roles}{\node[roles]}
\tikzaddtikzonlycommandshortcutdef{\ternary}{\node[roles=3]}

\tikzaddtikzonlycommandshortcutdef{\vunary}{\node[vrole]}
\tikzaddtikzonlycommandshortcutdef{\vrole}{\node[vrole]}
\tikzaddtikzonlycommandshortcutdef{\vbinary}{\node[vroles]}
\tikzaddtikzonlycommandshortcutdef{\vroles}{\node[vroles]}
\tikzaddtikzonlycommandshortcutdef{\vternary}{\node[vroles=3]}

\tikzaddtikzonlycommandshortcutdef{\plays}{\draw[relationship]}

% TODO: add error message if matrix package not loaded ?
\tikzaddtikzonlycommandshortcutdef{\rules}{\matrix[row sep=0mm,nodes={right}]}

\tikzaddtikzonlycommandshortcutdef{\limits}{\draw[limits]}
\tikzaddtikzonlycommandshortcutdef{\limited}{\draw[limits]}
\tikzaddtikzonlycommandshortcutdef{\limitsto}{\draw[limits to]}

\tikzaddtikzonlycommandshortcutdef{\constraint}{\node[text=constraintcolor]}

%%%% Textual rules

\tikzset{rule/.style args={#1}{%
 append after command={%
   \bgroup%
     [current point is local=true]
     (\tikzlastnode.north west) node[font=\orm@font@bold@scriptsize,
        anchor=north east,inner sep=0,text=constraintcolor] {#1}
   \egroup%
 },
 orm,inner sep=0.5mm,
}}
\tikzset{rule/.default={}}


%%%% Predicates and roles
\tikzstyle{all predicates}=[
 every orm line,
 fill=white,
 rectangle split,
 inner sep=0
]

\tikzset{roles/.style args={#1}{
 all predicates,rectangle split parts=#1, rectangle split allocate boxes=#1,
 rectangle split horizontal=true,
 rectangle split empty part height=2.5mm,rectangle split empty part width=2.25mm, % 4-1.5 = 2.5
%  every label/.style={label distance=1.5mm}
%label distance=1.5mm
 every predicate
}}
\tikzset{roles/.default={2}}

\tikzset{vroles/.add style={}{roles=#1,rotate=90}}
\tikzset{vroles/.default={2}}
\tikzstyle{role}=[roles=1]
\tikzstyle{vrole}=[vroles=1]

\tikzstyle{role name}=[font=\orm@font,color=blue,inner sep=0.5mm]

%% end of roles

% TODO: read
% http://www.latex-project.org/guides/clsguide.pdf

\pgfkeyssetvalue{/tkzorm/constraintstroke}{constraintcolor}
\pgfkeyssetvalue{/tkzorm/constraintfill}{constraintcolor}

%%%
% arrow heads

% dot as arrow head (no color)
\pgfarrowsdeclare{dot}{dot}{
 \pgfutil@tempdima=0.2pt%
 \advance\pgfutil@tempdima by.2\pgflinewidth%
 \pgfutil@tempdimb=5.5\pgfutil@tempdima\advance\pgfutil@tempdimb
 by\pgflinewidth
 \pgfarrowsleftextend{+-\pgfutil@tempdimb}
 \pgfutil@tempdimb=1.5\pgfutil@tempdima\advance\pgfutil@tempdimb
 by.5\pgflinewidth
 \pgfarrowsrightextend{+\pgfutil@tempdimb}
}{
 \pgfutil@tempdima=0.2pt%
 \advance\pgfutil@tempdima by.2\pgflinewidth%
 \pgfsetdash{}{+0pt}
 \pgfpathcircle{\pgfqpoint{+3\pgfutil@tempdima}{0pt}}{+4.5\pgfutil@tempdima}
 \pgfsetstrokecolor{\orm@constraint@stroke}
 \pgfsetfillcolor{\orm@constraint@fill}
 %\pgfsetfillcolor{\pgfkeysvalueof{/tkzorm/constraintfill}}
 \pgfusepathqfillstroke
}

% mandatory constraint dot arrow head
\pgfarrowsdeclare{mdot}{mdot}{
 \pgfarrowsrightextend{0pt}% put arrow head over the tip
 \pgfutil@tempdima=0.25mm\advance\pgfutil@tempdima by 0.5\pgflinewidth% lw
 \pgfarrowsleftextend{+-\pgfutil@tempdima}% for arrow composing
}{
 \pgfutil@tempdima=0.5mm\advance\pgfutil@tempdima by \pgflinewidth% radius
 \pgfutil@tempdimb=0.25mm\advance\pgfutil@tempdimb by 0.5\pgflinewidth% lw
 \pgfpathcircle{\pgfqpoint{0.5\pgflinewidth}{0pt}}{\pgfutil@tempdima}
 \pgfsetfillcolor{ormconstraintcolor}
 \pgfusepathqfill
}

% implied mandatory constraint dot arrow head
\pgfarrowsdeclare{idot}{idot}{
 \pgfarrowsrightextend{0pt}% put arrow head over the tip
 \pgfutil@tempdima=0.25mm\advance\pgfutil@tempdima by 0.5\pgflinewidth% lw
 \pgfarrowsleftextend{+-\pgfutil@tempdima}% for arrow composing
}{
 \pgfutil@tempdima=0.5mm\advance\pgfutil@tempdima by \pgflinewidth% radius
 \pgfpathcircle{\pgfqpoint{0.5\pgflinewidth}{0pt}}{\pgfutil@tempdima}
 \pgfsetfillcolor{ormimpliedcolor}
 \pgfusepathqfill
}

% deontic mandatory constraint dot arrow head
\pgfarrowsdeclare{odot}{odot}{
 \pgfutil@tempdima=0.5mm\advance\pgfutil@tempdima by 1.0\pgflinewidth% radius
 \pgfarrowsrightextend{0.5\pgfutil@tempdima}% put arrow head over the tip
 \pgfarrowsleftextend{0pt}% for arrow composing
}{
 %\pgfutil@tempdima=0.5mm\advance\pgfutil@tempdima by 1.0\pgflinewidth% radius
 %\pgfutil@tempdimb=0.25mm\advance\pgfutil@tempdimb by 0.5\pgflinewidth% lw
 %\advance\pgfutil@tempdima by -0.5\pgfutil@tempdimb% -linewidth
 \pgfutil@tempdima=0.475mm\advance\pgfutil@tempdima by 0.75\pgflinewidth% r-lw
 \pgfutil@tempdimb=0.25mm\advance\pgfutil@tempdimb by 1\pgflinewidth% lw
 \pgfpathcircle{\pgfqpoint{\pgfutil@tempdimb}{0pt}}{\pgfutil@tempdima}
 \pgfutil@tempdima=0.25mm\advance\pgfutil@tempdima by 0.5\pgflinewidth% lw
 \pgfsetdash{}{+0pt}
 \pgfsetlinewidth{\pgfutil@tempdima}
 \pgfsetstrokecolor{ormdeonticcolor}
 \pgfsetfillcolor{white}
 \pgfusepathqfillstroke
}

% implied deontic mandatory constraint dot arrow head
\pgfarrowsdeclare{iodot}{iodot}{
 \pgfutil@tempdima=0.5mm\advance\pgfutil@tempdima by 1.0\pgflinewidth% radius
 \pgfarrowsrightextend{0.5\pgfutil@tempdima}% put arrow head over the tip
 \pgfarrowsleftextend{0pt}% for arrow composing
}{
 \pgfutil@tempdima=0.475mm\advance\pgfutil@tempdima by 0.75\pgflinewidth% r-lw
 \pgfutil@tempdimb=0.25mm\advance\pgfutil@tempdimb by 1\pgflinewidth% lw
 \pgfpathcircle{\pgfqpoint{\pgfutil@tempdimb}{0pt}}{\pgfutil@tempdima}
 \pgfutil@tempdima=0.25mm\advance\pgfutil@tempdima by 0.5\pgflinewidth% lw
 \pgfsetdash{}{+0pt}
 \pgfsetlinewidth{\pgfutil@tempdima}
 \pgfsetstrokecolor{ormimpliedcolor}
 \pgfsetfillcolor{white}
 \pgfusepathqfillstroke
}


% filled arrow for subtyping, subset constraints and value-comparision constraints
\pgfarrowsdeclare{orm arrow}{orm arrow}
{
 \pgfutil@tempdima=0.5pt%
 \advance\pgfutil@tempdima by.1\pgflinewidth%
 \pgfutil@tempdimb=8.705\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth%
 \pgfarrowsleftextend{+-\pgfutil@tempdimb}
 \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by1.28\pgflinewidth%
 \pgfarrowsrightextend{+\pgfutil@tempdimb}
}{
 \pgfutil@tempdima=0.5pt%
 \advance\pgfutil@tempdima by.1\pgflinewidth%
 \pgfsetdash{}{+0pt}
 \pgfsetmiterjoin
 \pgfpathmoveto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{157}{10\pgfutil@tempdima}}}
 \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}}
 \pgfpathlineto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-157}{10\pgfutil@tempdima}}}
 \pgfpathclose
 \pgfsetfillcolor{ormconstraintcolor} % TODO: change if implied, deontic etc.
 %\pgfsetstrokefillcolor{ormconstraintcolor} % TODO: change if implied, deontic etc.
 \pgfusepathqfillstroke
}

% line styles that enable the mandatory constraint arrow tip
\tikzstyle{required}      =[relationship,mdot-]
\tikzstyle{required by}   =[relationship,-mdot]
\tikzstyle{both required} =[relationship,mdot-mdot]

% aliases
\tikzstyle{mandatory}     =[required]
\tikzstyle{both mandatory}=[both required]
\tikzstyle{optional}      =[relationship]


% draw a mandatory constraint arrow tip over a node
\tikzset{constraint dot/.style={append after command={
 (\tikzlastnode.center) edge[required] (\tikzlastnode.center)
}}}
\tikzstyle{cdot}            =[constraint dot]


%%%% Constraint symbols
\tikzstyle{every constraint}=       []
% TODO: every uniqueness bar
\tikzstyle{every constraint line}=  [every orm line,draw=constraintcolor,every constraint]
%\tikzstyle{every constraint line}=  [line width=\orm@linewidth,draw=constraintcolor,solid]
\tikzstyle{every constraint circle}=[]
\tikzstyle{constraint circle}=      [every orm,every constraint line,
                                    shape=circle,
                                    font=\orm@font@scriptsize,
                                    minimum size=4mm,,inner sep=0pt,
                                    every constraint circle]
\tikzstyle{constraint no circle}=   [constraint circle,draw=none,fill=none]

\tikzstyle{limits}=                 [every constraint line,dotted]
\tikzstyle{limits to}=              [every constraint line,dashed,-orm arrow]


% internal uniqueness constraint

% Implied and duplicated model parts:

\tikzstyle{duplicated}=             [drop shadow]
\tikzstyle{duplicated model}=       [every orm/.append style={drop shadow},
                                    every predicate/.append style={drop shadow}]

\tikzstyle{every implied line}=     [constraintcolor=gray!80,thin]
\tikzstyle{every implied}=          [fill=gray!30,every implied line]

\tikzstyle{implied}=[
   every orm/.append style={every implied},
   every orm line/.append style={every implied line},,
   constraint color=gray!100,thin,
   every relationship/.style={fill=gray!30},
       required/.append style={idot-},
       required by/.append style={-idot},
       both required/.append style={idot-idot}
]
\tikzstyle{implied model}=[implied]

\tikzstyle{deontic}=                [
   every orm line/.append style={constraintcolor=blue!100},
   constraintcolor=blue!100,
   constraint color=blue!100,
   required/.append style={odot-},
   required by/.append style={-odot},
   both required/.append style={odot-odot}
]


%%%% Constraints

% Define a constraints type
%
% #1 = name of the constraint
% #2 = path code to be drawn above the constraint circle with |append after command|
%
\newcommand{\constraintdeclare}[2]{%
 \tikzset{constraint/#1/.style={constraint circle,append after command={#2}}}%
}

% Define a constraint alias
%
% #1 = alias name
% #2 = name of the constraint
%
\newcommand{\constraintdeclarealias}[2]{%
 \tikzset{constraint/#1/.style={constraint=#2}}%
}

% Define a constraint by drawing another node at the some position as the current node
\newcommand{\constraintdeclareasnode}[2]{
 \constraintdeclare{#1}{
   (\tikzlastnode.center) node[anchor=center] {\tikz{#2}}
}}

% style /tikz/constraint and its keys
\tikzset{constraint/.is choice}

%\tikzset{constraint/misc/.style={constraint circle,text=constraintcolor}}%


%\constraintdeclarealias{le}{symmetric}
%\tikzset{constraint/le/.append style={label={[text=constraintcolor,font=\orm@font@scriptsize]center:$<$}}}

% TODO: clean up code
\tikzset{constraint/</.style={
 constraint circle,
 append after command={
   \bgroup%
     [current point is local=true]
     (\tikzlastnode) +(180:2mm) node[cdot]{}
                     +(0:2mm) node[cdot]{}
   \egroup%
 },
 label={[text=constraintcolor,font=\orm@font@scriptsize]center:$<$}
}}
% TODO: clean up code
\tikzset{constraint/ge/.style={
 constraint circle,
 append after command={
   \bgroup%
     [current point is local=true]
     (\tikzlastnode) +(180:2mm) node[cdot]{}
                     +(0:2mm) node[cdot]{}
   \egroup%
 },
 label={[text=constraintcolor,font=\orm@font@scriptsize]center:$\ge$}
}}
% TODO: clean up code
\tikzset{constraint/>/.style={
 constraint circle,
 append after command={
   \bgroup%
     [current point is local=true]
     (\tikzlastnode) +(180:2mm) node[cdot]{}
                     +(0:2mm) node[cdot]{}
   \egroup%
 },
 label={[text=constraintcolor,font=\orm@font@scriptsize]center:$>$}
}}
% TODO: clean up code
\tikzset{constraint/le/.style={
 constraint circle,
 append after command={
   \bgroup%
     [current point is local=true]
     (\tikzlastnode) +(180:2mm) node[cdot]{}
                     +(0:2mm) node[cdot]{}
   \egroup%
 },
 label={[text=constraintcolor,font=\orm@font@scriptsize]center:$\le$}
}}

%\tikzstyle{entity}=                 [every orm,
%                                     shape=rectangle,rounded corners,
%                                     align=center,minimum size=6mm,
%                                     every object,every entity]
\tikzset{constraint/text/.style={color=constraintcolor,font=\orm@font,align=center}}

\tikzset{constraint/.default=text}

% TODO: color=constraintcolor


%%%% Ring constraints

% TODO: possibly join with cdot
\tikzstyle{ormdot}=         [fill=constraintcolor,radius=.6mm,draw=none]


\constraintdeclareasnode{acyclic}{
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \draw [every constraint line]
     (270:1mm) edge (270:3mm);
}
%\constraintdeclarealias{DAG}{acyclic} % directed-acyclic-graph (DAG)

\constraintdeclareasnode{intransitive}{
 \fill[every constraint line,fill=white,draw=white] circle (2.2mm);
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \path[every constraint line,rounded corners=0] (90:2mm) -- (210:2mm) -- (330:2mm) -- (90:2mm);
 \draw[every constraint line] (270:0mm) to (270:1.75mm);
}

% TODO: document
\constraintdeclareasnode{strongly intransitive}{
 \fill[every constraint line,fill=white,draw=white] circle (2.2mm);
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot]  (30:1mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \path[every constraint line,rounded corners=0] (90:2mm) -- (210:2mm) -- (330:2mm) -- (90:2mm);
 \draw[every constraint line] (270:0mm) to (270:1.75mm);
}

% TODO: document tree and otree
\constraintdeclareasnode{tree}{
 \fill[every constraint line,fill=white,draw=white] circle (2.2mm);
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \path[every constraint line,rounded corners=0] (339:2mm) -- (90:2mm) -- (210:2mm);
}

\constraintdeclareasnode{otree}{
 \fill[every constraint line,fill=white,draw=white] circle (2.2mm);
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \path[every constraint line,rounded corners=0] (339:2mm) -- (90:2mm) -- (210:2mm);
 \path[every constraint line,rounded corners=0]
   (.8mm,-0mm) -- (-.6mm,-1mm) -- (.8mm,-2mm);
}

\constraintdeclareasnode{purely reflexive}{
 \path[use as bounding box] (270:2.75mm) -- (90:2.75mm);
 \path [ormdot] (180:2mm) circle;
 \draw[every constraint line] (90:1.25mm) to (270:1.25mm);
%    (-.8mm, .4mm) -- (.8mm, .4mm)
%    (-.8mm,-.4mm) -- (.8mm,-.4mm);
}

\constraintdeclareasnode{reflexive}{
 \path[use as bounding box] (270:2.75mm) -- (90:2.75mm);
 \path [ormdot] (180:2mm) circle;
}

\constraintdeclareasnode{irreflexive}{
 \path[use as bounding box] (270:2.75mm) -- (90:2.75mm);
 \path [ormdot] (180:2mm) circle;
%  \draw [every constraint line] (90:1.25mm) -- (270:1.25mm);
 \draw [every constraint line] (270:1mm) to (270:2.75mm);
}

\constraintdeclareasnode{symmetric irreflexive}{
 \path [ormdot] (180:2mm) circle;
 \path [ormdot] (  0:2mm) circle;
 \draw [every constraint line]
   (-.8mm, .4mm) -- (.8mm, .4mm)
   (-.8mm,-.4mm) -- (.8mm,-.4mm)
   (90:1.25mm) to (270:1.25mm);
}

\constraintdeclareasnode{transitive}{
 \draw[every constraint line,fill=white,draw=white] circle (2.2mm);
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \draw[every constraint line] (90:2mm) -- (210:2mm) -- (330:2mm) -- (90:2mm);
}

\constraintdeclareasnode{acyclic intransitive}{
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \path[every constraint line] (90:2mm) -- (210:2mm) -- (330:2mm) -- (90:2mm);
 \draw[every constraint line] (270:0mm) to (270:2.75mm);
}

\constraintdeclareasnode{symmetric}{
 \path [ormdot] (180:2mm) circle;
 \path [ormdot] (  0:2mm) circle;
}

\constraintdeclareasnode{asymmetric}{
 \path[use as bounding box] (270:2.75mm) -- (90:2.75mm);
 \path [ormdot] (+2mm,0mm) circle;
 \path [ormdot] (-2mm,0mm) circle;
 \draw [every constraint line] (270:1mm) to (270:2.75mm);
}

\constraintdeclareasnode{antisymmetric}{
 \path [ormdot] (180:2mm) circle;
 \path [ormdot] (  0:2mm) circle;
 \draw[every constraint line] (90:2.75mm) to (270:2.75mm);
}

\constraintdeclareasnode{tree}{
 \draw [every constraint line,fill=white,draw=white] circle (2.2mm);
 \path [ormdot]  (90:2mm) circle;
 \path [ormdot] (210:2mm) circle;
 \path [ormdot] (330:2mm) circle;
 \draw [every constraint line] (210:2mm) -- (90:2mm) -- (330:2mm);
}

% TODO: strictly order, total, connected, etc.


% TODO: test and document this
\tikzset{objectification/.style={
 entity,fill=none,
 append after command={
   \bgroup%
     [current point is local=true]
     node[orm,above=0 of \tikzlastnode] {``#1''}
   \egroup%
 }
}}


%%%% Subtypes
% TODO: how to get current line width?
\tikzstyle{inheritance}=[line width=\orm@linewidth*1.5,>=orm arrow,
 draw,color=constraintcolor]
\tikzstyle{subtype}=[inheritance,<-,solid]
\tikzstyle{suptype}=[inheritance,->,solid]
\tikzstyle{subinterface}=[subtype,dashed]
\tikzstyle{supinterface}=[suptype,dashed]

%%%% Role indices

\tikzset{index/.code={\orm@parse@index#1:\pgf@nil}}
\tikzset{index/.default=1}

\def\orm@parse@index#1:#2\pgf@nil{%
 \def\orm@temp{#2}%
 \ifx\orm@temp\pgfutil@empty%
   \orm@@parse@index1:#1:\pgf@nil%
 \else%
   \orm@@parse@index#1:#2\pgf@nil%
 \fi%
}

% \orm@verticalfalse
% \orm@verticaltrue
% \tikz@do@alignfalse

\def\orm@@parse@index#1:#2:\pgf@nil{%
 \tikzset{append after command={%
   \bgroup%
    [current point is local=true]
     let \n1 = {#1*\orm@role@width} in
     (\tikzlastnode.west) to[draw=none]
     node[role index,pos=1,sloped,anchor=east] {#2}
     ($(\tikzlastnode.west)!\n1!(\tikzlastnode.east)$)
   \egroup%
 }
}}
\tikzset{index/.default=1}


%%%% Uniqueness constraint bars

\def\orm@rolebar@length#1{#1*\orm@role@width-2*\orm@role@linewidth}
\def\orm@rolebar@shift{0.75mm} % = 3*0.25mm

\def\orm@rolebar@xshifta#1{\orm@role@linewidth+#1*\orm@role@width-\orm@role@width}
\def\orm@rolebar@xshiftb#1{#1*\orm@role@width-\orm@role@linewidth}
\def\orm@rolebar@yshift#1{%
 \ifnum#1<0-\fi0.5*\orm@role@height+#1*\orm@rolebar@shift%
}

\tikzstyle{uniqueness bar}=[every constraint line,-]
\tikzstyle{skipped uniqueness bar}=[
 every constraint line,-,dotted,preaction={every constraint line,-,white}
]

\def\orm@unique@bar@normal{uniqueness bar}
\def\orm@unique@bar@skipped{skipped uniqueness bar}
\global\let\orm@unique@bar@style=\orm@unique@bar@normal

%%
% Styles to draw external constraints
%
\pgfkeys{
 /orm/external constraint/.style={
   every constraint line,
   fill=white,text=constraintcolor,align=center,
   font=\orm@font@scriptsize,minimum size=4mm,inner sep=0pt
 }
}

% Defines an external constraints as node shape, based on the circle shape
% The symbol is *always* drawn but circle and fill can be modified.
% You can still modify the layout via color, line width, stroke opacity.
% The shapes do not respect outer sep (outer xsep/outer ysep) yet (TODO).
\newcommand{\constraintdeclareshape}[2]{%
 \expandafter\pgfdeclareshape{#1}{
   \inheritsavedanchors[from=circle]
   \inheritanchor[from=circle]{north}
   \inheritanchor[from=circle]{north west}
   \inheritanchor[from=circle]{north east}
   \inheritanchor[from=circle]{center}
   \inheritanchor[from=circle]{west}
   \inheritanchor[from=circle]{east}
   \inheritanchor[from=circle]{mid}
   \inheritanchor[from=circle]{mid west}
   \inheritanchor[from=circle]{mid east}
   \inheritanchor[from=circle]{base}
   \inheritanchor[from=circle]{base west}
   \inheritanchor[from=circle]{base east}
   \inheritanchor[from=circle]{south}
   \inheritanchor[from=circle]{south west}
   \inheritanchor[from=circle]{south east}
   \inheritanchorborder[from={circle}]
   \backgroundpath{% \behindbackgroundpath and \beforebackgroundpath don't do.
     \pgfsetdash{}{0pt}% solid circle
     \pgfutil@tempdima=\radius%
     \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
     \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
     \ifdim\pgf@xb<\pgf@yb%
       \advance\pgfutil@tempdima by-\pgf@yb%
     \else%
       \advance\pgfutil@tempdima by-\pgf@xb%
     \fi%
     \pgfpathcircle{\centerpoint}{\pgfutil@tempdima}%
   }
   \foregroundpath{%
     \pgfsetdash{}{0pt}%
     \pgfsetbuttcap%
     \pgfsetmiterjoin%
     #2 \pgfusepathqstroke%
   }
 }
 \tikzset{constraint/#1/.style={/orm/external constraint,shape=#1}}
 \tikzset{#1 constraint/.style={/orm/external constraint,shape=#1}}
}


\constraintdeclareshape{unique}{
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\radius}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\radius}%
}

\constraintdeclareshape{preferred unique}{
 \centerpoint \pgf@xc=\pgf@x \pgf@yc=\pgf@y%
 \pgfutil@tempdima=\pgflinewidth%
 \[email protected]\pgfutil@tempdima%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\radius\advance\pgf@y by-\pgfutil@tempdima}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\radius\advance\pgf@y by-\pgfutil@tempdima}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\radius\advance\pgf@y by\pgfutil@tempdima}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\radius\advance\pgf@y by\pgfutil@tempdima}%
}

\constraintdeclareshape{equal}{
 \pgfutil@tempdima=\radius% x
 \[email protected]\pgfutil@tempdima%
 \pgfutil@tempdimb=\radius% y
 \[email protected]\pgfutil@tempdimb%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgfutil@tempdima\advance\pgf@y by\pgfutil@tempdimb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgfutil@tempdima\advance\pgf@y by\pgfutil@tempdimb}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgfutil@tempdima\advance\pgf@y by-\pgfutil@tempdimb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgfutil@tempdima\advance\pgf@y by-\pgfutil@tempdimb}%
}

\constraintdeclareshape{subset}{
 \pgf@xa=\radius \[email protected]\pgf@xa% xa = 0.5 r
 \pgf@ya=\radius \[email protected]\pgf@ya% ya = 0.4 r
 \[email protected]\pgf@ya% yb = 0.5 ya = 0.2 r
 \pgf@xb=\pgf@xa \advance\pgf@xb by -\pgf@yb%

 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by-\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by \pgf@xa\advance\pgf@y by-\pgf@ya}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by \pgf@xa}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@xb}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by \pgf@xa\advance\pgf@y by\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@xb\advance\pgf@y by\pgf@ya}%
 \pgfpatharc{90}{270}{\pgf@yb}
}

\constraintdeclareshape{supset}{
 \pgf@xa=\radius \[email protected]\pgf@xa% xa = 0.5 r
 \pgf@ya=\radius \[email protected]\pgf@ya% ya = 0.4 r
 \[email protected]\pgf@ya% yb = 0.5 ya = 0.2 r
 \pgf@xb=\pgf@xa \advance\pgf@xb by -\pgf@yb%

 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by-\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by \pgf@xa\advance\pgf@y by-\pgf@ya}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by \pgf@xb}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by \pgf@xb\advance\pgf@y by\pgf@ya}%
 \pgfpatharc{90}{-90}{\pgf@yb}
}

\constraintdeclareshape{exclusive}{% exclusive constraint ('x')
 \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{45}{\radius}}}%
 \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{225}{\radius}}}%
 \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{135}{\radius}}}%
 \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{-45}{\radius}}}%
}

% inclusive-or (disjunctive mandatory role) constraint
\constraintdeclareshape{mandatory}{
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgfpathcircle{\centerpoint}{\pgf@xa}
 \pgfsetfillcolor{constraintcolor} % TODO: constraitfillcolor / not for deontic
 % use deontic dot instead?
 \pgfusepathqfillstroke
}

% exclusive-or constraint ('xor' or 'partition')
\constraintdeclareshape{partition}{
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgfpathcircle{\centerpoint}{\pgf@xa}
 \pgfsetfillcolor{constraintcolor} % TODO: constraitfillcolor / not for deontic
 \pgfusepathqfillstroke
 \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{45}{\radius}}}%
 \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{225}{\radius}}}%
 \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{135}{\radius}}}%
 \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{-45}{\radius}}}%
}

% Collection constraints (not standard ORM2)
\constraintdeclareshape{rank}{% aka ordered set
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgf@ya=\radius \[email protected]\pgf@ya%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by-\pgf@ya}%
}
\constraintdeclareshape{sequence}{%
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgf@ya=\radius \[email protected]\pgf@ya%
 \pgf@xc=\radius \[email protected]\pgf@xc%

 \pgfpathmoveto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@ya}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by-\pgf@ya}%
 \pgfusepathqstroke

 \pgfsetdash{{\pgflinewidth}{1pt}}{0pt}% dotted
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\radius}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\radius}%
}
\constraintdeclareshape{weak sequence}{%
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgf@xb=\pgflinewidth%
 \pgf@yb=\radius \[email protected]\pgf@yb%
 \pgf@ya=\radius \[email protected]\pgf@ya%

 \pgfpathmoveto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by\pgf@ya\advance\pgf@y by\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by-\pgf@ya\advance\pgf@y by\pgf@yb}%

 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@x by-\pgf@xb\advance\pgf@y by-\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@x by-\pgf@xb\advance\pgf@y by-\pgf@ya\advance\pgf@y by-\pgf@yb}%
 \pgfusepathqstroke

 \pgfsetdash{{\pgflinewidth}{1pt}}{0pt}% dotted
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\radius\advance\pgf@y by\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\radius\advance\pgf@y by\pgf@yb}%
}

\constraintdeclareshape{weak rank}{% aka poset
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgf@xb=\pgflinewidth%
 \pgf@yb=\radius \[email protected]\pgf@yb%
 \pgf@ya=\radius \[email protected]\pgf@ya%

 \pgfpathmoveto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by\pgf@ya\advance\pgf@y by\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by-\pgf@ya\advance\pgf@y by\pgf@yb}%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@x by-\pgf@xb\advance\pgf@y by-\pgf@yb}%
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@x by-\pgf@xb\advance\pgf@y by-\pgf@ya\advance\pgf@y by-\pgf@yb}%
}

\constraintdeclareshape{counted}{
 \pgf@xa=\radius \[email protected]\pgf@xa%
 \pgf@xb=\radius \[email protected]\pgf@xb%
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by\pgf@xb}
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by\pgf@xb}
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xa\advance\pgf@y by-\pgf@xb}
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xa\advance\pgf@y by-\pgf@xb}
 \pgfpathmoveto{\centerpoint\advance\pgf@x by\pgf@xb\advance\pgf@y by\pgf@xa}
 \pgfpathlineto{\centerpoint\advance\pgf@x by\pgf@xb\advance\pgf@y by-\pgf@xa}
 \pgfpathmoveto{\centerpoint\advance\pgf@x by-\pgf@xb\advance\pgf@y by\pgf@xa}
 \pgfpathlineto{\centerpoint\advance\pgf@x by-\pgf@xb\advance\pgf@y by-\pgf@xa}
}
%\constraintdeclarealias{in bag}{counted}
%\constraintdeclarealias{in multiset}{counted}

\constraintdeclareshape{external}{} % needed because shapes are in /orm/...
\constraintdeclareshape{misc}{} % alias for 'external'

%\constraintdeclare{custom}{} % empty constraint circle

\constraintdeclarealias{required}{mandatory}
\constraintdeclarealias{total}{mandatory}
\constraintdeclarealias{or}{mandatory}
\constraintdeclarealias{x}{exclusive}
\constraintdeclarealias{xor}{partition}

%%
% Styles to draw uniqueness bars
%
\pgfkeys{/orm/.cd,
   uniqueness bar from/.initial=1,%
   uniqueness bar to/.initial=1,%
   uniqueness bar level/.initial=1,%
   uniqueness bar roles/.initial=1,%
   uniqueness bar set roles/.style={%
     /orm/uniqueness bar roles=#1,
     /pgf/minimum width=#1*4mm
   },
   uniqueness bar lower/.initial=0,%
   uniqueness bar from/.value required,%
   uniqueness bar to/.value required,%
   uniqueness bar level/.value required,%
   uniqueness bar roles/.value required,%
   uniqueness bar set roles/.value required,%
   uniqueness bar lower/.value required,%
   uniqueness bar style/.style={}
}

%
% This node shape draws a uniqueness bar above or below a predicate node.
% You should use is to shape an invisible node of same size and position
% as the predicate to constraint. The bar is affected by several styles
% named '/orm/uniqueness bar ...' each.
%
\pgfdeclareshape{uniqueness bar}{
 \inheritsavedanchors[from=rectangle]
 \inheritanchorborder[from=rectangle]
 \inheritanchor[from=rectangle]{north}
 \inheritanchor[from=rectangle]{west}
 \inheritanchor[from=rectangle]{east}
 \inheritanchor[from=rectangle]{south}
 \inheritanchor[from=rectangle]{center}
 \savedmacro\barlevel{%
     \edef\barlevel{\pgfkeysvalueof{/orm/uniqueness bar level}}%
     \edef\barfrom{\pgfkeysvalueof{/orm/uniqueness bar from}}%
     \edef\barto{\pgfkeysvalueof{/orm/uniqueness bar to}}%
     \edef\barroles{\pgfkeysvalueof{/orm/uniqueness bar roles}}%
     \edef\barlower{\pgfkeysvalueof{/orm/uniqueness bar lower}}%
 }
 \foregroundpath{
   \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
   \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
   \pgfmathsetlength\pgfutil@tempdima{
       (\pgf@xb-\pgf@xa-\pgflinewidth) / (\barroles>0 ? \barroles : 1)
   }% role width
   \pgf@xb=\pgf@xa
   \advance\pgf@xa by 1.5\pgflinewidth%
   \advance\pgf@xa by -1\pgfutil@tempdima%
   \advance\pgf@xa by \barfrom\pgfutil@tempdima%
   \advance\pgf@xb by-0.5\pgflinewidth%
   \advance\pgf@xb by \barto\pgfutil@tempdima%
   \pgfmathsetlength\pgfutil@tempdima{\barlevel}%
   \pgfutil@tempdimb=3\pgflinewidth% level distance
   \ifdim\pgfutil@tempdima<0pt%
     \advance\pgf@ya by +0.5\pgflinewidth%
     \advance\pgf@ya by \barlower\pgfutil@tempdimb%
     \advance\pgf@ya by \barlevel\pgfutil@tempdimb%
     \pgf@yb=\pgf@ya%
   \else%
     \advance\pgf@yb by-0.5\pgflinewidth%
     \advance\pgf@yb by -\barlower\pgfutil@tempdimb%
     \advance\pgf@yb by \barlevel\pgfutil@tempdimb%
   \fi%
   \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yb}}%
   \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}%
}
}


% Power types
\tikzset{power/.style args={#1}{
       append after command={
           \pgfextra{
               \node[entity,shape=rectangle,rounded corners,fit={(\tikzlastnode)},label={[font=\orm@font]#1}] at (\tikzlastnode) (\tikzlastnode-power) {};
           }
       }
   }
}


% Sequence types
\tikzset{sequence/.style args={#1}{
       append after command={
           \pgfextra{
               \node[entity,shape=rectangle,rounded corners=0pt,fit={(\tikzlastnode)},label={[font=\orm@font]#1}] at (\tikzlastnode) (\tikzlastnode-sequence) {};
           }
       }
   }
}


\tikzset{
 unique/.code={\orm@parse@xunique#1:\pgf@nil},
 unique/.default=1,
}

% parses '<which>:<level>' and '<which>'
\def\orm@parse@xunique#1:#2\pgf@nil{%
 \def\orm@temp{#2}%
 \ifx\orm@temp\pgfutil@empty%
   \orm@@parse@xunique#1:1:\pgf@nil%
 \else%
   \orm@@parse@xunique#1:#2\pgf@nil%
 \fi%
}

% parses n-m:<level> and n:<level>
\def\orm@@parse@xunique#1:#2:\pgf@nil{%
 \pgfutil@in@{-}{#1}%
 \ifpgfutil@in@%
    \orm@parse@xunique@@bar#1:#2\pgf@nil%
 \else%
   \orm@parse@xunique@@bar#1-#1:#2\pgf@nil%
 \fi%
}

\def\orm@parse@xunique@@bar#1-#2:#3\pgf@nil{%
 \def\orm@tempA{#1}%
 \ifx\orm@tempA\pgfutil@empty%
   \relax%
   \orm@parse@xunique@@bar#2-#2:-1\pgf@nil
 \else%
\tikzset{append after command={
   \bgroup%
    [current point is local=true]
    let \p1 = (\tikzlastnode.west), \p2 = (\tikzlastnode.east)
    in \pgfextra{\pgfmathparse{(\x2-\x1)/4mm}}
    (\tikzlastnode) node[
       /orm/uniqueness bar from/.expand once=#1,
       /orm/uniqueness bar to/.expand once=#2,
       /orm/uniqueness bar set roles/.expand once=\pgfmathresult,
       /orm/uniqueness bar level=#3,
       shape=uniqueness bar,
       \orm@unique@bar@style,
       minimum height=2.5mm,
       /orm/uniqueness bar style
    ]{}
   \egroup
   }}%
 \fi%
}

%% Skipped uniqueness bar
% TODO: remove this duplicated code.

\tikzset{
 skip unique/.code={\orm@parse@sunique#1:\pgf@nil},
 skip unique/.default=1,
}

% parses '<which>:<level>' and '<which>'
\def\orm@parse@sunique#1:#2\pgf@nil{%
 \def\orm@temp{#2}%
 \ifx\orm@temp\pgfutil@empty%
   \orm@@parse@sunique#1:1:\pgf@nil%
 \else%
   \orm@@parse@sunique#1:#2\pgf@nil%
 \fi%
}

% parses n-m:<level> and n:<level>
\def\orm@@parse@sunique#1:#2:\pgf@nil{%
 \pgfutil@in@{-}{#1}%
 \ifpgfutil@in@%
    \orm@parse@sunique@@bar#1:#2\pgf@nil%
 \else%
   \orm@parse@sunique@@bar#1-#1:#2\pgf@nil%
 \fi%
}

\def\orm@parse@sunique@@bar#1-#2:#3\pgf@nil{%
 \def\orm@tempA{#1}%
 \ifx\orm@tempA\pgfutil@empty%
   \relax%
   \orm@parse@xunique@@bar#2-#2:-1\pgf@nil
 \else%
\tikzset{append after command={
   \bgroup%
    [current point is local=true]
    let \p1 = (\tikzlastnode.west), \p2 = (\tikzlastnode.east)
    in \pgfextra{\pgfmathparse{(\x2-\x1)/4mm}}
    \pgfextra{\let\orm@unique@bar@style=\orm@unique@bar@skipped}%
    (\tikzlastnode) node[
       /orm/uniqueness bar from/.expand once=#1,
       /orm/uniqueness bar to/.expand once=#2,
       /orm/uniqueness bar set roles/.expand once=\pgfmathresult,
       /orm/uniqueness bar level=#3,
       shape=uniqueness bar,
       \orm@unique@bar@style,
       minimum height=2.5mm
    ]{}
   \egroup
   }}%
 \fi%
}

% TODO: add optional parameters and document this
\tikzstyle{preferred unique}=[unique=1:1,unique=1:2]

\makeatother

%<–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––>
\endinput