%
%  Haim Bar      haim.bar@uconn.edu
%  HaiYing Wang  haiying.wang@uconn.edu
%
%  This package is based on an ongoing work by Haim Bar and HaiYing Wang, and comments and questions are welcome!

\newif\ifruncode
% Change to \runcodefalse if you want to suspend code execution
\runcodetrue
\DeclareOption{run}{\runcodetrue}
\DeclareOption{cache}{\runcodefalse}

\newif\ifminted
\mintedtrue
\DeclareOption{nominted}{\mintedfalse}

\DeclareOption{R}{
  % create a configuration file for R server if it does not exist.
  \IfFileExists{R.config}{}{
    \newwrite\tempfile
    \immediate\openout\tempfile=R.config
    \immediate\write\tempfile{[SERVERCONFIG]}
    \immediate\write\tempfile{PORT = 65432}
    \immediate\write\tempfile{DEBUGFILE = Rdebug.txt}
    \immediate\write\tempfile{PIPETIMEOUT = 300}
    \immediate\closeout\tempfile
  }
  % Start the server. Need to run just once. Can comment out after the first
  % compilation, but remember to terminate the server
  \immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","R") if not client("./","R","``` ```") else print("server is already running")'}
  % Some editors terminate all child processes after LaTeX compiling such as Emacs with Auctex. For this case, use the following line instead of the above line.
  % \immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","R") if not client("./","R","``` ```") else print("server is already running")' &}
}

\DeclareOption{julia}{
  % create a configuration file for R server if it does not exist.
  \IfFileExists{julia.config}{}{
    \newwrite\tempfile
    \immediate\openout\tempfile=julia.config
    \immediate\write\tempfile{[SERVERCONFIG]}
    \immediate\write\tempfile{PORT = 65431}
    \immediate\write\tempfile{DEBUGFILE = juliadebug.txt}
    \immediate\write\tempfile{PIPETIMEOUT = 300}
    \immediate\closeout\tempfile
  }
  % Start the server. Need to run just once. Can comment out after the first
  % compilation, but remember to terminate the server
  \immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","julia") if not client("./","julia","``` ```") else print("server is already running")'}
  % \immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","julia") if not client("./","julia","``` ```") else print("server is already running")' &}
}

\DeclareOption{matlab}{
  % create a configuration file for R server if it does not exist.
  \IfFileExists{matlab.config}{}{
    \newwrite\tempfile
    \immediate\openout\tempfile=matlab.config
    \immediate\write\tempfile{[SERVERCONFIG]}
    \immediate\write\tempfile{PORT = 65430}
    \immediate\write\tempfile{DEBUGFILE = matlabdebug.txt}
    \immediate\write\tempfile{PIPETIMEOUT = 300}
    \immediate\closeout\tempfile
  }
  % Start the server. Need to run just once. Can comment out after the first
  % compilation, but remember to terminate the server
  \immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","matlab") if not client("./","matlab","``` ```") else print("server is already running")'}
  % \immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","matlab") if not client("./","matlab","``` ```") else print("server is already running")' &}
}

\DeclareOption{stopserver}{
  \AtEndDocument{
  %% stop the server when the pdf compilation is done.
    \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","R","QUIT")'}
    \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","QUIT")'}
    \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","QUIT")'}
}}

\ProcessOptions*

\usepackage[many]{tcolorbox}            % to put boxes around text
\usepackage{xcolor}               % for highlighting
\usepackage[utf8x]{inputenc}
\usepackage{textgreek}
\usepackage{filecontents}
\usepackage{xifthen}
\usepackage{xparse}
\usepackage{xstring}

% Use minted if it is loaded; otherwise use fvextra
\ifminted
\usepackage[cache=false]{minted}
\else
\usepackage{fvextra}
\fi

\immediate\write18{mkdir tmp}

\definecolor{bg}{rgb}{0.95,0.95,0.95} % code block background color

\newcounter{codelisting}
\renewcommand{\thecodelisting}{\arabic{codelisting}}
\newenvironment{codelisting}[1][]{
 \par\vspace{\baselineskip}\noindent
  \refstepcounter{codelisting}
  \begin{ttfamily}
   \noindent \textbf{Listing~\thecodelisting. #1}
}
{
 \end{ttfamily}
  \noindent\ignorespacesafterend
 }  

% counter for code output temporary file names
\newcounter{codeOutput}
\setcounter{codeOutput}{0}

% a command to set the temporary file name for code output
\newcommand{\setvalue}[2]{
    \ifdefined #1
        \renewcommand{#1}{#2}
    \else
        \newcommand{#1}{#2}
    \fi
}
\setvalue{\tmpname}{} % initialize with a blank



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
% \showCode prints the source code, using minted for a pretty layout
% Arg #1 is the programming language,
% Arg #2 is the source file name,
% Args #3 and #4 are the first and last line to show (optional).

\NewDocumentCommand{\showCode}{m m O{} O{}}{% \-\\
  \ifthenelse{\isempty{#3}}{
    \ifminted
    \inputminted[fontsize=\footnotesize,linenos, frame=single, bgcolor=bg, breaklines=true]{#1}{#2}
    \else
    \VerbatimInput[fontsize=\footnotesize,frame=single,breaklines]{#2}
    \fi
  }{
    \ifminted
    \inputminted[fontsize=\footnotesize,linenos,frame=single, bgcolor=bg, breaklines=true, firstline=#3, lastline=#4, firstnumber=1]{#1}{#2}
    \else
    \VerbatimInput[fontsize=\footnotesize,frame=single,breaklines, firstline=#3, lastline=#4, firstnumber=1]{#2}
    \fi
  }
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \runExtCode runs an external code.
% Arg #1 is the executable program,
% Arg #2 is the source file name,
% Arg #3 is the output file name (optional - if not given, the counter 
%        codeOutput is used).
% Arg #4 controls when to run the code (optional - if not given, it listens
%        to \runcode; run = force the code to run; cache or anything else =
%        use cache)
\NewDocumentCommand{\runExtCode}{m m m O{}}{
  \stepcounter{codeOutput}
  \ifthenelse{\isempty{#3}}
    { \setvalue{\tmpname}{tmp/\jobname_tmp\thecodeOutput.tex} }
    { \setvalue{\tmpname}{tmp/#3.tex} }
  % toggle \runcode above if you want to enable/disable code execution
    \ifthenelse{\isempty{#4}}
      { \ifruncode
        \immediate\write18{#1 #2 > \tmpname }
        \fi
      }{
        \ifstrequal{#4}{run}{\immediate\write18{#1 #2 > \tmpname }}{}
      }
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \includeOutput[Arg #1]{Arg #2} is used to embed the output from executed code.
% Arg #1 is the output file name (optional - if not given, the counter 
%        codeOutput is used).
% Arg #2 is the optional type output with default "vbox"
%         (vbox = verbatim in a box, tex = pure latex, or inline)

\NewDocumentCommand{\includeOutput}{m O{vbox}}{\-
  \ifthenelse{\isempty{#1}}
  {\setvalue{\tmpname}{tmp/\jobname_tmp\thecodeOutput.tex}}
  {\unskip\setvalue{\tmpname}{tmp/#1.tex}\unskip}\unskip
  % even if the code is not executed, but we ran it before, we can use a 
  % cached version if it exists.
  \IfFileExists{\tmpname}
  {
    \ifstrequal{#2}{vbox}
    {\begin{tcolorbox}[breakable,colback=red!5!white,colframe=red!75!black]
        \ifminted\unskip
 \inputminted[fontsize=\footnotesize,breaklines=true]{text}{\tmpname}\unskip
        \else\unskip
        \VerbatimInput[fontsize=\footnotesize,breaklines]{\tmpname}\unskip
        \fi
      \end{tcolorbox}}
    {\unskip\ifstrequal{#2}{inline}
      {\unskip\input{\tmpname}\unskip}
      {\input{\tmpname}}}}
  % if code execution disabled, and no cache:
  {\begin{tcolorbox}
      Code execution disabled (cache not available).
    \end{tcolorbox}}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \inln{Arg #1}{Arg #2}[Arg #3] is used to execute short source code
% and embed resulting output.
% Arg #1 is the executable program;
% Arg #2 is the source code
% Arg #3 is the type output (if skipped or with empty value the default type is
%        inline; vbox = verbatim in a box);

\NewDocumentCommand{\inln}{m m O{inline}}{\-
  \stepcounter{codeOutput}\unskip
  \unskip\setvalue{\tmpname}{tmp/\jobname_inln\thecodeOutput}\unskip\unskip\unskip
  \IfBeginWith{#2}{```}{\ifruncode\immediate\write18{#1 > \tmpname.tex}\unskip\fi}
  {\newwrite\tempfile
    \immediate\openout\tempfile=\tmpname.txt
    \immediate\write\tempfile{#2}
    \immediate\closeout\tempfile
    \ifruncode
    \immediate\write18{#1 \tmpname.txt > \tmpname.tex}\unskip
    \fi}
  \IfFileExists{\tmpname.tex}
  {\unskip
    \ifstrequal{#3}{vbox}
        {\begin{tcolorbox}[breakable,colback=red!5!white,colframe=red!75!black]
        \ifminted\unskip
 \inputminted[fontsize=\footnotesize,breaklines=true]{text}{\tmpname.tex}\unskip
        \else\unskip
        \VerbatimInput[fontsize=\footnotesize,breaklines]{\tmpname.tex}\unskip
        \fi
      \end{tcolorbox}}
    {\unskip\input{\tmpname.tex}\unskip}}
    {\textcolor{red}{notrun}}}

\NewDocumentCommand{\runR}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","R","#2")'} m m O{}}
{ 
  \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","R","#2")'}
  \ifstrequal{#1}{\runcmd}
  {\runExtCode{#1}{}{#3}[#4]}
  {\runExtCode{#1}{#2}{#3}[#4]}
}

\NewDocumentCommand{\inlnR}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","R","\tmpname.txt")'} m O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;client("./","R","#2")'}{#2}[#3]}{\inln{#1}{#2}[#3]}}

\NewDocumentCommand{\runJulia}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","#2")'} m m O{}}
{ 
  \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","#2")'}
  \ifstrequal{#1}{\runcmd}
  {\runExtCode{#1}{}{#3}[#4]}
  {\runExtCode{#1}{#2}{#3}[#4]}
}

\NewDocumentCommand{\inlnJulia}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","\tmpname.txt")'} m O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;client("./","julia","#2")'}{#2}[#3]}{\inln{#1}{#2}[#3]}}

\NewDocumentCommand{\runMatlab}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","#2")'} m m O{}}
{ 
  \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","#2")'}
  \ifstrequal{#1}{\runcmd}
  {\runExtCode{#1}{}{#3}[#4]}
  {\runExtCode{#1}{#2}{#3}[#4]}
}

\NewDocumentCommand{\inlnMatlab}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","\tmpname.txt")'} m O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;client("./","matlab","#2")'}{#2}[#3]}{\inln{#1}{#2}[#3]}}

\endinput
