% TODO : ajout de reglage sur la taille du nom
%\newbox\component@boxa
\newcounter{component@p@num}
\newcounter{component@r@num}
\newcounter{component@c@num}
\newcounter{component@nf@num}
\newcounter{component@a@num}
\newcounter{component@current@i}
\newcommand{\component@p}{}
\newcommand{\component@r}{}
\newcommand{\component@c}{}
\newcommand{\component@nf}{}
\newcommand{\component@a}{}
\newlength\component@width
%\newlength\component@name@width
\newlength\component@pin@space
\newlength\component@pin@length
\newlength\component@pin@size
\newlength\component@height
\newlength\component@border@a
\newlength\component@border@r
\newlength\component@border@p
\newlength\component@border@c
\newlength\component@border@nf
\newlength\component@border
\newlength\component@membrane
%\newlength\component@name@height
\setlength\component@border{5mm}

\usepackage{xkeyval,calc} 

% taken from pgf (modified to expand the list)
\def\pgffor@normal@list#1{%
  \edef\pgffor@values{#1, \noexpand\pgffor@stop,}%
%% remplace =>  \def\pgffor@values{#1, \pgffor@stop,}%
  \ifx\pgffor@values\pgffor@emptyvalues
    \def\pgffor@values{\pgffor@stop,}%
  \fi%
  \let\pgffor@body=\pgfutil@empty%
  \global\pgffor@continuetrue%
  \pgffor@collectbody}


%% PORTS
\newcommand{\declare@port}[2]{%
  \edef\@tempa{\csname component@#2\endcsname}%
  \stepcounter{component@#2@num}
  \ifx\@tempa\@empty\relax%
    \expandafter\edef\csname component@#2\endcsname{#1}%
  \else%
    \expandafter\edef\csname component@#2\endcsname{#1, \csname component@#2\endcsname}%
  \fi%
}
\define@key{port}{pos}{\def\component@port@pos{#1}}
\define@key{port}{label}{\def\component@port@label{#1}}
\define@key{port}{intern label}{\def\component@port@intern@label{#1}}
\presetkeys{port}{label=,pos=,intern label=}{}
\def\provides{\@ifnextchar[\@provides{\@provides[]}}
\def\@provides[#1]#2{
  \presetkeys{port}{pos=right}{}
  \setkeys{port}{#1}%
  \ifx\component@port@intern@label\@empty\relax%
    \def\component@port@intern@label{internlabel}%
  \else%
  \fi%
  \declare@port{{#2/\component@port@label/\component@port@pos/\component@port@intern@label}}{p}%
}
\def\requires{\@ifnextchar[\@requires{\@requires[]}}
\def\@requires[#1]#2{
  \presetkeys{port}{pos=left}{}
  \setkeys{port}{#1}%
  \ifx\component@port@intern@label\@empty\relax%
    \def\component@port@intern@label{internlabel}%
  \else%
  \fi%
  \declare@port{{#2/\component@port@label/\component@port@pos/\component@port@intern@label}}{r}%
}
\def\controls{\@ifnextchar[\@controls{\@controls[]}}
\def\@controls[#1]#2{
  \presetkeys{port}{pos=above}{}
  \setkeys{port}{#1}%
  \ifx\component@port@intern@label\@empty\relax%
    \def\component@port@intern@label{internlabel}%
  \else%
  \fi%
  \declare@port{{#2/\component@port@label/\component@port@pos/\component@port@intern@label}}{c}%
}
\def\nfc{\@ifnextchar[\@nfc{\@nfc[]}}
\def\@nfc[#1]#2{
  \presetkeys{port}{pos=below}{}
  \setkeys{port}{#1}%
  \ifx\component@port@intern@label\@empty\relax%
    \def\component@port@intern@label{internlabel}%
  \else%
  \fi%
  \declare@port{{#2/\component@port@label/\component@port@pos/\component@port@intern@label}}{nf}%
}
\def\attribute{\@ifnextchar[\@attribute{\@attribute[]}}
\def\@attribute[#1]#2{
  \presetkeys{port}{pos=below}{}
  \setkeys{port}{#1}%
  \ifx\component@port@intern@label\@empty\relax%
    \def\component@port@intern@label{internlabel}%
  \else%
  \fi%
  \declare@port{{#2/\component@port@label/\component@port@pos/\component@port@intern@label}}{a}%
}

\newcommand{\requireport}[6]{
% 1 -> pos, 2 -> pin length, 3 -> pin size, 4 -> label, 5 -> label pos, 6 -> port name
    \draw (#1) -- ++(-#2,0)  ++(-#3,-#3) arc (-90:90:#3) ;
    \draw (#1) ++(-#2,0) node[coordinate] (#4) {} ;
    \draw (#1) ++(-#2,0) ++(-0.1,0) node[#5] {#6};
}
\newcommand{\provideport}[6]{
% 1 -> pos, 2 -> pin length, 3 -> pin size, 4 -> label, 5 -> label pos, 6 -> port name
    \draw (#1) -- ++(#2,0) node[circle,inner sep=0pt,minimum size=2*#3,outer sep=0pt,fill] (#4) {} ;
    \draw (#1) ++(#2,0) ++(0.1,0) node[#5]  {#6};
}
\newcommand{\controlport}[6]{
% 1 -> pos, 2 -> pin length, 3 -> pin size, 4 -> label, 5 -> label pos, 6 -> port name
    \draw (#1) -- ++(0,#2) node[circle,inner sep=0pt,minimum size=2*#3,outer sep=0pt,fill] (#4) {} ;
    \draw (#1) ++(0,#2) ++(0,0.1) node[#5]  {#6};
}
\newcommand{\undefport}[8]{
% 1 -> pos, 2 -> pin size, 3 -> label, 4 -> label pos, 5 -> port name, 6 -> shape, 7 -> sens, 8 -> decalage
    \draw (#1) -- ++#7 node[#6,inner sep=0pt,minimum size=2*#2,outer sep=0pt,fill] (#3) {} ;
    \draw (#3) ++#8 node[#4]  {#5};
}
\newcommand{\nfport}[6]{
% 1 -> pos, 2 -> pin length, 3 -> pin size, 4 -> label, 5 -> label pos, 6 -> port name
    \draw (#1) -- ++(0,-#2) node[rectangle,inner sep=0pt,minimum size=2*#3,outer sep=0pt,fill] (#4) {} ;
    \draw (#1) ++(0,-#2) ++(0,-0.1) node[#5]  {#6};
}

\usepgflibrary{shapes.geometric}
%% COMPONENTS
\def\component@form{rectangle}
\define@key{component}{name}{\def\component@name{#1}}
\define@key{component}{label}{\def\component@label{#1}}
\define@key{component}{fill}{\def\component@fill{#1}}
\define@key{component}{width}{\setlength\component@width{#1}}
\define@key{component}{membrane}{\setlength\component@membrane{#1}}
\define@key{component}{distance}{\setlength\component@pin@space{#1}}
\define@key{component}{pin length}{\setlength\component@pin@length{#1}}
\define@key{component}{pin size}{\setlength\component@pin@size{#1}}
\define@key{component}{border}{\setlength\component@border{#1}}
\define@key{component}{name height}{\def\component@name@height{#1}}
\presetkeys{component}{name=,label=,width=1cm,distance=1cm,border=5mm,fill=none,membrane=1pt,pin length=3mm,pin size=3pt,name height=2mm}{}
\def\component{\@ifnextchar[\@component{\@component[]}}
\def\@component[#1]#2{%
  \setkeys{component}{#1}%
  \setcounter{component@r@num}{-1}
  \setcounter{component@p@num}{-1}
  \setcounter{component@c@num}{-1}
  \setcounter{component@nf@num}{-1}
  \def\component@pos{#2}
%   \setbox\component@boxa\hbox{SECURITE}
%   \setlength\component@name@width{\wd\component@boxa}
%     \show\component@name@width
%   \ifdim\wd\component@boxa>\component@width
%     \setlength\component@width{\component@name@width}
%     \show\component@width
%   \else
%   \fi
}
\def\endcomponent{
  \setlength\component@border@a{\component@border}
  \setlength\component@border@r{\component@border}
  \setlength\component@border@p{\component@border}
  \setlength\component@border@c{(\component@width-\component@pin@space*\value{component@c@num})/2}
  \setlength\component@border@nf{(\component@width-\component@pin@space*\value{component@nf@num})/2}
  \ifnum\value{component@r@num}>\value{component@p@num}
    \setlength\component@height{\component@border@r*2+\component@pin@space*\value{component@r@num}}
    \setlength\component@border@p{\component@border@r + \component@pin@space*(\value{component@r@num}-\value{component@p@num})/2}
  \else
    \setlength\component@height{\component@border@p*2+\component@pin@space*\value{component@p@num}}
    \setlength\component@border@r{\component@border@p + \component@pin@space*(\value{component@p@num}-\value{component@r@num})/2}
  \fi
  %COMPONENT
  \ifx\component@label\empty%
    \def\component@label{temp component}
  \else%
  \fi%
  \ifx\component@fill\empty%
    \def\component@fill@opt{}
  \else%
    \def\component@fill@opt{fill=\component@fill}
  \fi%
  \draw[line width=\component@membrane] \component@pos ++(\component@width/2,\component@height/2) node[draw,fill=\component@fill,minimum width=\component@width,minimum height=\component@height,\component@form] (\component@label) {} ;
  \draw \component@pos ++(\component@width/2,\component@name@height) node {\component@name} ;
  %REQUIRES
  \setcounter{component@current@i}{0}
  \begin{scope}[line width=1pt]
  \foreach \port@name/\port@label/\port@label@pos/\port@label@in in {\component@r}
    { 
    \draw \component@pos ++(0cm,\component@border@r+\component@pin@space*\value{component@current@i}) node[coordinate] (\port@label@in) {} ;
    \requireport{\port@label@in}{\component@pin@length}{\component@pin@size}{\port@label}{\port@label@pos}{\port@name}
% 1 -> pos, 2 -> pin length, 3 -> pin size, 4 -> label, 5 -> label pos, 6 -> port name
    \addtocounter{component@current@i}{1}
    }
  %PROVIDES
  \setcounter{component@current@i}{0}
  \foreach \port@name/\port@label/\port@label@pos/\port@label@in in {\component@p}
    {
    \draw \component@pos ++(\component@width,\component@border@p+\component@pin@space*\value{component@current@i}) node[coordinate] (\port@label@in) {};
    \provideport{\port@label@in}{\component@pin@length}{\component@pin@size}{\port@label}{\port@label@pos}{\port@name}
    \addtocounter{component@current@i}{1}
    }
  %CONTROLS
  \setcounter{component@current@i}{0}
  \foreach \port@name/\port@label/\port@label@pos/\port@label@in in {\component@c}
    {
    \draw \component@pos ++(\component@border@c+\component@pin@space*\value{component@current@i},\component@height) node[coordinate] (\port@label@in) {};
    \controlport{\port@label@in}{\component@pin@length}{\component@pin@size}{\port@label}{\port@label@pos}{\port@name}
    \addtocounter{component@current@i}{1}
    }
  %NF CONTRACTS
  \setcounter{component@current@i}{0}
  \foreach \port@name/\port@label/\port@label@pos/\port@label@in in {\component@nf}
    {
    \draw \component@pos ++(\component@border@nf+\component@pin@space*\value{component@current@i},0) node[coordinate] (\port@label@in) {};
    \nfport{\port@label@in}{\component@pin@length}{\component@pin@size}{\port@label}{\port@label@pos}{\port@name}
    \addtocounter{component@current@i}{1}
    }
  %ATTRIBUTES
  \setcounter{component@current@i}{0}
  \foreach \port@name/\port@label/\port@label@pos/\port@label@in in {\component@a}
    {
    \draw \component@pos ++(\component@border@a+\component@pin@space*\value{component@current@i},\component@height-\component@border@a) node[coordinate] (\port@label@in) {};
    \draw (\port@label@in) node[rectangle,inner sep=0pt,minimum size=2\component@pin@size,outer sep=0pt,draw,fill=white,rounded corners,thin] (\port@label) {} ;
    \draw (\port@label@in) ++(0,-0.15) node[\port@label@pos]  {\tiny\port@name};
    \addtocounter{component@current@i}{1}
    }
  \end{scope}
}

