%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: manuak: \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:

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

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

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

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

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

\let\xmlload\xmlloadfile

% aliased

%let\xmlall                    \clf_xmlall
%let\xmlatt                    \clf_xmlatt
%let\xmlattdef                 \clf_xmlattdef
%let\xmlattribute              \clf_xmlattribute
%let\xmlattributedef           \clf_xmlattributedef
%let\xmlbadinclusions          \clf_xmlbadinclusions
%let\xmlchainatt               \clf_xmlchainatt
%let\xmlchainattdef            \clf_xmlchainattdef
%let\xmlchecknamespace         \clf_xmlchecknamespace
%let\xmlcommand                \clf_xmlcommand
%let\xmlcontext                \clf_xmlcontext
%let\xmlcount                  \clf_xmlcount
%let\xmldelete                 \clf_xmldelete
%let\xmldirect                 \clf_xmldirect             % in loops, not dt but root
%let\xmldirectives             \clf_xmldirectives
%let\xmldirectivesafter        \clf_xmldirectivesafter
%let\xmldirectivesbefore       \clf_xmldirectivesbefore
%let\xmldisplayverbatim        \clf_xmldisplayverbatim
%let\xmlelement                \clf_xmlelement
%let\xmlfilter                 \clf_xmlfilter
%let\xmlfilterlist             \clf_xmlfilterlist
%let\xmlfirst                  \clf_xmlfirst
%let\xmlflush                  \clf_xmlflush
%let\xmlflushcontext           \clf_xmlflushcontext
%let\xmlflushlinewise          \clf_xmlflushlinewise
%let\xmlflushpure              \clf_xmlflushpure
%let\xmlflushspacewise         \clf_xmlflushspacewise
%let\xmlflushtext              \clf_xmlflushtext
%let\xmlfunction               \clf_xmlfunction
%let\xmlinclude                \clf_xmlinclude
%let\xmlincludeoptions         \clf_xmlincludeoptions
%let\xmlinclusion              \clf_xmlinclusion
%let\xmlinclusionbase          \clf_xmlinclusionbase
%let\xmlinclusions             \clf_xmlinclusions
%let\xmlindex                  \clf_xmlindex
%let\xmlinlineverbatim         \clf_xmlinlineverbatim
%let\xmllast                   \clf_xmllast
%let\xmllastatt                \clf_xmllastatt
%let\xmllastmatch              \clf_xmllastmatch
%let\xmllastpar                \clf_xmllastpar
%let\xmlloaddirectives         \clf_xmlloaddirectives
%let\xmlmain                   \clf_xmlmain
%let\xmlmatch                  \clf_xmlmatch
%let\xmlname                   \clf_xmlname
%let\xmlnamespace              \clf_xmlnamespace
%let\xmlnonspace               \clf_xmlnonspace
%let\xmlpar                    \clf_xmlpar
%let\xmlparam                  \clf_xmlparam
%let\xmlpath                   \clf_xmlpath
%let\xmlpopmatch               \clf_xmlpopmatch
%let\xmlpos                    \clf_xmlpos
%let\xmlpure                   \clf_xmlpure
%let\xmlpushmatch              \clf_xmlpushmatch
%let\xmlraw                    \clf_xmlraw
%let\xmlrefatt                 \clf_xmlrefatt
%let\xmlregisterns             \clf_xmlregisterns         % document
%let\xmlremapname              \clf_xmlremapname          % element
%let\xmlremapnamespace         \clf_xmlremapnamespace     % document
%let\xmlsave                   \clf_xmlsave
%let\xmlsetatt                 \clf_xmlsetatt
%let\xmlsetattribute           \clf_xmlsetattribute
%let\xmlsetpar                 \clf_xmlsetpar
%let\xmlsetparam               \clf_xmlsetparam
%let\xmlsetsetup               \clf_xmlsetsetup
%let\xmlsnippet                \clf_xmlsnippet
%let\xmlstrip                  \clf_xmlstrip
%let\xmlstripanywhere          \clf_xmlstripanywhere
%let\xmlstripnolines           \clf_xmlstripnolines
%let\xmlstripped               \clf_xmlstripped
%let\xmlstrippednolines        \clf_xmlstrippednolines
%let\xmltag                    \clf_xmltag
%let\xmltext                   \clf_xmltext
%let\xmltobuffer               \clf_xmltobuffer           % id pattern name
%let\xmltobuffertextonly       \clf_xmltobuffertextonly   % id pattern name
%let\xmltobufferverbose        \clf_xmltobufferverbose    % id pattern name
%let\xmltofile                 \clf_xmltofile             % id pattern filename
%let\xmltoparameters           \clf_xmltoparameters
%let\xmlverbatim               \clf_xmlverbatim

\let\xmlposition               \xmlindex

\unexpanded\def\xmlinfo#1{\hbox{\ttxx[\xmlname{#1}]}}
\unexpanded\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

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

% goodie:

\def\xmltempbuffername{xml-temp}

\unexpanded\def\prettyprintbuffer#1#2% only used here
  {\ifdefined\scitebuffer
     \scitebuffer[#2][#1]%
   \else
     \typebuffer[#1][\c!option=#2]%
   \fi}

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

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

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

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

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

% kind of special:

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

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

% these are expandable! todo: \xmldoifelseattribute

%let\xmldoif              \clf_xmldoif
%let\xmldoifnot           \clf_xmldoifnot
%let\xmldoifelse          \clf_xmldoifelse
%let\xmldoiftext          \clf_xmldoiftext
%let\xmldoifnottext       \clf_xmldoifnottext
%let\xmldoifelsetext      \clf_xmldoifelsetext

%let\xmldoifatt           \clf_xmldoifatt
%let\xmldoifnotatt        \clf_xmldoifnotatt
%let\xmldoifelseatt       \clf_xmldoifelseatt

%let\xmldoifempty         \clf_xmldoifempty
%let\xmldoifnotempty      \clf_xmldoifnotempty
%let\xmldoifelseempty     \clf_xmldoifelseempty
%let\xmldoifselfempty     \clf_xmldoifselfempty
%let\xmldoifnotselfempty  \clf_xmldoifnotselfempty
%let\xmldoifelseselfempty \clf_xmldoifelseselfempty

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

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

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

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

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

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

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

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

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

\def\xmldocument{main}

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

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

\unexpanded\def\xmlstarttiming{\clf_xmlstarttiming} % undocumented
\unexpanded\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
   \doifelsenothing{#5}%
     {\xmlsetup{#3}{xml:process}}%
     {\xmlsetup{#3}{#5}}%
   %xmlpopdocument
   \endgroup}

\unexpanded\def\xmlprocessfile      {\lxml_process\plusone  \xmlload}
\unexpanded\def\xmlprocessdata      {\lxml_process\zerocount\xmlloaddata}
\unexpanded\def\xmlprocessbuffer    {\lxml_process\zerocount\xmlloadbuffer}
           \let\xmlprocess           \xmlprocessfile

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

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

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

% replaced by concat
%
% \unexpanded\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}

\unexpanded\def\xmlcdataobeyedline {\obeyedline}
\unexpanded\def\xmlcdataobeyedspace{\strut\obeyedspace}
\unexpanded\def\xmlcdatabefore     {\begingroup\tt}
\unexpanded\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!

\unexpanded\def\startxmldisplayverbatim
  {\dosingleempty\lxml_start_display_verbatim}

\let\stopxmldisplayverbatim\relax

\def\lxml_start_display_verbatim[#1]%
  {\startpacked
   \edef\currenttyping{#1}%
   \ifx\currenttyping\empty
     \let\currenttyping\v!typing
   \else % maybe test for existence
     \edef\currenttyping{xml:\currenttyping}%
   \fi
   \unexpanded\def\stopxmldisplayverbatim
     {\endofverbatimlines
      \stoppacked}%
   \doinitializeverbatim
   \beginofverbatimlines}

\unexpanded\def\startxmlinlineverbatim
  {\dosingleempty\lxml_start_inline_verbatim}

\let\stopxmlinlineverbatim\relax

\unexpanded\def\lxml_start_inline_verbatim[#1]%
  {\begingroup
   \edef\currenttype{#1}%
   \ifx\currenttype\empty
     \let\currenttype\v!type
   \else % maybe test for existence
     \edef\currenttype{xml:\currenttype}%
   \fi
   \let\stopxmlinlineverbatim\endgroup
   \doinitializeverbatim}

% processing instructions

\unexpanded\def\xmlinstalldirective#1#2%
  {\clf_xmlinstalldirective{#1}{\csstring#2}}

% an example:

% <?context-tex-directive bgroup ?>

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

\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}

\letvalue{\??xmldefaults\v!normal}\zerocount
\letvalue{\??xmldefaults\v!none  }\zerocount
\letvalue{\??xmldefaults\v!text  }\plusone
\letvalue{\??xmldefaults\v!hidden}\plustwo

\unexpanded\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
    \doif{\directxmlparameter\c!entities}\v!yes\clf_xmlloadentities
\to \everysetupxml

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

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

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

\let\xmldoifvalueelse\xmldoifelsevalue

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

%D Experimental:

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

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

\unexpanded\def\xmlsetentity#1#2{\clf_xmlsetentity{#1}{\detokenize{#2}}}
\unexpanded\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

\unexpanded\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
   \else\ifcsname#1\endcsname
     \csname#1\expandafter\expandafter\expandafter\endcsname
   \else
     #1%
   \fi\fi}

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

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

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

\unexpanded\def\processXMLbuffer
  {\dosingleempty\lxml_process_buffer}

\def\lxml_process_buffer[#1]%
  {\xmlprocessbuffer{temp}{#1}{}}

\unexpanded\def\processXMLfile#1%
  {\xmlprocessfile{temp}{#1}{}}

\unexpanded\def\XMLdata#1%
  {\xmlprocessdata{temp}{#1}{}}

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

\unexpanded\def\xmlsetinjectors[#1]%
  {\clf_xmlsetinjectors{#1}}

\unexpanded\def\xmlresetinjectors
  {\clf_xmlresetinjectors{}}

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

\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

\let\xmlapplyselectors\clf_xmlapplyselectors

% \let\xmlcatcodes\notcatcodes

\protect \endinput

% \newcount\charactersactiveoffset \charactersactiveoffset="10000
%
% \startextendcatcodetable\ctxcatcodes
%     \catcode\numexpr\charactersactiveoffset+`<\relax=13
%     \catcode\numexpr\charactersactiveoffset+`&\relax=13
%     \catcode\numexpr\charactersactiveoffset+`>\relax=13
% \stopextendcatcodetable
%
% \startextendcatcodetable\xmlcatcodes % not needed
%     \catcode\numexpr\charactersactiveoffset+`<\relax=13
%     \catcode\numexpr\charactersactiveoffset+`&\relax=13
%     \catcode\numexpr\charactersactiveoffset+`>\relax=13
% \stopextendcatcodetable
%
% \ctxlua { % entities are remembered in the format
%     commands.remapentity("<",characters.activeoffset + utf.byte("<"))
%     commands.remapentity("&",characters.activeoffset + utf.byte("&"))
%     commands.remapentity(">",characters.activeoffset + utf.byte(">"))
% }
