\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{byrne}[2022/01/06 Byrne]

\RequirePackage{xparse}
\RequirePackage{ifmtarg}
\RequirePackage{luamplib} % version v2.22.0 is required
\mplibsetformat{metafun}

\mplibglobaltextext{enable}
\newcount\mpInst
\mpInst = 0

\def\mpPre{}
\def\mpPost{}

\newif\ifCreateNewInstanceForPicture
\CreateNewInstanceForPicturetrue

\def\undefineList{}

\directlua{
function byFormatImageName(s)
       local resultingName = s:gsub ("," , "")
       tex.print("instanceOffspringPicture"..resultingName)
end
}

\def\formatImageName#1{\directlua{byFormatImageName("#1")}}


\DeclareDocumentCommand{\defineNewPicture}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\sfA{1/3}}%
               {\global\def\sfA{#1}}%
       \IfNoValueTF{#2}%
               {\global\def\sfB{defaultScaleFactor}}%
               {\global\def\sfB{#2}}%
       \undefineList%
       \def\undefineList{}%
       \ifCreateNewInstanceForPicture%
               \global\advance \mpInst by 1%
               \global\def\currentInstance{byInstance\the\mpInst}%
       \fi%
       \setbox0\vbox{%
       \everymplib[\currentInstance]{beginfig(0);}%
       \everyendmplib[\currentInstance]{endfig;}%
       \begin{mplibcode}[\currentInstance]%
               picture instanceMainPicture;
               input byrne;
               \mpPre
               instanceMainPicture := image(
                       startMainPictureMode;
                       projectionAngle := (0, 0, 0);
                       linecap := butt;
                       scaleFactor := \sfB;
                               #3
                       scaleFactor := \sfA;
                       generateAngleSynonyms;
                       generateLineSynonyms;
                       stopMainPictureMode;
               );
               \mpPost
       \end{mplibcode}%
       }\global\addToUndefineList{#2}%
}

\def\drawImageFromCurrentInstance#1{
       \begin{mplibcode}[\currentInstance]%
               draw #1;
       \end{mplibcode}%
}

% Every time some simple picture is drawn, new macro is defined
% with \markPictAsReady. If macro is defined, predefined picture is used.
% Every time new picture is added, instructions to undefine it are added with
% \addToUndefineList. \undefineList is thus generated command, that, once executed,
% undefines everything that was appended to it with \addToUndefineList.

\def\unmarkPictAsReady#1{\expandafter\let\csname #1\endcsname\@undefined}

\def\addToUndefineList#1{\expandafter\def\expandafter\undefineList\expandafter{\undefineList \unmarkPictAsReady{#1}}}

\def\undefineList{}
\addToUndefineList{lastPicture}

% When larger picture is defined, we can visualize its parts with \drawFromCurrentPicture
% First (optional) argument is for picture's vertical alignment relative to the string
% Currently only `middle' and anything other (for `top') is working
% Second (optional) argument is for picture's name for future reuse
% If picture with the same name exists, it's not defined again.
% Third argument is MP code for picture itself.
% To actually define an inline picture \defineFromCurrentPicture is called.
% The latter can also be called separately, which can be convenient
% if one wants to define multiple inline pictures in one place.
% Whenever everything is defined, \drawDefinedPicture macro is called for

\def\defineFromCurrentPicture#1#2#3{%
       \begin{mplibcode}[\currentInstance]%
               picture \formatImageName{#2};
               \formatImageName{#2} = image(
                       startOffspringPictureMode;
                       linecap := butt;
                       #3
                       stopOffspringPictureMode;
               );
       \end{mplibcode}%
\global\def\lastPict{#2}%
\global\expandafter\edef\csname\lastPict\endcsname{{\noexpand\drawDefinedPicture{\expandafter\lastPict}{\expandafter#1}}}}

\DeclareDocumentCommand{\drawFromCurrentPicture}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\currentInlinePicturePlacement{middle}}%
               {\global\def\currentInlinePicturePlacement{#1}}%
       \IfNoValueTF{#2}%
               {\defineFromCurrentPicture{\currentInlinePicturePlacement}{lastPicture}{#3}}%
               {\expandafter\ifx\csname #2\endcsname\relax%
                               \defineFromCurrentPicture{\currentInlinePicturePlacement}{#2}{#3}%
                               \global\addToUndefineList{#2}%
                       \else%
                               \global\def\lastPict{#2}%
                       \fi}%
       \csname\lastPict\endcsname%
}

% \drawDefinedPicture draws defined and named picture, aligned as needed and,
% possibly, with margins modified with \offsetPicture (i. e., if we want picture to act as if it's less tall that it actually is,
% we put some value as its first argument, if we want picture to be less deep, we use second argument, and place picture
% itself as third).

\newdimen\pictOffsetTop
\newdimen\pictOffsetBottom

\pictOffsetTop=0pt
\pictOffsetBottom=0pt

\def\offsetPicture#1#2#3{{\pictOffsetTop=#1\pictOffsetBottom=#2#3\pictOffsetTop=0pt\pictOffsetBottom=0pt}}

\newdimen\midht
\newdimen\middp
\def\drawDefinedPicture#1#2{%
       \setbox0\vbox{\drawImageFromCurrentInstance{\formatImageName{#1}}}%
       \ifdim\ht0<\baselineskip\advance\pictOffsetTop by 1pt\advance\pictOffsetBottom by 1pt\fi%
       \setbox0\vbox{\vskip2pt\vskip-\pictOffsetTop\box0\vskip2pt\vskip-\pictOffsetBottom}%
       \def\tmpmiddle{middle}%
       \def\tmpalignment{#2}%
       \ifx\tmpalignment\tmpmiddle%
               \middp=0.5\ht0
               \midht=0.5\ht0
               \advance\middp by -3pt
               \advance\midht by 3pt
       \else%
               \middp=0pt
               \midht=\ht0
               \advance\middp by 3pt
               \advance\midht by -3pt
       \fi%
       \advance\middp by 0.5\pictOffsetTop
       \advance\midht by -0.5\pictOffsetTop
       \advance\middp by -0.5\pictOffsetBottom
       \advance\midht by 0.5\pictOffsetBottom
       \dp0=\middp
       \ht0=\midht
       \nobreak\hskip0pt\nobreak\,\nobreak\box0\,%
}

% Some convenient shorthand macros for commonly used derivations of definition picture are defined below

\def\drawCurrentPicture{\drawImageFromCurrentInstance{instanceMainPicture}}


\DeclareDocumentCommand{\drawUnitLine}{o m}{%
       \IfNoValueTF{#1}%
               {\drawFromCurrentPicture[middle][uline#2]{startAutoLabeling;draw byNamedCompoundLine(1cm, 0)(#2);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[middle][uline#2#1]{startAutoLabeling;draw byNamedCompoundLine(#1, 0)(#2);stopAutoLabeling;}}%
}

\def\drawProportionalLine#1{\drawFromCurrentPicture[middle][pline#1]{startAutoLabeling;draw byNamedCompoundLine(1cm, 1)(#1);stopAutoLabeling;}}

\DeclareDocumentCommand{\drawSizedLine}{o m}{%
       \IfNoValueTF{#1}%
               {\drawFromCurrentPicture[middle][sline#2]{startAutoLabeling;draw byNamedCompoundLine(2cm, 2)(#2);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[middle][sline#2#1]{startAutoLabeling;draw byNamedCompoundLine(#1, 2)(#2);stopAutoLabeling;}}%
}

\DeclareDocumentCommand{\drawUnitRay}{o m}{%
       \IfNoValueTF{#1}%
               {\drawFromCurrentPicture[middle][uray#2]{startAutoLabeling;draw byNamedCompoundRay(1cm, 0)(#2);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[middle][uray#2#1]{startAutoLabeling;draw byNamedCompoundRay(#1, 0)(#2);stopAutoLabeling;}}%
}

\def\drawProportionalRay#1{\drawFromCurrentPicture[middle][pray#1]{startAutoLabeling;draw byNamedCompoundRay(1cm, 1)(#1);stopAutoLabeling;}}

\DeclareDocumentCommand{\drawSizedRay}{o m}{%
       \IfNoValueTF{#1}%
               {\drawFromCurrentPicture[middle][sray#2]{startAutoLabeling;draw byNamedCompoundRay(2cm, 2)(#2);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[middle][sray#2#1]{startAutoLabeling;draw byNamedCompoundRay(#1, 2)(#2);stopAutoLabeling;}}%
}

\def\drawProportionalIndLine#1{\drawFromCurrentPicture[middle][lineindprop#1]{startAutoLabeling;draw byNamedCompoundIndLine(1cm, 1)(#1);stopAutoLabeling;}}

\DeclareDocumentCommand{\drawUnitIndLine}{o m}{%
       \IfNoValueTF{#1}%
               {\drawFromCurrentPicture[middle][lineindsized#2]{startAutoLabeling;draw byNamedCompoundIndLine(2cm, 2)(#2);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[middle][lineindsized#2#1]{startAutoLabeling;draw byNamedCompoundIndLine(#1, 2)(#2);stopAutoLabeling;}}%
}

\def\drawRightAngle{%
\drawFromCurrentPicture[middle][onerightangle]{draw rightAngle;}}

\def\drawTwoRightAngles{%
\drawFromCurrentPicture[middle][tworightangles]{draw twoRightAngles;}}

\def\drawAngle#1{\drawFromCurrentPicture[middle][angle#1]{startAutoLabeling;draw byNamedAngleWithDummySides(#1);stopAutoLabeling;}}

\def\drawAngleWithSides#1{\drawFromCurrentPicture[middle][anglewithsides#1]{startAutoLabeling;draw byNamedAngleSides(#1)();stopAutoLabeling;}}

\DeclareDocumentCommand{\drawPolygon}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][polygon#3]{startAutoLabeling;draw byNamedPolygon(#3);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[\plal][#2]{startAutoLabeling;draw byNamedPolygon(#3);stopAutoLabeling;}}%
}

\DeclareDocumentCommand{\drawCircle}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][circle#3]{startAutoLabeling;draw byNamedCircle(#3);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[\plal][circle#3]{
               startAutoLabeling;
               startTempScale(#2);
               draw byNamedCircle(#3);
               stopTempScale;
               stopAutoLabeling;
               }}%
}

\DeclareDocumentCommand{\drawArc}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][arc#3]{startAutoLabeling;draw byNamedArc(#3);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[\plal][arc#3]{
               startAutoLabeling;
               startTempScale(#2);
               draw byNamedArc(#3);
               stopTempScale;
               stopAutoLabeling;
               }}%
}

\DeclareDocumentCommand{\drawLine}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][line#3]{startAutoLabeling;draw byNamedLineSeq(0)(#3);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[\plal][#2]{startAutoLabeling;draw byNamedLineSeq(0)(#3);stopAutoLabeling;}}%
}

\def\drawPointM#1{\drawFromCurrentPicture[middle][pointm#1]{startAutoLabeling; draw byNamedPointMark(#1); stopAutoLabeling;}}

\DeclareDocumentCommand{\drawPointL}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][pointl#3]{startAutoLabeling; draw byNamedPointLines(#3,""); stopAutoLabeling;}}%
               {\drawFromCurrentPicture[\plal][pointl#3Minus#2]{startAutoLabeling; draw byNamedPointLines(#3,"#2"); stopAutoLabeling;}}%
}

\DeclareDocumentCommand{\drawPoint}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][point#3]{
               startAutoLabeling; draw byNamedPointLines(#3,""); stopAutoLabeling;
               draw byNamedPointMark(#3);
               }}%
               {\drawFromCurrentPicture[\plal][point#3Minus#2]{
               startAutoLabeling; draw byNamedPointLines(#3,"#2"); stopAutoLabeling;
               draw byNamedPointMark(#3);
               }}%
}

\DeclareDocumentCommand{\drawMagnitude}{o o m}{%
       \IfNoValueTF{#1}%
               {\global\def\plal{middle}}%
               {\global\def\plal{#1}}%
       \IfNoValueTF{#2}%
               {\drawFromCurrentPicture[\plal][magnitude#3]{startAutoLabeling;draw byNamedMagnitude(0)(#3);stopAutoLabeling;}}%
               {\drawFromCurrentPicture[\plal][magnitude#2#3]{startAutoLabeling;draw byNamedMagnitude(#2)(#3);stopAutoLabeling;}}%
}