%D \module
%D   [       file=latexmp.mp,
%D         system={latexMP},
%D        version=1.2.1,
%D          title=latexMP,
%D       subtitle=LaTeX typesetting in \METAPOST, 
%D         author=Jens-Uwe Morawski,
%D           date={2005/04/06},
%D      copyright={none; this module is Public Domain}]
%D
%C - all variables start with prefix "latexmp_"
%C - all internal macros have suffix "_latexmp"
%C - macros without "_latexmp" suffix are:
%C    textext, setupLaTeXMP

%D \section{Initialisation}
if known latexmp_module: message(" not loaded again"); endinput ; fi ;
boolean latexmp_module ; latexmp_module := true ;

%D set the name of the temporary file
string latexmp_lmpfile ; latexmp_lmpfile := "ltx-" & jobname & ".tmp" ;

%D save some original \METAPOST\ definitions
inner end ; inner bye ;
let origEnd_latexmp=end ;
let origBye_latexmp=bye ;
let origShipit_latexmp=shipit ;
string latexmp_extrabeginfig, latexmp_extraendfig ;
extra_endfig := extra_endfig & "; resetattachstrings_latexmp ;" ;
latexmp_extrabeginfig := extra_beginfig ;
latexmp_extraendfig := extra_endfig ;
color latexmp_background ;
latexmp_background := background ;

%D The runtime control of latexMP states:
%D (1) is this the second run in \type{rerun} mode ; (2) has the temporary
%D mp file already been read; (3) is the LaTeX preamble already
%D been written to the temporary file
boolean latexmp_secondrun, latexmp_lmploaded, latexmp_texinit ;
latexmp_secondrun := false ;
latexmp_lmploaded := false ;
latexmp_texinit := false ;

%D The current number of \type{textext()} in the input file. The counter
%D is incremented at every \type{textext} call. It is used to assign the
%D pictures from the temporary file.
numeric latexmp_counter ; latexmp_counter := 0 ;

%D \section{Setup}
%D LaTeX preamble variables
string latexmp_docclass, latexmp_classoptions,
latexmp_inputenc, latexmp_fontenc, latexmp_babellang,
latexmp_packages, latexmp_preamble, latexmp_lmpprefix,
latexmp_preamblefile ;

latexmp_docclass := "article" ;
latexmp_classoptions := "" ;
latexmp_inputenc := "" ;
latexmp_fontenc := "" ;
latexmp_babellang := "" ;
latexmp_packages := "" ;
latexmp_preamble := "" ;
latexmp_preamblefile := "" ;

%D The setup variables that control activation of the specials:
numeric latexmp_mode ;       latexmp_mode := 1 ;
boolean latexmp_subsinfont ; latexmp_subsinfont := false ;
boolean latexmp_multicolor ; latexmp_multicolor := false ;
boolean latexmp_debug ;      latexmp_debug := false ;

%D The setup command:
def setupLaTeXMP(text kvps) =
  if not latexmp_secondrun:
    if latexmp_texinit:
      message("LaTeXMP: setupLaTeXMP cannot be used if textext" &
	"has already been used; set-up ignored.");
    else:
    begingroup;
%D declaration of key-value parameters for LaTeX preamble
    save class, options, inputencoding, fontencoding, language,
    packages, preamble, preamblefile ;
    string class, options, inputencoding, fontencoding, language,
    packages, preamble, preamblefile;
%D declaration of key and synonyms for \type{mode}
    save mode, normal, rerun ;
    numeric mode, normal, rerun ;
    normal:=1 ; rerun := 2 ;
%D declaration of keys and synonyms for the specials
    save textextlabel, multicolor, debug, enable, disable ;
    boolean textextlabel, multicolor, debug, enable, disable ;
    enable:=true ; disable := false ;
    
    processKeyvals_latexmp(kvps) ;

    if known class:
      if (length class) >0: latexmp_docclass:=class ;
      else: latex_docclass:="article";
      fi;
    fi;
    if known options: latexmp_classoptions:=options ; fi;
    if known inputencoding: latexmp_inputenc:=inputencoding ; fi;
    if known fontencoding: latexmp_fontenc:=fontencoding ; fi;
    if known language: latexmp_babellang:=language ; fi;
    if known preamble:latexmp_preamble:=preamble ; fi;
    if known preamblefile: latexmp_preamblefile:=preamblefile ; fi;
    if known packages: latexmp_packages:=packages ; fi;
    if known mode:
      if (mode=normal) or (mode=rerun): latexmp_mode:=mode ;
      else:
	errmessage("latexMP error: set mode either to 'normal' or 'rerun'.") ;
	latexmp_mode := 1 ;
      fi;
    fi;
    if known textextlabel: latexmp_subsinfont:=textextlabel ; fi;
    if known multicolor: latexmp_multicolor:=multicolor ; fi;
    if known debug: latexmp_debug:=debug ; fi;
  endgroup;
  
%D overwrite the default definition of \type{thelabel} if user has specified
%D \type{textextlabel=enable}:
  if latexmp_subsinfont:
    vardef thelabel@#(expr s,z) =
      save p; picture p;
      if picture s: p=s
      else: p = textext(s)
      fi;
      p shifted (z + labeloffset*laboff@# -
	(labxf@#*lrcorner p + labyf@#*ulcorner p
	  + (1-labxf@#-labyf@#)*llcorner p ))
    enddef;
  fi;

%D In \type{rerun} mode for the first run own definitions for \type{end}
%D and \type{bye} are used; output is disabled for first run.
  if latexmp_mode=2:
    let end=end_latexmp ;
    let bye=end_latexmp ;
    let shipit=relax ;
%D Since in the first run the temporary file will not contain
%D correct definitions automatic loading of that file by \type{textext}
%D is disabled (we fake here that it is already loaded). Loading of the
%D temporary file in \type{end_latexmp}.
    latexmp_lmploaded := true ;
  fi;
  fi;fi;
enddef;

%D used in \type{writeLaTeXpreamble_latexmp}
%D to generate \type{\usepackage} statements
def writepackages_latexmp=
  begingroup;
    save inoptions, currentpackage, currentoptions, s ;
    boolean inoptions ; inoptions:=false;
    string currentpackage, currentoptions, s ;
    currentpackage:=""; currentoptions:="" ;

    for c=0 upto ((length latexmp_packages)-1):
      s := substring (c,c+1) of latexmp_packages ;
      if s="[":	    inoptions := true ;
      elseif s="]": inoptions := false;
      elseif s=",":
	if inoptions: currentoptions:= currentoptions & s ;
	else:
	  if (length currentpackage)>0:
	    s:="{" & currentpackage & "}" ;
	    if (length currentoptions)>0:
	      s:="[" & currentoptions & "]" & s ;
	    fi;
	    write ("\usepackage" & s) to latexmp_lmpfile ;
	    currentpackage:=""; currentoptions:="" ;
	  fi;
	fi;
      else:
	if inoptions: currentoptions:= currentoptions & s ;
	else: currentpackage:= currentpackage & s ;
	fi;
      fi;
    endfor;
    if (length currentpackage)>0: s:="{" & currentpackage & "}" ;
      if (length currentoptions)>0: s:="[" & currentoptions & "]" & s ; fi;
      write ("\usepackage" & s) to latexmp_lmpfile ;
    fi;
  endgroup;
enddef;

%D \section{LaTeX preamble}

def writeLaTeXpreamble_latexmp =
  write "verbatimtex" to latexmp_lmpfile ;
  write "%&latex" to latexmp_lmpfile ;
%D If preamble file has been specified in the setup only a
%D \type{\input} for this file will be used in the LaTeX preamble:
  if (length latexmp_preamblefile)>0:
    write ("\input{" & latexmp_preamblefile & "}") to latexmp_lmpfile ;
  else:
%D Specific definitions from the setup parameters:
    write ("\documentclass"
      if (length latexmp_classoptions)>0:
	& "[" & latexmp_classoptions & "]"
      fi & "{" & latexmp_docclass & "}") to latexmp_lmpfile ;
    if (length latexmp_fontenc)>0:
      write ("\usepackage[" & latexmp_fontenc & "]{fontenc}")
      to latexmp_lmpfile ;
    fi
    if (length latexmp_inputenc)>0:
      write ("\usepackage[" & latexmp_inputenc & "]{inputenc}")
      to latexmp_lmpfile ;
    fi
    if (length latexmp_babellang)>0:
      write ("\usepackage[" & latexmp_babellang & "]{babel}")
      to latexmp_lmpfile ;
    fi
    if (length latexmp_packages)>0: writepackages_latexmp ; fi;
    if (length latexmp_preamble)>0:
      write latexmp_preamble to latexmp_lmpfile ;
    fi
  fi;
  if latexmp_multicolor:
    write ("\makeatletter") to latexmp_lmpfile ;
    write ("\font\latexmp@special=cmtt8 scaled 250") to latexmp_lmpfile ;
    write ("\def\reset@color{" &
      "\parbox[t][0pt][t]{0pt}{\makebox[0pt][l]{\latexmp@special ecolorxxx}}}")
      to latexmp_lmpfile ;
    write ("\newcommand*{\color}[2][named]{\parbox[t][0pt][t]{0pt}{" &
      "\makebox[0pt][l]{\latexmp@special bcolorxxx:#1:#2}}" &
      "\aftergroup\reset@color\ignorespaces}") to latexmp_lmpfile ;
    write ("\def\textcolor#1#{\@textcolor{#1}}") to latexmp_lmpfile ;
    write ("\def\@textcolor#1#2#3{\protect\leavevmode{\color#1{#2}#3}}")
      to latexmp_lmpfile ;
    write ("\newcommand*{\transparent}[3][1]{\parbox[t][0pt][t]{0pt}{"&
     "\makebox[0pt][l]{\latexmp@special btransxxx:#1,#2}}"&
     "#3\parbox[t][0pt][t]{0pt}{" &
     "\makebox[0pt][l]{\latexmp@special etransxxx}}}") to latexmp_lmpfile ;
    write "\makeatother" to latexmp_lmpfile ;
  fi;
  write "\begin{document}" to latexmp_lmpfile ;
  write "etex" to latexmp_lmpfile ;
  write "picture latexmp_picture[];" to latexmp_lmpfile ;
enddef;

%D \section{Main Macros}

%D The macro that does the job:
vardef textext@#(expr s)=
  save pic ;  picture pic ;
  latexmp_counter:= latexmp_counter+1 ;
  getpicture_latexmp ;
  addstring_latexmp(s) ;
  if (length (str @#))>0 :
	% V. 1.1 compatible with MetaFun
	thelabel@#(pic,origin)
  else:
	% V. 1.2 better compatibility with btex..etex
	pic
  fi
enddef;

%D strings \type{latexmp_prepend} and \type{latexmp_append} are attached
%D to the string passed to \type{textext}. This may be useful for package
%D authors to implement styling interfaces.
string latexmp_prepend, latexmp_append ;
latexmp_prepend:= "" ; latexmp_append := "" ;

%D is called at each endfig via extra_endfig
def resetattachstrings_latexmp =
	latexmp_prepend:= "" ; latexmp_append := "" ;
enddef;

def addstring_latexmp(expr s)=
  if not latexmp_texinit:
    write EOF to latexmp_lmpfile ;
    writeLaTeXpreamble_latexmp ;
    latexmp_texinit := true ;
  fi;
  write "latexmp_picture[" & (decimal latexmp_counter) & "]:= btex " &
	latexmp_prepend & s & latexmp_append & " etex ;" to latexmp_lmpfile ;
enddef;

def getpicture_latexmp =
  if not latexmp_lmploaded:
    if not (readfrom latexmp_lmpfile=EOF):
      scantokens ("input " & latexmp_lmpfile) ;
    fi;
    latexmp_lmploaded := true ;
  fi;
  if known latexmp_picture[latexmp_counter]:
    if latexmp_multicolor and not latexmp_debug:
      pic := colorspecials_latexmp(latexmp_picture[latexmp_counter]) ;
    else:
      pic := latexmp_picture[latexmp_counter] ;
    fi;
  else:
    pic := ("LaTeXMP " & (decimal latexmp_counter))
       infont defaultfont ;
  fi;
enddef;

%D The following is only used if option \type{multicolor} is set in
%D \type{setupLaTeXMP}. It is employed in \type{getpicture_latexmp}
%D in order to strip specials from the LaTeX picture and change
%D the colors of text elements accordigly.
vardef colorspecials_latexmp(expr p) =
  save _P, _bb, _tp, _fp, _t, _addto_P ;
  save _withcolor, _colorpointer, _transparent, _transpointer;
  picture _P ; path _bb ;
  string _withcolor[], _transparent[], _tp, _fp, _addto_P ;
  numeric _colorpointer, _transpointer ;
  _P := nullpicture ;  _bb := pathpart p ;
  _withcolor[0]:= "" ; _colorpointer := 0 ; _transparent[0]:="" ;
  _transpointer:=0 ;
  _addto_P := "addto _P also _tp infont _fp transformed _t " ;
  for c within p:
    if textual c:
      _tp:= textpart c ;
      _fp:= fontpart c ;
      transform _t ;
      (xpart _t,xxpart _t,xypart _t)=(xpart c,xxpart c,xypart c) ; 
      (ypart _t,yypart _t,yxpart _t)=(ypart c,yypart c,yxpart c) ;
      if (_fp="cmtt8") and ((substring (1,9) of _tp)="colorxxx"):
      % color special found
	if (substring (0,1) of _tp)="b":
	% begin color special
	  _colorpointer := _colorpointer+1;
	  _withcolor[_colorpointer]:= colormacro_latexmp(substring (10,(length _tp)) of _tp) ;
	elseif (substring (0,1) of _tp)="e":
	% end color special
	  if not (_colorpointer=0):
%C if \type{\color} is used ungrouped in a parbox the \type{ecolorxxx}
%C appears prior \type{bcolorxxx}. multiple instances of \type{ecolorxxx}
%C would result in counting \type{_colorpointer<0}. thus checking
%C for \type{_colorpointer=0} is a ugly hack for this problem.
	    _colorpointer := _colorpointer-1;
	  fi;
%C else:?? ooops; should not happen 
	fi;
      elseif (_fp="cmtt8") and ((substring (1,9) of _tp)="transxxx"):
      % transparency special found
	if (substring (0,1) of _tp)="b":
	% begin trans special
	  _transpointer := _transpointer+1;
	  _transparent[_transpointer]:= substring (10,(length _tp)) of _tp ;
	elseif (substring (0,1) of _tp)="e":
	% end trans special
	  _transpointer := _transpointer-1;
	fi;
      else:
	scantokens (_addto_P & withcurrentcolor_latexmp ) ;
      fi;
    fi;
  endfor;
  setbounds _P to _bb ;
  _P
enddef;

vardef colormacro_latexmp(expr colspec)=
  save _cmd, _pos, _m, _c ; string _cmd, _m, _c ;
  _pos := 0 ; _cmd:="" ;
  for i=1 upto (length colspec):
    if (substring (i-1,i) of colspec)=":":
      _pos := i ;
    fi;
  endfor;
  if _pos<2: % "x:..." --> no color model found
    errmessage("LaTeXMP: no color model found in: " & colspec) ;
  else:
    _m := substring (0,(_pos-1)) of colspec ;
    _c := substring (_pos,(length colspec)) of colspec ;
    if expandafter known (scantokens ("latexmp_color_" & _m)):
      _cmd := (scantokens ("latexmp_color_" & _m)) & "(" & _c & ")" ;
    else:
      errmessage("LaTeXMP: color model '" & _m & "' not supported)") ;
    fi;
  fi;
  _cmd
enddef;

vardef withcurrentcolor_latexmp=
  if (length _withcolor[_colorpointer])>0:
    if (length _transparent[_transpointer])>0:
      " withcolor transparent(" & _transparent[_transpointer] & "," &
	_withcolor[_colorpointer] &")"
    else:  " withcolor " & _withcolor[_colorpointer] fi
  else:
    if (length _transparent[_transpointer])>0:
      " withcolor transparent(" & _transparent[_transpointer] & ",black)"
    else: "" fi
  fi
enddef;

%D \section{The end macro for rerun mode}
string latexmp_beforererun ; latexmp_beforererun := "" ;

def end_latexmp =
%D read temporary file if strings have been written there
  if latexmp_counter>0:
    write EOF to latexmp_lmpfile;
    scantokens ("input " & latexmp_lmpfile) ;
  fi;
%D re-init
  latexmp_counter := 0 ; latexmp_secondrun := true ; latexmp_texinit := false ;
%D restore defaults
  extra_beginfig := latexmp_extrabeginfig ;
  extra_endfig := latexmp_extraendfig ;
  background := latexmp_background ;
  let end=origEnd_latexmp ; let bye=origBye_latexmp ;
  let shipit=origShipit_latexmp ;
  clear_pen_memory; clearit;
  pickup pencircle scaled .5bp; defaultpen := savepen;
%D run pre-rerun hooks
  scantokens latexmp_beforererun ;
%D input current job again
  scantokens ("input " & jobname) ;
enddef;

%D \section{color support}
vardef Hsvcolor_latexmp(expr H,s,v) =
  save h, o, b, d, pc, sc; numeric h, o, b, d, pc, sc ;
  h := H/60 ;  pc := floor h ;  sc := h - pc ;
  o := (1-s)*v ;  b := (1-(sc*s))*v ;  d := (1-((1-sc)*s))*v ;
  if (pc = 0) or (pc = 6): (v,d,o)
  elseif pc = 1: (b,v,o)	
  elseif pc = 2: (o,v,d)	
  elseif pc = 3: (o,b,v)	
  elseif pc = 4: (d,o,v)	
  else:(v,o,b)
  fi
enddef;
vardef cmykcolor_latexmp(expr c,m,y,k) =
%D use MetaFun cmyk-specials if available; macro \type{cmyk()}
%D checks if \type{cmykcolors=true}
  if known context_spec: cmyk(c,m,y,k) else: (1-c-k,1-m-k,1-y-k) fi
enddef;
vardef graycolor_latexmp(expr g) = (g,g,g) enddef ;

%D which macro should be used for a given color model in multicolor mode.
string latexmp_color_Hsv, latexmp_color_rgb,
latexmp_color_gray, latexmp_color_cmyk, latexmp_color_named ;

latexmp_color_Hsv := "Hsvcolor_latexmp" ;
latexmp_color_gray := "graycolor_latexmp" ;
latexmp_color_rgb := "" ;
latexmp_color_cmyk := "cmykcolor_latexmp" ;
latexmp_color_named := "" ;

%D \section{Key-Value Support Macros}
def processKeyvals_latexmp (text _kvps_)=
  begingroup;
    save _equals, _assign ;
    let _equals= = ;
    
    primarydef _ll_ _assign _rr_ =
      hide(_ll_ _equals _rr_ ) 1
    enddef;

    save = ;
    let = _equals _assign ;
    for _xx_ _equals _kvps_ : endfor ;% NOP
  endgroup;
enddef;
