%D \module
%D   [     file=t-filter,
%D      version=2010.09.25,
%D        title=\CONTEXT\ User Module,
%D     subtitle=Filter,
%D       author=Aditya Mahajan,
%D         date=\currentdate,
%D    copyright=Aditya Mahajan,
%D        email=adityam <at> umich <dot> edu,
%D      license=Simplified BSD License]

\writestatus{loading}{ConTeXt User Module / Filter}

\startmodule    [filter]

\unprotect

\startmode[\s!mkiv]
  \ctxloadluafile{t-filter}
\stopmode


\startinterface all
  \setinterfaceconstant {filter}           {filter}
  \setinterfaceconstant {filtercommand}    {filtercommand}
  \setinterfaceconstant {output}           {output} 
  \setinterfaceconstant {read}             {read} 
  \setinterfaceconstant {readcommand}      {readcommand} 

  \setinterfacevariable {httpget}          {httpget}
  \setinterfacevariable {httppost}         {httppost}
\stopinterface

\def\??externalfilter??{externalfilter}
\def\currentexternalfilter{}
\def\externalfiltercountername{\??externalfilter??-\currentexternalfilter-counter}

\newwrite\externalfilterwrite

\def\externalfilterparameter#1%
  {\csname
     \docheckparentparameter{\??externalfilter??\currentexternalfilter}{#1}%
   \endcsname}

\def\docheckparentparameter#1#2%
  {\ifcsname#1#2\endcsname
      #1#2%
    \else
      \expandafter\redocheckparentparameter\csname#1\s!parent\endcsname{#2}%
    \fi}

\def\redocheckparentparameter#1#2%
  {\ifx#1\relax
      \s!empty
   \else
      \docheckparentparameter{#1}{#2}%
   \fi}

\def\setupexternalfilters
  {\dodoubleargument\dosetupexternalfilters}
  
\def\dosetupexternalfilters[#1][#2]%
  {\ifsecondargument
     \getparameters[\??externalfilter??#1][#2]%
   \else
     \getparameters[\??externalfilter??][#1]%
   \fi}


\def\defineexternalfilter
  {\dodoubleargument\dodefineexternalfilter}

\def\dodefineexternalfilter[#1][#2]%
  {\edef\currentexternalfilter{#1}%
  \getparameters[\??externalfilter??#1][\s!parent=\??externalfilter??,#2]%
   \doif{\externalfilterparameter\c!continue}\v!yes
      {\expandafter\newcounter\csname\externalfiltercountername\endcsname}%
   \setvalue{\e!start#1}{\bgroup\obeylines\dodoubleargument\dostartexternalfilter[#1]}%
   \setvalue{\e!stop#1}{\doprocessexternalfilter}%
   \setvalue{process#1file}{\dodoubleargument\doprocessexternalfiler[#1]}%
   \setvalue{inline#1}{\doinlineexternalfilter[#1]}
   }


\chardef\externalfilter!!method\zerocount    %0 = os, 1 = httpget, 2 = httppost

\def\dostartexternalfilter[#1][#2]% filter options
  {% Initializations
   \egroup %\bgroup in \start#1
   \begingroup % to keep assignments local
   \edef\currentexternalfilter   {#1}%
   \getparameters[\??externalfilter??#1][\c!name=,#2]%
   \processaction[\externalfilterparameter\c!method]
                 [\v!httpget  => \chardef\externalfilter!!method\plusone ,
                  \v!httppost => \chardef\externalfilter!!method\plustwp ,
                  \v!default  => \chardef\externalfilter!!method\zerocount ,
                  \v!unknown  => \chardef\externalfilter!!method\zerocount ]%
   % Set the name of temp file for os filter
   \setexternalfilterfilenames
   % Capture the contents of the buffer
   \dostartbuffer[\externalfiltertmpfile][\e!start#1][\e!stop#1]}

\def\setexternalfilterfilenames%
  {% Set the name of temp file for os filter
   \doifelse{\externalfilterparameter\c!continue}\v!yes
       {\edef\externalfiltertmpfile{\??externalfilter??-\currentexternalfilter-\csname\externalfiltercountername\endcsname}}
       {\edef\externalfiltertmpfile{\??externalfilter??-\currentexternalfilter}}
   \doifsomething{\externalfilterparameter\c!name}
       {\edef\externalfiltertmpfile{\externalfilterparameter\c!name}}
   % The following  macros are useful for filter= and filtercommand= options
   % The basename of the external file 
   \edef\externalfilterbasefile  {\jobname-\externalfiltertmpfile}%
   % The name of the buffer to which data is written
   \edef\externalfilterinputfile {\externalfilterbasefile.tmp}%
   % The name of the file to which the output is written
   \edef\externalfilteroutputfile{\externalfilterparameter\c!output}%
  }

\def\doprocessexternalfilter%
  {\ifcase\externalfilter!!method % os 
     % By defualt, buffers are in memory in MkIV
     \doifmode\s!mkiv{\savebuffer[\externalfiltertmpfile]}%
     % Run external command
     \doexecuteexternalfilter
   \or % httpget
     \doexecutehttpgetfilter
   \or % httppost
     \doexecutehttpostfilter
   \fi
   \doreadprocessedfile
   \endgroup 
   % Finalization
   \ifnum\externalfilter!!method=\zerocount
     \doif{\externalfilterparameter\c!continue}\v!yes
          {\expandafter\increment\csname\externalfiltercountername\endcsname}%
   \fi
   }

\def\doexecuteexternalfilter
  {\doifelse{\externalfilterparameter\c!continue}\v!yes
   {\doifmode{*first}
     {\executesystemcommand
      {mtxrun --ifchanged=\externalfilterinputfile\space 
          bin:\externalfilterparameter\c!filtercommand}}}
   {\executesystemcommand
      {\externalfilterparameter\c!filtercommand}}}

\def\doexecutehttpgetfilter
  {\doifmodeelse{\s!mkiv}
    {\edef\externalfilteroutputfile{\ctxlua{thirddata.externalfilter.httpget
      (\!!bs\externalfilterparameter\c!filter\!!es  ,
       \!!bs\externalfiltertmpfile\!!es             ,
       \!!bs\externalfilterparameter\c!separator\!!es)}}}
    {{\tttf TODO: httpget does not work in MkII}}}

\def\doexecutehttppostfilter
    {{\tttf TODO: httppost is not yet implemented}}
  

\def\doreadprocessedfile
  {\doif{\externalfilterparameter\c!read}\v!yes
      {\doiffileelse{\externalfilteroutputfile}
          {\dodoreadprocessedfile}
          %TODO: Proper error message
          {{\tttf File \externalfilteroutputfile\ not found! Check your definition}}}}

\def\dodoreadprocessedfile
  {\begingroup
   \externalfilterparameter\c!before
   \processcommacommand[\externalfilterparameter\c!setups]\directsetup
   \externalfilterparameter\c!readcommand\externalfilteroutputfile
   \externalfilterparameter\c!after
   \endgroup}

\def\doprocessexternalfiler[#1][#2]%
  {\edef\currentexternalfilter    {#1}%
   \edef\externalfilterinputfile  {#2}%
   \splitfiletype {#2}%
   %BEWARE. \edef doesn not work
   \def\externalfilterbasefile   {\splitoffname}
   \def\externalfilteroutputfile{\externalfilterparameter\c!output}%
   \doexecuteexternalfilter
   \doreadprocessedfile}
   
\def\doinlineexternalfilter[#1]%
  {\begingroup % to keep assignments local
   \edef\currentexternalfilter {#1}%
   \getparameters[\??externalfilter??#1][\c!name=,\c!continue=\v!no]%
   \setexternalfilterfilenames
   \pushcatcodetable
   \futurelet\next\dodoinlineexternalfilter}

\def\dodoinlineexternalfilter
  {\ifx\next\bgroup
     \expandafter\dodoinlineexternalfilterA
   \else
     \expandafter\dodoinlineexternalfilterB
   \fi}

\def\dodoinlineexternalfilterA
  {\setcatcodetable \typcatcodesa
   \redoinlineexternalfilter}

\def\dodoinlineexternalfilterB#1%
  {\setcatcodetable \vrbcatcodes
   \def\dododoinlineexternalfilterB##1#1{\redoinlineexternalfilter{##1}}%
   \dododoinlineexternalfilterB}

\def\redoinlineexternalfilter#1%
  {\immediate\openout \externalfilterwrite\externalfilterinputfile
   \immediate\write   \externalfilterwrite{\detokenize{#1}}%
   \immediate\closeout\externalfilterwrite
   \popcatcodetable
   \doexecuteexternalfilter
   \doreadprocessedfile
   \endgroup}



\setupexternalfilters
  [
   \c!before=,
   \c!after=,
   \c!setups=,
   \c!continue=\v!no,
   \c!read=\v!yes,
   \c!readcommand=\ReadFile,
   \c!output=\externalfilterbasefile.tex,
   \c!filter=,
   \c!method=\v!default,
   \c!filtercommand={\externalfilterparameter\c!filter\space \externalfilterinputfile},
   \c!separator=,
 ]
   
% For tracing
\def\showexternalfilterstate
  {\starttable[|l|l|]
  \NC currentexternalfilter     \NC \currentexternalfilter      \NC \AR
  \NC externalfilterinputfile   \NC \externalfilterinputfile    \NC \AR
  \NC externalfilteroutputfile  \NC \externalfilteroutputfile   \NC \AR
  \NC externalfilterbasefile    \NC \externalfilterbasefile     \NC \AR
  \stoptable}
   
\protect
\stopmodule
