% \iffalse meta-comment
% A LaTeX Class and Package for OMDoc Document Structures
% Copyright (c) 2006 Michael Kohlhase, all rights reserved
%               this file is released under the
%               LaTeX Project Public License (LPPL)
%
% The development version of this file can be found at
% https://svn.kwarc.info/repos/kwarc/projects/stex/sty/omdoc.dtx
% \fi
%   
% \iffalse
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{omdoc}[2007/09/09 v0.3 OMDoc document Structure]
%<cls>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<cls>\ProvidesClass{omdoc}[2007/09/09 v0.3 OMDoc Documents]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{url,array,omdoc,float}
\usepackage[show]{ed}
\usepackage{hyperref}
\makeindex
\floatstyle{boxed}
\newfloat{exfig}{thp}{lop}
\floatname{exfig}{Example}
\begin{document}\DocInput{omdoc.dtx}\end{document}
%</driver>
% \fi
% 
%\CheckSum{341}
% 
% \changes{v0.1}{2006/1/17}{First Version}
% \changes{v0.2}{2006/7/11}{added OMDoc class}
% \changes{v0.3}{2007/09/09}{moved omtext and friends here from the statements package}
% 
% \GetFileInfo{omdoc.sty}
% 
% \MakeShortVerb{\|}
%
% \def\twin#1#2{\index{#1!#2}\index{#2!#1}}
% \def\twintoo#1#2{{#1 #2}\twin{#1}{#2}}
% \def\atwin#1#2#3{\index{#1!#2!#3}\index{#3!#2 (#1)}}
% \def\atwintoo#1#2#3{{#1 #2 #3}\atwin{#1}{#2}{#3}}
% \def\sTeX{{\raisebox{-.5ex}S\kern-.5ex\TeX}}
% \def\omdoc{OMDoc}
% \def\latexml{{\LaTeX}ML}
% \title{Semantic Markup for Open Mathematical Documents in {\LaTeX}\thanks{Version {\fileversion} (last revised
%        {\filedate})}}
%    \author{Michael Kohlhase\\
%            Jacobs University, Bremen\\
%            \url{http://kwarc.info/kohlhase}}
% \maketitle
%
% \begin{abstract}
%   The |omdoc| packge is part of the {\sTeX} collection, a version of {\TeX/\LaTeX} that
%   allows to markup {\TeX/\LaTeX} documents semantically without leaving the document
%   format, essentially turning {\TeX/\LaTeX} into a document format for mathematical
%   knowledge management (MKM).
%
%   This package supplies a the infrastructure for writing {\omdoc} documents in {\LaTeX}.
%   This includes a simple structure sharing mechanism for {\sTeX} that allows to to move
%   from a copy-and-paste document development model to a copy-and-reference model, which
%   conserves space and simplifies document management. The augmented structure can be
%   used by MKM systems for added-value services, either directly from the {\sTeX}
%   sources, or after translation.
% \end{abstract}
%\newpage
% 
%\section{Introduction}\label{sec:STR}
%
% The |omdoc| package supplies macros and environment that allow to label document
% fragements and to reference them later in the same document or in other documents. In
% essence, this enhances the docuent-as-trees model to
% documents-as-directed-acyclic-graphs (DAG) model. This structure can be used by MKM
% systems for added-value services, either directly from the {\sTeX} sources, or after
% translation. Currently, trans-document referencing provided by this package can conly be
% used in the {\sTeX} collection.
%
% {\sTeX} is a version of {\TeX/\LaTeX} that allows to markup {\TeX/\LaTeX} documents
% semantically without leaving the document format, essentially turning {\TeX/\LaTeX} into
% a document format for mathematical knowledge management (MKM).
%
% DAG models of documents allow to replace the ``Copy and Paste'' in the source document
% with a label-and-reference model where document are shared in the document source and
% the formatter does the copying during document formatting/presentation.\ednote{talk
%   about the advantages and give an example.}\ednote{is there a way to load documents at
%   URIs in LaTeX?}\ednote{integrate with latexml's XMRef in the Math mode.}
%
% \section{The User Interface}\label{sec:user}
%
% \subsection{Document Structure}\label{sec:user:struct}
% 
% \DescribeEnv{omgroup} The structure of the document is given by the |omgroup|
% environment just like in {\omdoc}.
%
% \subsection{Providing IDs for {\omdoc} Elements}\label{sec:user:ids}
%
% Some of the {\omdoc} elements need IDs to function corrrectly. The general strategy here
% is to equip the {\sTeX} macros with keys, so that the author can specify meaningful
% ones, but to let the transformation give default ones if the author did not. 
% 
% \subsection{Mathematical Text}\label{sec:user:omtext}
% 
% \DescribeEnv{omtext} The |omtext| environment is used for any text fragment that has a
% contribution to a text that needs to be marked up. It can have a title, which can be
% specified via the |title| key. Often it is also helpful to annotate the |type| key. The
% standard relations from rhethorical structure theory |abstract|, |introduction|,
% |conclusion|, |thesis|, |comment|, |antithesis|, |elaboration|, |motivation|,
% |evidence|, |transition|, | note|, |annote| are recommended. Note that some of them are
% unary relations like |introduction|, which calls for a target. In this case, a target
% using the |for| key should be specified. The |transition| relation is special in that it
% is binary (a ``transition between two statements''), so additionally, a source should be
% specified using the |from| key.\ednote{describe the keys more fully}
%
% \subsection{Structure Sharing}\label{sec:user:sharing}
%
% \DescribeMacro{\STRlabel}\DescribeMacro{\STRcopy} The |\STRlabel| macro takes two
% arguments: a label and the content and stores the the content for later use by
% |\STRcopy{label}|, which expands to the previously stored content.
%
% \DescribeMacro{\STRsemantics} The |\STRlabel| macro has a variant |\STRsemantics|, where
% the label argument is optional, and which takes a third argument, which is ignored in
% {\LaTeX}. This allows to specify the meaning of the content (whatever that may mean) in
% cases, where the source document is not formatted for presentation, but is transformed
% into some content markup format. \ednote{make an example}
% 
% \subsection{Phrase-Level Markup}\label{sec:user:phrase}
%
% \DescribeEnv{phrase} The |phrase| enviornment allows to mark up phrases with semantic
% information. It takes an optional |KeyVal| argument with the keys 
% \StopEventually{\ednotemessage}
%
% \section{Implementation: The OMDoc Class}\label{sec:impl:cls}
%
% We load |article.cls|, and the desired packages. For the {\latexml} bindings, we make
% sure the right packages are loaded.
%    \begin{macrocode}
%<*cls>
\LoadClass{article}
\RequirePackage{omdoc}
%</cls>
%<*ltxml.cls>
# -*- CPERL -*-
package LaTeXML::Package::Pool;
use strict;
use LaTeXML::Package;
LoadClass('article');
%</ltxml.cls>
%    \end{macrocode}
% Now, we also need to register the namespace prefixes for {\latexml} to use. 
%    \begin{macrocode}
%<*ltxml.cls>
RegisterNamespace('omdoc'=>"http://www.mathweb.org/omdoc"); # OMDoc namespace
RegisterNamespace(om=>"http://www.openmath.org/OpenMath");
RegisterNamespace('m'=>"http://www.w3.org/1998/Math/MathML");
RegisterNamespace('dc'=>"http://purl.org/dc/elements/1.1/");
RegisterNamespace('cc'=>"http://creativecommons.org/ns");
%</ltxml.cls>
%    \end{macrocode}
% Since we are dealing with a class, we need to set up the document type in the {\latexml}
% bindings. 
%    \begin{macrocode}
%<*ltxml.cls>
RelaxNGSchema('/Users/kohlhase/stex/rnc/omdoc+ltxml',
        '#default'=>"http://www.mathweb.org/omdoc",
        'om'=>"http://www.openmath.org/OpenMath",
        'm'=>"http://www.w3.org/1998/Math/MathML",
        'dc'=>"http://purl.org/dc/elements/1.1/",
        'cc'=>"http://creativecommons.org/ns",
        'ltx'=>"http://dlmf.nist.gov/LaTeXML");
%</ltxml.cls>
%    \end{macrocode}
% Then we load the |omdoc| package, which we define separately in the next section so that
% it can be loaded separately\ednote{reword}
%    \begin{macrocode}
%<*ltxml.cls>
RequirePackage('omdoc');
%</ltxml.cls>
%    \end{macrocode}
% Now, we will define the environments we need. The top-level one is the |document|
% environment, which we need to provide with an identifier.\ednote{probably move to the
%   omdoc package}
%    \begin{macrocode}
%<*ltxml.cls>
DefEnvironment('{document}','<omdoc:omdoc>#body</omdoc:omdoc>',
	       beforeDigest=> sub { AssignValue(inPreamble=>0); },
	       afterDigest=> sub { $_[0]->getGullet->flush; return; });
%</ltxml.cls>\iffalse$\fi
%    \end{macrocode}
%
% \section{Implementation: OMDoc Package}\label{sec:impl:sty}
% We first need to set up the packages by requiring the |KeyVal| package to be loaded (in
% the ritht version).
%
%    \begin{macrocode}
%<package>\RequirePackage{keyval}[1997/11/10]
%<*ltxml.sty>
package LaTeXML::Package::Pool;
use strict;
use LaTeXML::Package;
RequirePackage('keyval');
%</ltxml.sty>
%    \end{macrocode}
% 
% \subsection{Document Structure}\label{sec:impl:struct}
% 
% The structure of the document is given by the |omgroup| environment just like in
% OMDoc. The hierarchy is adjusted automatically\ednote{maybe define the toplevel
%   according to a param, need to know how to detect that the chapter macro exists.}
%
%    \begin{macrocode}
%<*package>
\define@key{omgroup}{id}{\label{#1}}
\define@key{omgroup}{type}{\def\omgroup@type{#1}}
\define@key{omgroup}{display}{\def\omgroup@display{#1}}
\def\omgroup@flow{flow}
\newcount\section@level\section@level=1
\newenvironment{omgroup}[2][]% title
{\setkeys{omgroup}{#1}
\ifx\omgroup@display\omgroup@flow{#2}\else
\ifnum\section@level=1\section{#2}\fi
\ifnum\section@level=2\subsection{#2}\fi
\ifnum\section@level=3\subsubsection{#2}\fi
\ifnum\section@level=4\paragraph{#2}\fi
\advance\section@level by 1\fi}{}
\def\tgroup{\omgroup}\def\endtgroup{\endomgroup}
%</package>
%<*ltxml.sty>
DefKeyVal('omgroup','id','Semiverbatim');
DefKeyVal('omgroup','type','Semiverbatim');
DefKeyVal('omgroup','display','Semiverbatim');
DefEnvironment('{omgroup} OptionalKeyVals:omgroup {}',
               "<omdoc:omgroup ?&KeyVal(#1,'id')(xml:id='#1')() ?&KeyVal(#1,'type')(type='#1')()>\n"
  	       . "?#1(<omdoc:metadata><dc:title>#1</dc:title></omdoc:metadata>\n)()"
	       . "#body\n"
	     . "</omdoc:omgroup>");

DefEnvironment('{tgroup} OptionalKeyVals:omgroup {}',
               "<omdoc:tgroup ?&KeyVal(#1,'id')(xml:id='#1')() ?&KeyVal(#1,'type')(type='#1')()>\n"
  	       . "?#1(<omdoc:metadata><dc:title>#1</dc:title></omdoc:metadata>\n)()"
	       . "#body\n"
	     . "</omdoc:tgroup>");
%</ltxml.sty>
%    \end{macrocode}
% 
%
% the |itemize|, |description|, and |enumerate| environments do double duty in OMDoc, 
% \begin{enumerate}
% \item outside a |CMP| they are transformed into a 
%   |<omgroup type='itemize|description|enumerate'>|, where the text after the macros
%   |\item| come to be the children. If that is only text, then it is enclosed in an
%   |<omtext><CMP>|, otherwise it is left as it is. The optional argument of the |\item|
%   is transformed into the |<metadata><dc:title>| of the generated |\item| element.
%  \item inside a |CMP|, they are transformed into |<ul>|, |<dl>|, and |<ol>| elements
%    like in html.
% \item Outside a |CMP|, |\item| is turned into |\ignoe@item|
% \end{enumerate}
%    \begin{macrocode}
%<*ltxml.sty>
DefParameterType('IfBeginFollows', sub {
		   my ($gullet) = @_;
		   $gullet->skipSpaces;
		   return 1 unless $gullet->ifNext(T_CS('\begin'));
		   return; },
		 reversion=>'', optional=>1);

Let('\group@item@maybe@unwrap','\relax');

DefMacro('\group@item[] IfBeginFollows', sub {
  my($gullet,$tag,$needwrapper)=@_;
  ( T_CS('\group@item@maybe@unwrap'),
    ($needwrapper ? (Invocation(T_CS('\group@item@wrap'),$tag)->unlist) : ()) ); });

DefConstructor('\group@item@wrap {}',
	       "<omdoc:omtext>"
	       . "?#1(<omdoc:metadata><dc:title>#1</dc:title></omdoc:metadata>)()"
               . "<omdoc:CMP><omdoc:p>",
	       beforeDigest=>sub {
		 Let('\group@item@maybe@unwrap','\group@item@unwrap'); 
		 $_[0]->bgroup;
		 useCMPItemizations();
		 return; },
	       properties=>sub{ RefStepItemCounter(); });
DefConstructor('\group@item@unwrap',
	       "</omdoc:p></omdoc:CMP></omdoc:omtext>",
	       beforeDigest=>sub { 
		 $_[0]->egroup;
		 Let('\group@item@maybe@unwrap','\relax'); });

Let('group@item@maybe@unwrap','\relax');

Let('\itemize@item'=>'\group@item');
Let('\enumerate@item'=>'\group@item');
Let('\description@item'=>'\group@item');

DefEnvironment('{itemize}',
	       "<omdoc:omgroup xml:id='#id' type='itemize'>#body</omdoc:omgroup>",
	       properties=>sub { beginItemize('itemize'); },
	       beforeDigestEnd=>sub { Digest(T_CS('\group@item@maybe@unwrap')); });
DefEnvironment('{enumerate}',
	       "<omdoc:omgroup xml:id='#id' type='enumerate'>#body</omdoc:omgroup>",
	       properties=>sub { beginItemize('enumerate'); },
	       beforeDigestEnd=>sub { Digest(T_CS('\group@item@maybe@unwrap')); });
DefEnvironment('{description}',
	       "<omdoc:omgroup xml:id='#id' type='description'>#body</omdoc:omgroup>",
	       properties=>sub { beginItemize('description'); },
	       beforeDigestEnd=>sub { Digest(T_CS('\group@item@maybe@unwrap')); });
%</ltxml.sty>
%    \end{macrocode}
%
% Inside a |theory| element , use |tgroup| instead of |omgroup|, otherwise, same as default case
% 
%    \begin{macrocode}
%<*ltxml.sty>
Let('\tgroup@itemize@item'=>'\group@item');
Let('\tgroup@enumerate@item'=>'\group@item');
Let('\tgroup@description@item'=>'\group@item');

DefEnvironment('{tgroup@itemize}',
	       "<omdoc:tgroup xml:id='#id' type='itemize'>#body</omdoc:tgroup>",
	       properties=>sub { beginItemize('tgroup@itemize'); },
	       beforeDigest=>sub { Let(T_CS('\end{itemize}') =>T_CS('\end{tgroup@itemize}')); },
	       beforeDigestEnd=>sub { Digest(T_CS('\group@item@maybe@unwrap')); });
DefEnvironment('{tgroup@enumerate}',
	       "<omdoc:tgroup xml:id='#id' type='enumerate'>#body</omdoc:tgroup>",
	       properties=>sub { beginItemize('tgroup@enumerate'); },
	       beforeDigest=>sub{ Let(T_CS('\end{enumerate}') =>T_CS('\end{tgroup@enumerate}'));},
	       beforeDigestEnd=>sub { Digest(T_CS('\group@item@maybe@unwrap')); });
DefEnvironment('{tgroup@description}',
	       "<omdoc:tgroup xml:id='#id' type='description'>#body</omdoc:tgroup>",
	       properties=>sub { beginItemize('tgroup@description'); },
	       beforeDigest=>sub{ Let(T_CS('\end{description}') =>T_CS('\end{tgroup@description}'));},
	       beforeDigestEnd=>sub { Digest(T_CS('\group@item@maybe@unwrap')); });

sub useTheoryItemizations {
    Let(T_CS('\begin{itemize}')    =>T_CS('\begin{tgroup@itemize}'));
    Let(T_CS('\begin{enumerate}')  =>T_CS('\begin{tgroup@enumerate}'));
    Let(T_CS('\begin{description}')=>T_CS('\begin{tgroup@description}'));
    return; }
%</ltxml.sty>
%    \end{macrocode}
%
% Inside a |CMP|, we generate |omdoc:li|, |omdoc:di| with |autoclose|
% 
%    \begin{macrocode}
%<*ltxml.sty>
DefConstructor('\CMP@itemize@item[]',
       '<omdoc:li>'
       . '?#1(<omdoc:metadata><dc:title>#1</dc:title></omdoc:metadata>)()',
       properties=>sub{ RefStepItemCounter(); });

DefConstructor('\CMP@enumerate@item[]',
       '<omdoc:li>'
       . '?#1(<omdoc:metadata><dc:title>#1</dc:title></omdoc:metadata>)()',
       properties=>sub{ RefStepItemCounter(); });

DefConstructor('\CMP@description@item[]',
       '<omdoc:di>'
       . '?#1(<omdoc:dt>#1</omdoc:dt>)()<omdoc:dd>', # trust di and dt to autoclose
       properties=>sub{ RefStepItemCounter(); });

DefEnvironment('{CMP@itemize}',
	       "<omdoc:ul xml:id='#id'>#body</omdoc:ul>",
	       properties=>sub { beginItemize('CMP@itemize'); },
	       beforeDigest=>sub { Let(T_CS('\end{itemize}') =>T_CS('\end{CMP@itemize}')); });
DefEnvironment('{CMP@enumerate}',
	       "<omdoc:ol  xml:id='#id'>#body</omdoc:ol>",
	       properties=>sub { beginItemize('CMP@enumerate'); },
	       beforeDigest=>sub { Let(T_CS('\end{enumerate}') =>T_CS('\end{CMP@enumerate}')); });
DefEnvironment('{CMP@description}',
	       "<omdoc:dl  xml:id='#id'>#body</omdoc:dl>",
	       properties=>sub { beginItemize('CMP@description'); },
	       beforeDigest=>sub { Let(T_CS('\end{description}') =>T_CS('\end{CMP@description}'));});

sub useCMPItemizations {
    Let(T_CS('\begin{itemize}')    =>T_CS('\begin{CMP@itemize}'));
    Let(T_CS('\begin{enumerate}')  =>T_CS('\begin{CMP@enumerate}'));
    Let(T_CS('\begin{description}')=>T_CS('\begin{CMP@description}'));
    return; }

Tag('omdoc:CMP', afterOpen => sub {
      AssignValue('_LastSeenCMP', $_[1], 'global');
      return; });

Tag('omdoc:li', autoClose=>1);
Tag('omdoc:dd', autoClose=>1);
Tag('omdoc:di', autoClose=>1);
%</ltxml.sty>
%    \end{macrocode}
%
% \subsection{Mathematical Text}\label{sec:impl:mtxt}
%
% We define the actions that are undertaken, when the keys are encountered. Here
% this is very simple, we just define an internal macro with the value, so that we can use
% it later.
%
%    \begin{macrocode}
%<*package>
\define@key{stat}{id}{\def\st@id{#1}}
\define@key{stat}{display}{\def\st@display{#1}}
\define@key{stat}{for}{\def\stat@for{#1}}
\define@key{stat}{from}{\def\stat@from{#1}}
\define@key{stat}{type}{\def\stat@type{#1}}
\define@key{stat}{title}{\def\stat@title{#1}}
\define@key{stat}{continues}{\def\stat@continues{#1}}
%</package>
%<*ltxml.sty>
DefKeyVal('stat','id','Semiverbatim');
DefKeyVal('stat','for','Semiverbatim');
DefKeyVal('stat','title','Semiverbatim');
DefKeyVal('stat','from','Semiverbatim');
DefKeyVal('stat','type','Semiverbatim');
DefKeyVal('stat','display','Semiverbatim'); # not used at the moment
%</ltxml.sty>
%    \end{macrocode}
%
% \begin{macro}{\show@st@keys@aux}
%    We now define a macro that shows the |st| keys, if in draft mode, they annotate the
%    document with key/value pairs.
%    \begin{macrocode}
%<*package>
\def\show@st@keys@aux{%
\@ifundefined{st@id}{}{\ifst@id{id=\st@id},\fi}%
\@ifundefined{st@display}{}{\ifst@display{display=\st@display}\fi}}
\def\clear@st@keys{\let\st@id=\relax\let\st@display=\relax}
%</package>
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\show@stat@keys@aux}
%   we do the same for the |stat| keys.
%    \begin{macrocode}
%<*package>
\def\show@stat@keys@aux{%
\@ifundefined{st@for}{}{\ifstat@for{for=\stat@for},\fi}%
\@ifundefined{st@from}{}{\ifstat@from{from=\stat@from},\fi}%
\@ifundefined{st@type}{}{\ifstat@type{type=\stat@type},\fi}%
\@ifundefined{st@title}{}{\ifstat@title{title=\stat@title},\fi}%
\@ifundefined{st@continues}{}{\ifstat@continues{continues=\stat@continues}\fi}}
%</package>
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\show@stat@keys}
% and combine them, so that the code is more readable.
%    \begin{macrocode}
%<*package>
\def\show@stat@keys#1{\footnote{#1[\show@st@keys@aux\show@stat@keys@aux]}%
\clear@st@keys\clear@stat@keys}
\def\clear@stat@keys{\let\stat@for=\relax\let\stat@from=\relax%
\let\stat@type=\relax\let\stat@title=\relax\let\stat@continues=\relax}
%</package>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\st@flow}
% We define this macro, so that we can test whether the |display| key has the value |flow|
%    \begin{macrocode}
%<package>\def\st@flow{flow}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{omtext}
%    The |omtext| environment is different, it does not have a keyword that marks
%    it. Instead, it can have a title, which is used in a similar way.
%    \begin{macrocode}
%<*package>
\def\omtext@pre@skip{\smallskip}
\def\omtext@post@skip{}
\newenvironment{omtext}[1][]{\setkeys{stat}{#1}{% keyval args
\def\lec#1{\@lec{#1}}% so the trailing \par does not get into the way
\omtext@pre@skip\par\noindent
\@ifundefined{stat@title}{}{\ifx\st@display\st@flow\else\stDMemph{\stat@title}:\fi}}
\ifst@env\show@stat@keys{omtext:\stat@title}\fi
\omtext@post@skip}{}
%</package>
%<*ltxml.sty>
DefCMPEnvironment('{omtext} OptionalKeyVals:stat',
		  "<omdoc:omtext "
		     . "?&KeyVal(#1,'id')(xml:id='&KeyVal(#1,'id')')() "
		     . "?&KeyVal(#1,'type')(type='&KeyVal(#1,'type')')() "
		     . "?&KeyVal(#1,'for')(for='&KeyVal(#1,'for')')() "
	             . "?&KeyVal(#1,'from')(from='&KeyVal(#1,'from')')()>"
		  . "?&KeyVal(#1,'title')(<omdoc:metadata><dc:title>&KeyVal(#1,'title')</dc:title></omdoc:metadata>)()"
		  . "<omdoc:CMP><omdoc:p>#body</omdoc:p></omdoc:CMP>"
		  . "</omdoc:omtext>\n");
%</ltxml.sty>
%    \end{macrocode}
% \end{environment}
%
% We also make our life easier If defininig an environment that is
% turned into something that contains |<CMP>|\meta{body}|</CMP>|, use this method instead
%    \begin{macrocode}
%<*ltxml.sty>
sub DefCMPEnvironment {
  my ($proto, $replacement, %options) = @_;
  my @before = $options{beforeDigest} ? ($options{beforeDigest}) : ();
  push(@before, \&useCMPItemizations);
  $options{beforeDigest} = \@before;
  DefEnvironment($proto, $replacement, %options);
}
%</ltxml.sty>
%    \end{macrocode}
%
%
% \subsection{Structure Sharing}\label{sec:impl:share}
%
% \begin{macro}{\STRlabel}
%    The main macro, it it used to attach a label to some text expansion. Later on, using the
%    |\STRcopy| macro, the author can use this label to get the expansion originally assigned.
%    \begin{macrocode}
%<*package>
\long\def\STRlabel#1#2{\STRlabeldef{#1}{#2}{#2}}
%</package>
%<*ltxml.sty>
DefConstructor('\STRlabel{}{}', sub {
  my($document,$label,$object)=@_;
  $document->absorb($object);
  $document->addAttribute('xml:id'=>ToString($label)) if $label; });
%</ltxml.sty>
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\STRcopy}
%    The |\STRcopy| macro is used to call the expansion of a given label. In case the label is
%    not defined it will issue a warning.
%    \begin{macrocode}
%<*package>
\def\STRcopy#1{\expandafter\ifx\csname STR@#1\endcsname\relax
\message{STR warning: reference #1 undefined!}
\else\csname STR@#1\endcsname\fi}
%</package>
%<*ltxml.sty>
DefConstructor('\STRcopy{}',"<omdoc:ref xref='#1'/>");
%</ltxml.sty>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@semantics}
%    if we have a presentation form and a semantic form, then we can use
%    \begin{macrocode}
%<*package>
\long\def\@semantics[#1]#2#3{#2\STRlabeldef{#1}{#2}}
%</package>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\STRlabeldef}
%    This is the macro that does the actual labelling. Is it called inside |\STRlabel|
%    \begin{macrocode}
%<*package>
\def\STRlabeldef#1{\expandafter\gdef\csname STR@#1\endcsname}
%</package>
%<*ltxml.sty>
DefMacro('\STRlabeldef{}{}', "");
%</ltxml.sty>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\STRsemantics}
%    \ednote{some explanation here}
%    \begin{macrocode}
%<*package>
\def\STRsemantics{\@ifnextchar[\@semantics{\@semantics[]}}
%</package>
%<*ltxml.sty>
DefConstructor('\STRsemantics[]{}{}', sub {
  my($document,$label,$ignore,$object)=@_;
  $document->absorb($object);
  $document->addAttribute('xml:id'=>ToString($label)) if $label; });
%</ltxml.sty>
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Phrase-level Markup}
% 
% \begin{environment}{phrase}
%    For the moment, we do disregard the most of the keys
%    \begin{macrocode}
%<*package>
\define@key{phrase}{id}{}
\define@key{phrase}{style}{}
\define@key{phrase}{class}{}
\define@key{phrase}{index}{}
\define@key{phrase}{verbalizes}{}
\define@key{phrase}{type}{}
\newenvironment{phrase}[1][]{\setkeys{phrase}{#1}}{}
%</package>
%<*ltxml.sty>
DefKeyVal('phrase','id','Semiverbatim');
DefKeyVal('phrase','style','Semiverbatim');
DefKeyVal('phrase','class','Semiverbatim');
DefKeyVal('phrase','index','Semiverbatim');
DefKeyVal('phrase','verbalizes','Semiverbatim');
DefKeyVal('phrase','type','Semiverbatim');
DefConstructor('\phrase OptionalKeyVals:phrase {}',
	       "<omdoc:phrase %&KeyVals(#1)>#body</omdoc:phrase>");
%</ltxml.sty>
%    \end{macrocode}
% \end{environment}
%
% \begin{environment}{nlex}
%    For the moment, we do disregard the most of the keys
%    \begin{macrocode}
%<*package>
\def\nlex#1{\green{\sl{#1}}}
\def\nlcex#1{*\green{\sl{#1}}}
%</package>
%<*ltxml.sty>
DefConstructor('\nlex{}',"<omdoc:phrase type='nlex'>#1</omdoc:phrase>");
DefConstructor('\nlcex{}',"<omdoc:phrase type='nlcex'>#1</omdoc:phrase>");
%</ltxml.sty>
%    \end{macrocode}
% \end{environment}
%
% \begin{environment}{inlinequote}
%  \ednote{describe above}
%    \begin{macrocode}
%<package>\def\inlinequote#1{``{\sl{#1}}''}
%<ltxml.sty>DefConstructor('\inlinequote{}',"<omdoc:phrase type='inlinequote'>#1</omdoc:phrase>");
%    \end{macrocode}
% \end{environment}
%
% \subsection{Colors}
% 
% \begin{environment}{blue, red, green, magenta}
%    We will use the following abbreviations for colors from |color.sty|
%    \begin{macrocode}
%<*package>
\def\blue#1{\textcolor{blue}{#1}}
\def\red#1{\textcolor{red}{#1}}
\def\green#1{\textcolor{green}{#1}}
\def\cyan#1{\textcolor{cyan}{#1}}
\def\magenta#1{\textcolor{magenta}{#1}}
\def\brown#1{\textcolor{brown}{#1}}
\def\yellow#1{\textcolor{yellow}{#1}}
%</package>
%    \end{macrocode}
% For the {\latexml} bindings, we go a generic route, we replace |\blue{#1}| by 
% |{\@omdoc@color{blue}\@omdoc@color@content{#1}}|. 
%    \begin{macrocode}
%<*ltxml.sty>
sub omdocColorMacro {
  my ($color, @args) = @_;
  my $tok_color = TokenizeInternal($color);
  (T_BEGIN, T_CS('\@omdoc@color'), T_BEGIN, $tok_color->unlist,
   T_END, T_CS('\@omdoc@color@content'), T_OTHER('['), $tok_color->unlist, T_OTHER(']'),
   T_BEGIN, $args[1]->unlist, T_END, T_END); }
DefMacro('\@omdoc@color{}', sub { MergeFont(color=>$_[1]->toString); return; });
%</ltxml.sty>
%    \end{macrocode}
% Ideally, here we will remove the optional argument and have a conversion module
% add the attribute at the end (or maybe add it just for math?)
% or, we can take the attributes for style from the current font ?
%    \begin{macrocode}
%<*ltxml.sty>
DefConstructor('\@omdoc@color@content[]{}',
	       "?#isMath(#2)(<omdoc:phrase ?#1(style='color:#1')()>#2</omdoc:phrase>)");
foreach my $color(qw(blue red green magenta cyan brown yellow)) {
  DefMacro("\\".$color.'{}', sub { omdocColorMacro($color, @_); }); }
%</ltxml.sty>
%    \end{macrocode}
% \end{environment}
%
%
% \subsection{{\LaTeX} Commands we interpret differently}
%
% The first think we have to take care of are the paragraphs, we want to generate {\omdoc}
% that uses the |p| element for paragraphs inside |CMP|s. For that we have modified the
% DTD only to allowed |p| elements in |CMP| (in particular no text). Then we instruct the
% |\par| macro to close a |p| element if possible. The next |p| element is then opened
% automatically, since we make |p| autoclose. 
%    \begin{macrocode}
%<*ltxml.sty>
DefConstructor('\par',sub { $_[0]->maybeCloseElement('omdoc:p'); },alias=>"\\par\n");
Tag('omdoc:p', autoClose=>1, autoOpen=>1);
%</ltxml.sty>
%    \end{macrocode}
% the rest of the reinterpretations is quite simple, we either disregard presentational
% markup or we re-interpret it in terms of {\omdoc}.
%    \begin{macrocode}
%<package>\def\omspace#1{\hspace*{#1}}
%<*ltxml.sty>
DefConstructor('\omspace{}','');
DefConstructor('\emph{}',"<omdoc:phrase class='emphasis'>#1</omdoc:phrase>");
DefConstructor('\em',"<omdoc:phrase class='emphasis'>");
Tag('omdoc:phrase', autoClose=>1);
DefEnvironment('{center}','#body');
DefEnvironment('{minipage}{}','#body');
DefEnvironment('{quote}',"<omdoc:phrase type='quote' style='display:block'>#body</omdoc:phrase>");
DefEnvironment('{quotation}',"<omdoc:phrase type='quote' style='display:block'>#body</omdoc:phrase>");
DefEnvironment('{small}','#body');
DefEnvironment('{footnotesize}','#body');
DefEnvironment('{tiny}','#body');
DefEnvironment('{scriptsize}','#body');
DefConstructor('\LARGE','');
DefConstructor('\Large','');
DefConstructor('\large','');
DefConstructor('\small','');

DefConstructor('\fbox{}','#1');

DefConstructor('\footnote[]{}',
       "<omdoc:note class='foot' ?#1(mark='#1')>#2</omdoc:note>");
DefConstructor('\footnotemark[]',"");
DefConstructor('\footnotetext[]{}',
	       "<omdoc:note class='foot' ?#1(mark='#1')>#2</omdoc:note>");

DefConstructor('\sf', '');
DefConstructor('\sc', '');
%</ltxml.sty>
%    \end{macrocode}
%
% \subsection{Providing IDs for {\omdoc} Elements}\label{sec:impl:ids}
%
% To provide default identifiers (see section~\ref{sec:user:ids}), we tag all {\omdoc}
% elements that allow |xml:id| attributes by excuting the |numberIt| procedure below.
% 
%    \begin{macrocode}
%<*ltxml.sty>
Tag('omdoc:p',afterOpen=>\&numberIt);
Tag('omdoc:omtext',afterOpen=>\&numberIt);
Tag('omdoc:omgroup',afterOpen=>\&numberIt);
Tag('omdoc:tgroup',afterOpen=>\&numberIt);
Tag('omdoc:CMP',afterOpen=>\&numberIt);
%</ltxml.sty>
%    \end{macrocode}
% The |numberIt| procedure gets the prefix from first parent with an |xml:id| attribute and then
% extends it with a label that reflects the number of preceding siblings, provided that
% there is not already an identifier. 
%    \begin{macrocode}
%<*ltxml.sty>
sub numberIt {
  my($document,$node,$whatsit)=@_;
  my(@parents)=$document->findnodes('ancestor::*[@xml:id]',$node); # find 1st id'd parent.
  my $prefix= (@parents ? $parents[$#parents]->getAttribute('xml:id')."." : '');
  my(@siblings)=$document->findnodes('preceding-sibling::*[@xml:id]',$node);
  my $n = scalar(@siblings)+1;
  my $id = ($node -> getAttribute('xml:id'));
  $node->setAttribute('xml:id'=>$prefix."p$n") unless $id; }
%</ltxml.sty>
%    \end{macrocode}
%
% \subsection{Leftovers}
%
%    \begin{macrocode}
%<*ltxml.sty>
DefConstructor('\url Semiverbatim',"<omdoc:link href='#1'>#1</omdoc:link>");
%</ltxml.sty>
%    \end{macrocode}
% \ednote{this should be handled differently, omdoc.sty should include url and give a new
% macro for it, which we then use in omdoc}
% and finally, we need to terminate the file with a success mark for perl.
%    \begin{macrocode}
%<ltxml.sty|ltxml.cls>1;
%    \end{macrocode}
% \Finale
\endinput

% \iffalse
% LocalWords:  GPL structuresharing STR omdoc dtx stex CPERL LoadClass url dc
%%% Local Variables: 
%%% mode: doctex
%%% TeX-master: t
%%% End: 
% \fi
% LocalWords:  RequirePackage RegisterNamespace namespace xsl DocType ltxml dtd
% LocalWords:  ltx DefEnvironment beforeDigest AssignValue inPreamble getGullet
% LocalWords:  afterDigest keyval omgroup DefKeyVal Semiverbatim KeyVal tgroup
% LocalWords:  OptionalKeyVals DefParameterType IfBeginFollows skipSpaces CMP
% LocalWords:  ifNext DefMacro needwrapper unlist DefConstructor omtext bgroup
% LocalWords:  useCMPItemizations RefStepItemCounter egroup beginItemize li di
% LocalWords:  beforeDigestEnd useTheoryItemizations dt autoclose ul ol dl env
% LocalWords:  afterOpen LastSeenCMP autoClose DefCMPEnvironment proto ToString
% LocalWords:  addAttribute nlex nlcex omdocColorMacro args tok MergeFont qw
% LocalWords:  TokenizeInternal toString isMath foreach maybeCloseElement id'd
% LocalWords:  autoOpen minipage footnotesize scriptsize numberIt whatsit href
% LocalWords:  getAttribute setAttribute
