%D \module
%D   [       file=lxml-ini,
%D        version=2007.08.17,
%D          title=\CONTEXT\ \XML\ Support,
%D       subtitle=Initialization,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D Todo: auto apply setups (manage at lua end)
%D Todo: manual: \xmlinclusion \xmlinclusions

\writestatus{loading}{ConTeXt XML Support / Initialization}

%registerctxluafile{lxml-tab}{} % loader
%registerctxluafile{lxml-lpt}{} % parser
%registerctxluafile{lxml-xml}{} % xml finalizers
%registerctxluafile{lxml-aux}{} % extras using parser
%registerctxluafile{lxml-mis}{} % extras independent of parser
\registerctxluafile{lxml-ent}{} % entity hacks
\registerctxluafile{lxml-tex}{} % tex finalizers
\registerctxluafile{lxml-dir}{} % ctx hacks
\registerctxluafile{lxml-ini}{} % interface

\unprotect

% todo: { } mandate so that we can alias

% undocumented:

\permanent\def\ctxlxml#1{\ctxlua{lxml.#1}}

% for now indirect .. this will change when we have updated luatex (scan_argument)

\permanent\def\xmlconcat          #1#2#3{\clf_xmlconcat     {#1}{#2}{\detokenize{#3}}}
\permanent\def\xmlconcatrange #1#2#3#4#5{\clf_xmlconcatrange{#1}{#2}{#3}{#4}{\detokenize{#5}}}

%D Maybe I should add \type {\protected} here:

\permanent\def\xmlloadfile  #1#2{\clf_xmlloadfile  {#1}{#2}{\directxmlparameter\c!compress}}
\permanent\def\xmlloadbuffer#1#2{\clf_xmlloadbuffer{#1}{#2}{\directxmlparameter\c!compress}}
\permanent\def\xmlloaddata  #1#2{\clf_xmlloaddata  {#1}{#2}{\directxmlparameter\c!compress}}

\aliased\let\xmlload\xmlloadfile

%D These are defined at the \LUA\ end:

% \xmlall \xmlatt \xmlattdef \xmlattribute \xmlattributedef \xmlbadinclusions
% \xmlchainatt \xmlchainattdef \xmlchecknamespace \xmlcommand \xmlcontext \xmlcount
% \xmldelete \xmldirect \xmldirectives \xmldirectivesafter \xmldirectivesbefore
% \xmldisplayverbatim \xmlelement \xmlfilter \xmlfilterlist \xmlfirst \xmlflush
% \xmlflushcontext \xmlflushlinewise \xmlflushpure \xmlflushspacewise \xmlflushtext
% \xmlfunction \xmlinclude \xmlincludeoptions \xmlinclusion \xmlinclusionbase
% \xmlinclusions \xmlindex \xmlinlineverbatim \xmllast \xmllastatt \xmllastmatch
% \xmllastpar \xmlloaddirectives \xmlmain \xmlmatch \xmlname \xmlnamespace
% \xmlnonspace \xmlpar \xmlparam \xmlpath \xmlpopmatch \xmlpos \xmlpure
% \xmlpushmatch \xmlraw \xmlrefatt \xmlregisterns \xmlremapname \xmlremapnamespace
% \xmlsave \xmlsetatt \xmlsetattribute \xmlsetpar \xmlsetparam \xmlsetsetup
% \xmlsnippet \xmlstrip \xmlstripanywhere \xmlstripnolines \xmlstripped
% \xmlstrippednolines \xmltag \xmltext \xmltobuffer \xmltobuffertextonly
% \xmltobufferverbose \xmltofile \xmltoparameters \xmlverbatim

\aliased\let\xmlposition\xmlindex

\permanent\protected\def\xmlinfo#1{\hbox{\ttxx[\xmlname{#1}]}}
\permanent\protected\def\xmlshow#1{\startpacked\ttx\xmlverbatim{#1}\stoppacked}

% the next one is handy for mode runs because it enforces a consistent
% #1 indexing (needed when using \xmltext{main:123}{...} like calls

%let\xmladdindex               \clf_xmladdindex

% we need to pass the last argument as function, so

%permanent\protected\def\xmlsetfunction#1#2#3{\ctxcommand{xmlsetfunction("#1",\!!bs#2\!!es,#3)}}
\permanent\protected\def\xmlsetfunction#1#2#3{\ctxlua{lxml.setaction("#1",\!!bs#2\!!es,#3)}}

% goodie:

\permanent\cdef\xmltempbuffername{xml-temp}

\permanent\protected\def\prettyprintbuffer#1#2% only used here
  {\ifdefined\scitebuffer % we could predefine to relax
     \scitebuffer[#2][#1]%
   \else
     \typebuffer[#1][\c!option=#2]%
   \fi}

\permanent\protected\def\xmlprettyprint#1#2%
  {\xmltobufferverbose{#1}{.}{\xmltempbuffername}%
   \prettyprintbuffer\xmltempbuffername{#2}}

\permanent\protected\def\xmlprettyprinttext#1#2%
  {\xmltobuffertextonly{#1}{.}{\xmltempbuffername}%
   \prettyprintbuffer\xmltempbuffername{#2}}

\permanent\protected\def\inlineprettyprintbuffer#1#2% only used here
  {\ifdefined\sciteinlinebuffer
     \sciteinlinebuffer[#2][#1]%
   \else
     \typeinlinebuffer[#1][\c!option=#2]%
   \fi}

\permanent\protected\def\xmlinlineprettyprint#1#2%
  {\xmltobufferverbose{#1}{.}{\xmltempbuffername}%
   \inlineprettyprintbuffer\xmltempbuffername{#2}}

\permanent\protected\def\xmlinlineprettyprinttext#1#2%
  {\xmltobuffertextonly{#1}{.}{\xmltempbuffername}%
   \inlineprettyprintbuffer\xmltempbuffername{#2}}

% kind of special:

\aliased\let\xmlstartraw\clf_xmlstartraw
\aliased\let\xmlstopraw \clf_xmlstopraw

\aliased\let\startxmlraw\clf_xmlstartraw
\aliased\let\stopxmlraw \clf_xmlstopraw

% These are expandable and defined at the \LUA\ end:

% \xmldoif \xmldoifnot \xmldoifelse \xmldoiftext \xmldoifnottext \xmldoifelsetext
% \xmldoifatt \xmldoifnotatt \xmldoifelseatt \xmldoifempty \xmldoifnotempty
% \xmldoifelseempty \xmldoifselfempty \xmldoifnotselfempty \xmldoifelseselfempty

\aliased\let\xmldoiftextelse      \xmldoifelsetext
\aliased\let\xmldoifemptyelse     \xmldoifelseempty
\aliased\let\xmldoifselfemptyelse \xmldoifelseselfempty

% \startxmlsetups xml:include
%     \xmlinclude{main}{include}{filename|href}
% \stopxmlsetups
%
% \xmlprependsetup{xml:include}

% \let\xmlgrab\xmlsetsetup % obsolete
% \let\xmlself\s!unknown   % obsolete

\aliased\let\xmlsetup\setupwithargumentswapped
\aliased\let\xmls    \setupwithargumentswapped % hardly any faster
\aliased\let\xmlw    \setupwithargument        % hardly any faster

% todo: 1:xml:whatever always before 3:xml:something

\permanent\protected\def\xmlprependsetup            #1{\clf_xmlprependsetup{*}{#1}}
\permanent\protected\def\xmlappendsetup             #1{\clf_xmlappendsetup {*}{#1}}
\permanent\protected\def\xmlbeforesetup           #1#2{\clf_xmlbeforesetup {*}{#1}{#2}}
\permanent\protected\def\xmlaftersetup            #1#2{\clf_xmlaftersetup  {*}{#1}{#2}}
\permanent\protected\def\xmlremovesetup             #1{\clf_xmlremovesetup {*}{#1}}
\permanent\protected\def\xmlresetsetups               {\clf_xmlresetsetups {*}}

\permanent\protected\def\xmlprependdocumentsetup  #1#2{\clf_xmlprependsetup{#1}{#2}}
\permanent\protected\def\xmlappenddocumentsetup   #1#2{\clf_xmlappendsetup {#1}{#2}}
\permanent\protected\def\xmlbeforedocumentsetup #1#2#3{\clf_xmlbeforesetup {#1}{#2}{#3}}
\permanent\protected\def\xmlafterdocumentsetup  #1#2#3{\clf_xmlaftersetup  {#1}{#2}{#3}}
\permanent\protected\def\xmlremovedocumentsetup   #1#2{\clf_xmlremovesetup {#1}{#2}}
\permanent\protected\def\xmlresetdocumentsetups     #1{\clf_xmlresetsetups {#1}}

\permanent\protected\def\xmlflushsetups             #1{\clf_xmlflushsetups {#1}{*}{}}   % #1 == id where to apply *
\permanent\protected\def\xmlflushdocumentsetups   #1#2{\clf_xmlflushsetups {#1}{*}{#2}} % #1 == id where to apply * and #2

\aliased\let\xmlregistersetup        \xmlappendsetup
\aliased\let\xmlregisterdocumentsetup\xmlappenddocumentsetup

\mutable\def\xmldocument{main}

\permanent\protected\def\xmlregisteredsetups
  {\xmlstarttiming
   \xmlflushsetups\xmldocument
   \xmldefaulttotext\xmldocument % after include
   \xmlstoptiming}

\permanent\protected\def\xmlregistereddocumentsetups#1#2% id setups
  {\xmlstarttiming
   % todo: test for duplicates !
   \xmlflushdocumentsetups{#1}{#2}%
   \xmldefaulttotext{#1}% after include
   \xmlstoptiming}

\permanent\protected\def\xmlstarttiming{\clf_xmlstarttiming} % undocumented
\permanent\protected\def\xmlstoptiming {\clf_xmlstoptiming}  % undocumented

\def\lxml_process#1#2#3#4#5% flag \loader id name what initializersetup
  {\begingroup
   \edef\xmldocument{#3}% #2 can be \xmldocument and set as such
   %xmlpushdocument{#3}%
   #2{#3}{#4}%
   \setcatcodetable\notcatcodes
   \xmlsetup{#3}{\ifempty{#5}xml:process\else#5\fi}%
   %xmlpopdocument
   \endgroup}

% This still doesn't solve a problem with weird grouping (start inside xml and
% end outside, so one has to do proper grouping inside xml mode).
%
% \def\lxml_process#1#2#3#4#5% flag \loader id name what initializersetup
%   {%\begingroup
%    \pushmacro\xmldocument
%    \edef\xmldocument{#3}% #2 can be \xmldocument and set as such
%    #2{#3}{#4}%
%    \pushcatcodetable
%    \setcatcodetable\notcatcodes
%    \xmlsetup{#3}{\ifempty{#5}xml:process\else#5\fi}%
%    \popcatcodetable
%    \popmacro\xmldocument
%    }%\endgroup}

\permanent\protected\def\xmlprocessfile  {\lxml_process\plusone  \xmlload}
\permanent\protected\def\xmlprocessdata  {\lxml_process\zerocount\xmlloaddata}
\permanent\protected\def\xmlprocessbuffer{\lxml_process\zerocount\xmlloadbuffer}
\aliased            \let\xmlprocess       \xmlprocessfile

\startxmlsetups xml:flush
    \xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:process
    \xmlregistereddocumentsetups{#1}{#1}
    \xmlmain{#1}
\stopxmlsetups

\permanent\protected\def\xmlloadonly#1#2#3%
  {\xmlload{#1}{#2}%
   \xmlregistereddocumentsetups{#1}{#3}}

% replaced by concat
%
% \protected\def\xmlconnect#1#2#3% inefficient
%   {\scratchcounter\xmlcount{#1}{#2}\relax
%    \ifcase\scratchcounter \or
%      \xmlall{#1}{#2}%
%    \else
%      \dorecurse \scratchcounter
%        {\ifnum\recurselevel>\plusone#3\fi
%         \xmlidx{#1}{#2}\recurselevel}%
%    \fi}

\permanent\protected\def\xmlcdataobeyedline {\obeyedline}
\permanent\protected\def\xmlcdataobeyedspace{\strut\obeyedspace}
\permanent\protected\def\xmlcdatabefore     {\begingroup\tt}
\permanent\protected\def\xmlcdataafter      {\endgroup}

% verbatim (dodo:pre/post whitespace, maybe splot verbatim and
% cdata commands), experimental:
%
% \xmlsetfunction{main}{verbatim}{lxml.displayverbatim}
% \xmlsetfunction{main}{verb}    {lxml.inlineverbatim}

% we use an xml: namespace so one has to define a suitable verbatim, say
%
% \definetyping[xml:verbatim][typing]
%
% this is experimental!

\permanent\tolerant\protected\def\startxmldisplayverbatim[#1]%
  {\startpacked
   \cdef\currenttyping{#1}%
   \ifempty\currenttyping
     \let\currenttyping\v!typing
   \else % maybe test for existence
     \cdef\currenttyping{xml:\currenttyping}%
   \fi
   \enforced\protected\def\stopxmldisplayverbatim
     {\endofverbatimlines
      \stoppacked}%
   \doinitializeverbatim
   \beginofverbatimlines}

\permanent\protected\lettonothing\stopxmldisplayverbatim

\permanent\tolerant\protected\def\startxmlinlineverbatim[#1]%
  {\begingroup
   \cdef\currenttype{#1}%
   \ifempty\currenttype
     \let\currenttype\v!type
   \else % maybe test for existence
     \cdef\currenttype{xml:\currenttype}%
   \fi
   \enforced\let\stopxmlinlineverbatim\endgroup
   \doinitializeverbatim}

\permanent\protected\lettonothing\stopxmlinlineverbatim

% processing instructions

\permanent\protected\def\xmlinstalldirective#1#2%
  {\clf_xmlinstalldirective{#1}{\csstring#2}}

% an example:

% <?context-tex-directive bgroup ?>

\appendtoks
    \xmlinstalldirective{tex}{xmltexcommand}%
\to \everyjob

\permanent\def\xmltexcommand#1{\begincsname#1\endcsname}

% \def\xmlcontextdirective#1% kind class key value
%   {\executeifdefined{xml#1directive}\gobblethreearguments}

% setting up xml:
%
% \setupxml[\c!default=]        % mkiv only == text
% \setupxml[\c!default=\v!none] % mkiv only, undefined -> hidden
% \setupxml[\c!default=\v!text] % mkiv only, undefined -> text

% \def\xmlctxdirective#1#2#3{\doif{#1}{clue}{\doif{#2}{page}}{\page[#3]}}

\newconstant\xmlprocessingmode % 0=unset, 1=text, 2=hidden

\installcorenamespace{xml}
\installcorenamespace{xmldefaults}
\installcorenamespace{xmlmapvalue}

\installdirectcommandhandler \??xml {xml}

\letcsname\??xmldefaults\v!normal\endcsname\zerocount
\letcsname\??xmldefaults\v!none  \endcsname\zerocount
\letcsname\??xmldefaults\v!text  \endcsname\plusone
\letcsname\??xmldefaults\v!hidden\endcsname\plustwo

\permanent\protected\def\xmldefaulttotext
  {\ifcase\xmlprocessingmode
     \expandafter\gobbleoneargument       % 0 (none)
   \or
     \expandafter\clf_xmlsetcommandtotext % 1 (normal)
   \or
     \expandafter\clf_xmlsetcommandtonone % 2 (hidden)
   \else
     \expandafter\gobbleoneargument       %   (none)
   \fi}

\appendtoks
    \xmlprocessingmode\executeifdefined{\??xmldefaults\directxmlparameter\c!default}\plusone
\to \everysetupxml

\setupxml
  [\c!default=,          % flush all
   \c!compress=\v!no,    % strip comment
   \c!entities=\v!no]    % load big entity file

\appendtoks
    \ifcstok{\directxmlparameter\c!entities}\v!yes
        \clf_xmlloadentities
    \fi
\to \everysetupxml

\permanent\def\xmlmapvalue    #1#2#3{\defcsname\??xmlmapvalue#1:#2\endcsname{#3}} % keep #3 to grab spaces
\permanent\def\xmldoifelsevalue #1#2{\ifcsname\??xmlmapvalue#1:#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}

\permanent\def\xmlvalue#1#2% #3
  {\ifcsname\??xmlmapvalue#1:#2\endcsname
     \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\def\xmlmappedvalue#1#2#3%
  {\ifcsname\??xmlmapvalue#1:#2\endcsname
     \expandafter\lastnamedcs
   \else
     \csname\??xmlmapvalue#1:#3\expandafter\endcsname
   \fi}

\aliased\let\xmldoifvalueelse\xmldoifelsevalue

\aliased\let\xmlmapval\xmlmapvalue
\aliased\let\xmlval   \xmlvalue

%D Experimental:

\permanent\def\xmlgetindex    #1{\clf_xmlgetindex {\xmldocument}{#1}}
\permanent\def\xmlwithindex #1#2{\clf_xmlwithindex{\xmldocument}{#1}{#2}}
\permanent\def\xmlreference #1#2{\string\xmlwithindex{#1}{#2}}

%D Entities:
%D
%D \starttyping
%D \xmlsetentity{tex}{\TEX{}} % {} needed
%D \stoptyping

\permanent\protected\def\xmlsetentity#1#2{\clf_xmlsetentity{#1}{\detokenize{#2}}}
\permanent\protected\def\xmltexentity#1#2{\clf_xmltexentity{#1}{\detokenize{#2}}}

%D The following might change (or even disappear) so we keep it undocumented.

\setnewconstant\xmlautoentities\plusone % 0=off, 1=upper, 2=upper,lower

\permanent\protected\def\xmle
  {\ifcase\xmlautoentities
     \expandafter\lxml_e_none
   \or
     \expandafter\lxml_e_upper
   \or
     \expandafter\lxml_e_upperlower
   \else
     \expandafter\lxml_e_none
   \fi}

\def\lxml_e_none#1#2% safe
  {#1}

\def\lxml_e_upper#1#2% can be abbreviation
  {\ifcsname#2\endcsname
     \csname#2\expandafter\endcsname
   \else
     #1%
   \fi}

\def\lxml_e_upperlower#1#2% can be anything, so unsafe
  {\ifcsname#2\endcsname
     \csname#2\expandafter\endcsname
   \orelse\ifcsname#1\endcsname
     \csname#1\expandafter\endcsname
   \else
     #1%
   \fi}

%D We keep these around as there are also MP, LUA and TEX variants but they are not
%D the same as in \MKII.

\permanent\tolerant\protected\def\processXMLbuffer[#1]{\xmlprocessbuffer{temp}{#1}{}}
\permanent         \protected\def\processXMLfile    #1{\xmlprocessfile  {temp}{#1}{}}
\permanent         \protected\def\XMLdata           #1{\xmlprocessdata  {temp}{#1}{}}

\aliased\let\processxmlbuffer\processXMLbuffer
\aliased\let\processxmlfile  \processXMLfile
\aliased\let\xmldata         \XMLdata

\permanent\protected\def\xmlsetinjectors  [#1]{\clf_xmlsetinjectors{#1}}
\permanent\protected\def\xmlresetinjectors    {\clf_xmlresetinjectors{}}

% \def\xmlinjector#1{\executeifdefined{#1}\donothing}

\permanent\def\xmlinjector#1{\fastsetup{xml:directive:injector:#1}}

\startsetups xml:directive:injector:page
    \page
\stopsetups

\startsetups xml:directive:injector:column
    \column
\stopsetups

\startsetups xml:directive:injector:blank
    \blank
\stopsetups

\startsetups xml:directive:injector:noline
    \vskip-\lineheight
\stopsetups

\aliased\let\xmlapplyselectors\clf_xmlapplyselectors

% In the\MKIV\ file there is some commented code wrt handing entities with active
% characters ... very old and obsolete.

\protect \endinput

